Skip to content

Instantly share code, notes, and snippets.

@jamietre
Created April 29, 2016 18:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamietre/c0face4a1e351694977e0791c70f0d28 to your computer and use it in GitHub Desktop.
Save jamietre/c0face4a1e351694977e0791c70f0d28 to your computer and use it in GitHub Desktop.
Better msbuild config for Typescript projects in Visual Studio that tries to use npm modules first
<?xml version="1.0" encoding="utf-8"?>
<!--
***********************************************************************************************
Microsoft.TypeScript.targets
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
created a backup copy. Incorrect changes to this file will make it
impossible to load or build your web deploy projects from the command-line or the IDE.
This file defines the steps in the standard build process for TypeScript files.
Copyright (C) Microsoft Corporation. All rights reserved.
***********************************************************************************************
-->
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VsToolsPath Condition="'$(VsToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VsToolsPath>
</PropertyGroup>
<UsingTask TaskName="TypeScript.Tasks.VsTsc" AssemblyFile="TypeScript.tasks.dll" />
<UsingTask TaskName="TypeScript.Tasks.FindConfigFiles" AssemblyFile="TypeScript.tasks.dll" />
<PropertyGroup>
<CompileTypeScriptDependsOn>
$(CompileTypeScriptDependsOn);
ValidateConfig;
PreComputeCompileTypeScript;
PreComputeCompileTypeScriptWithTSConfig;
</CompileTypeScriptDependsOn>
<CompileDependsOn>
ValidateConfig;
FindConfigFiles;
CompileTypeScript;
CompileTypeScriptWithTSConfig;
$(CompileDependsOn);
</CompileDependsOn>
<PublishPipelineCollectFilesCore>
$(PublishPipelineCollectFilesCore);
ValidateConfig;
FindConfigFiles;
CompileTypeScript;
CompileTypeScriptWithTSConfig;
</PublishPipelineCollectFilesCore>
<CleanDependsOn>
$(CleanDependsOn);
ValidateConfig;
FindConfigFiles;
TypeScriptClean;
TypeScriptCleanWithTSConfig;
</CleanDependsOn>
<BuiltProjectOutputGroupDependsOn>
ValidateConfig;
FindConfigFiles;
CompileTypeScript;
CompileTypeScriptWithTSConfig;
$(BuiltProjectOutputGroupDependsOn);
</BuiltProjectOutputGroupDependsOn>
</PropertyGroup>
<PropertyGroup>
<GetCopyToOutputDirectoryItemsDependsOn>
$(GetCopyToOutputDirectoryItemsDependsOn);
GetTypeScriptCopyToOutputDirectoryItems;
</GetCopyToOutputDirectoryItemsDependsOn>
</PropertyGroup>
<PropertyGroup>
<CfgPropertyPagesGuidsAddCSharp>{d4683cae-88c4-4b85-863d-ac8014f3ba36}</CfgPropertyPagesGuidsAddCSharp>
<CfgPropertyPagesGuidsAddVB>{d4683cae-88c4-4b85-863d-ac8014f3ba36}</CfgPropertyPagesGuidsAddVB>
<CfgPropertyPagesGuidsAddTypeScript>{d4683cae-88c4-4b85-863d-ac8014f3ba36}</CfgPropertyPagesGuidsAddTypeScript>
</PropertyGroup>
<PropertyGroup>
<!-- Indicates to the language service that this project supports TypeScript -->
<TypeScriptEnabled>true</TypeScriptEnabled>
<!-- Controls Compile-on-Save in the IDE -->
<TypeScriptCompileOnSaveEnabled Condition="'$(TypeScriptCompileOnSaveEnabled)' == ''">true</TypeScriptCompileOnSaveEnabled>
<!-- Makes the TypeScript compilation task a no-op -->
<TypeScriptCompileBlocked Condition="'$(TypeScriptCompileBlocked)' == ''">false</TypeScriptCompileBlocked>
<!-- Flag to indicate if we need to preserve Jsx constructs, this affects the extension of the output files -->
<JsxPreserve>false</JsxPreserve>
<JsxPreserve Condition=" '$(TypeScriptJSXEmit)' == 'Preserve' ">true</JsxPreserve>
<GenerateDeclarationFiles>false</GenerateDeclarationFiles>
<GenerateDeclarationFiles Condition="'$(TypeScriptGeneratesDeclarations)' == 'true'">true</GenerateDeclarationFiles>
<GenerateSourceMaps>false</GenerateSourceMaps>
<GenerateSourceMaps Condition="'$(TypeScriptSourceMap)' == 'true'">true</GenerateSourceMaps>
</PropertyGroup>
<PropertyGroup Condition="'$(TypeScriptBuildConfigurations)' == ''">
<PreferredUILang Condition="'$(BuildingInsideVisualStudio)' == 'true' and '$(PreferredUILang)' == ''">$([System.Globalization.CultureInfo]::CurrentUICulture.Name)</PreferredUILang>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptRemoveComments)' == 'true'">$(TypeScriptBuildConfigurations) --removeComments</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptNoImplicitAny)' == 'true'">$(TypeScriptBuildConfigurations) --noImplicitAny</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptGeneratesDeclarations)' == 'true'">$(TypeScriptBuildConfigurations) --declaration</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptModuleKind)' != '' and '$(TypeScriptModuleKind)' != 'none'">$(TypeScriptBuildConfigurations) --module $(TypeScriptModuleKind)</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptJSXEmit)' != '' and '$(TypeScriptJSXEmit)' != 'none'">$(TypeScriptBuildConfigurations) --jsx $(TypeScriptJSXEmit)</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptOutFile)' != ''">$(TypeScriptBuildConfigurations) --out &quot;$(TypeScriptOutFile)&quot;</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptOutDir)' != ''">$(TypeScriptBuildConfigurations) --outDir &quot;$(TypeScriptOutDir)&quot;</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptSourceMap)' == 'true'">$(TypeScriptBuildConfigurations) --sourcemap</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptTarget)' != ''">$(TypeScriptBuildConfigurations) --target $(TypeScriptTarget)</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptNoResolve)' == 'true'">$(TypeScriptBuildConfigurations) --noResolve</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptAdditionalFlags)' != ''">$(TypeScriptBuildConfigurations) $(TypeScriptAdditionalFlags)</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptMapRoot)' != ''">$(TypeScriptBuildConfigurations) --mapRoot &quot;$(TypeScriptMapRoot)&quot;</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptSourceRoot)' != ''">$(TypeScriptBuildConfigurations) --sourceRoot &quot;$(TypeScriptSourceRoot)&quot;</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptCodePage)' != ''">$(TypeScriptBuildConfigurations) --codepage $(TypeScriptCodePage)</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptCharset)' != ''">$(TypeScriptBuildConfigurations) --charset $(TypeScriptCharset)</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptEmitBOM)' == 'true'">$(TypeScriptBuildConfigurations) --emitBOM</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptNoLib)' == 'true'">$(TypeScriptBuildConfigurations) --noLib</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptPreserveConstEnums)' == 'true'">$(TypeScriptBuildConfigurations) --preserveConstEnums</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptSuppressImplicitAnyIndexErrors)' == 'true'">$(TypeScriptBuildConfigurations) --suppressImplicitAnyIndexErrors</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptNoEmitHelpers)' == 'true'">$(TypeScriptBuildConfigurations) --noEmitHelpers</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptInlineSourceMap)' == 'true'">$(TypeScriptBuildConfigurations) --inlineSourceMap</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptInlineSources)' == 'true'">$(TypeScriptBuildConfigurations) --inlineSources</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptNewLine)' != ''">$(TypeScriptBuildConfigurations) --newLine $(TypeScriptNewLine)</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptIsolatedModules)' == 'true'">$(TypeScriptBuildConfigurations) --isolatedModules</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptEmitDecoratorMetadata)' == 'true'">$(TypeScriptBuildConfigurations) --emitDecoratorMetadata</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptRootDir)' != ''">$(TypeScriptBuildConfigurations) --rootDir &quot;$(TypeScriptRootDir)&quot;</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptExperimentalDecorators)' == 'true'">$(TypeScriptBuildConfigurations) --experimentalDecorators</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptModuleResolution)' != ''">$(TypeScriptBuildConfigurations) --moduleResolution $(TypeScriptModuleResolution)</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptExperimentalAsyncFunctions)' == 'true'">$(TypeScriptBuildConfigurations) --experimentalAsyncFunctions</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptSuppressExcessPropertyErrors)' == 'true'">$(TypeScriptBuildConfigurations) --suppressExcessPropertyErrors</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptReactNamespace)' != ''">$(TypeScriptBuildConfigurations) --reactNamespace $(TypeScriptReactNamespace)</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptSkipDefaultLibCheck)' == 'true'">$(TypeScriptBuildConfigurations) --skipDefaultLibCheck</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptAllowUnusedLabels)' == 'true'">$(TypeScriptBuildConfigurations) --allowUnusedLabels</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptNoImplicitReturns)' == 'true'">$(TypeScriptBuildConfigurations) --noImplicitReturns</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptNoFallthroughCasesInSwitch)' == 'true'">$(TypeScriptBuildConfigurations) --noFallthroughCasesInSwitch</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptAllowUnreachableCode)' == 'true'">$(TypeScriptBuildConfigurations) --allowUnreachableCode</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptForceConsistentCasingInFileNames)' == 'true'">$(TypeScriptBuildConfigurations) --forceConsistentCasingInFileNames</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptAllowSyntheticDefaultImports)' == 'true'">$(TypeScriptBuildConfigurations) --allowSyntheticDefaultImports</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptAllowJS)' == 'true'">$(TypeScriptBuildConfigurations) --allowJs</TypeScriptBuildConfigurations>
<TypeScriptBuildConfigurations Condition="'$(TypeScriptNoImplicitUseStrict)' == 'true'">$(TypeScriptBuildConfigurations) --noImplicitUseStrict</TypeScriptBuildConfigurations>
<!-- noEmitOnError default is 'true', this ensures a proper incremental build behavior, where outputs are not generated in the presence of an error. -->
<TypeScriptBuildConfigurations Condition="'$(TypeScriptNoEmitOnError)' != 'false'">$(TypeScriptBuildConfigurations) --noEmitOnError</TypeScriptBuildConfigurations>
<!-- <TypeScriptBuildConfigurations Condition="'$(PreferredUILang)' != ''">$(TypeScriptBuildConfigurations) -locale $(PreferredUILang)</TypeScriptBuildConfigurations>-->
<TypeScriptBuildConfigurations Condition="'$(PreferredUILang)' != ''">$(TypeScriptBuildConfigurations)</TypeScriptBuildConfigurations>
</PropertyGroup>
<PropertyGroup>
<TypeScriptToolsVersion Condition="'$(TypeScriptToolsVersion)'==''">$([System.Environment]::GetEnvironmentVariable('TSVERSION'))</TypeScriptToolsVersion>
<TypeScriptToolsVersion Condition="'$(TypeScriptToolsVersion)'==''">1.8</TypeScriptToolsVersion>
<TscYieldDuringToolExecution Condition="'$(TscYieldDuringToolExecution)' == ''">true</TscYieldDuringToolExecution>
</PropertyGroup>
<ItemGroup>
<ProjectCapability Include="TypeScript" />
</ItemGroup>
<Target Name="ValidateConfig">
<PropertyGroup>
<!-- If there is a locally-installed TSC dependency for an npm module, use it -->
<TscLocalNpm>$(ProjectDir)node_modules\.bin\</TscLocalNpm>
<TscToolPath Condition="'$(TscToolPath)' == '' AND Exists('$(TscLocalNpm)')">$(TscLocalNpm)</TscToolPath>
<!-- Next try to locate global NPM package -->
<TscGlobalNpm>$(AppData)\npm\</TscGlobalNpm>
<TscToolPath Condition="'$(TscToolPath)' == '' AND Exists('$(TscGlobalNpm)')">$(TscGlobalNpm)</TscToolPath>
<!-- Next try to locate the nuget package -->
<TscNuget>$(MSBuildThisFileDirectory)tsc\</TscNuget>
<TscToolPath Condition="'$(TscToolPath)' == '' AND Exists('$(TscNuget)') ">$(TscNuget)</TscToolPath>
<!-- Finally check the global windows installation. -->
<TscVisualStudio>$(MSBuildProgramFiles32)\Microsoft SDKs\TypeScript\</TscVisualStudio>
<TscToolPath Condition="'$(TscToolPath)' == '' AND Exists('$(TscVisualStudio)') ">$(TscVisualStudio)</TscToolPath>
<!-- Now set the EXE correctly -->
<TscToolExe Condition="'$(TscToolExe)' == '' AND Exists('$(TscToolPath)tsc.cmd')">tsc.cmd</TscToolExe>
<TscToolExe Condition="'$(TscToolExe)' == '' AND (Exists('$(TscToolPath)tsc.exe') OR Exists('$(TscToolPath)$(TypeScriptToolsVersion)tsc.exe'))">tsc.exe</TscToolExe>
</PropertyGroup>
<Error Condition="'$(TscToolExe)' == ''"
Text="Could not locate typescript compiler. I looked in these locations:
- local npm%09'$(TscLocalNpm)'
- global npm%09'$(TscGlobalNpm)'
- nuget%09'$(TscNuget)'
- Visual Studio plugin%09'$(TscVisualStudio)$(TypescriptToolsVersion)'
You may want to run 'npm install' for this project, or check that your VS plugin or nuget package dependency is missing." />
</Target>
<Target Name="FindConfigFiles">
<FindConfigFiles
ProjectDir="$(ProjectDir)"
ContentFiles="@(Content)">
<Output TaskParameter="ConfigFiles" ItemName="foundFiles" />
</FindConfigFiles>
<ItemGroup>
<ConfigFiles Include="@(foundFiles)" KeepDuplicates="false" />
</ItemGroup>
</Target>
<Target Name="PreComputeCompileTypeScriptWithTSConfig"
Condition="'@(ConfigFiles)' != ''">
<VsTsc
ToolPath="$(TscToolPath)"
ToolExe="$(TscToolExe)"
TSConfigFile="%(ConfigFiles.Identity)"
YieldDuringToolExecution="$(TscYieldDuringToolExecution)"
ProjectDir="$(ProjectDir)"
ToolsVersion="$(TypeScriptToolsVersion)"
TypeScriptCompileBlocked="$(TypeScriptCompileBlocked)"
ComputeOutputOnly="true">
<Output TaskParameter="GeneratedJavascript" ItemName="emittedFiles" />
</VsTsc>
<ItemGroup>
<GeneratedJavascript Include="@(emittedFiles)" KeepDuplicates="false" />
</ItemGroup>
</Target>
<Target Name="PreComputeCompileTypeScript"
Condition="'@(ConfigFiles)' == ''">
<VsTsc
ToolPath="$(TscToolPath)"
ToolExe="$(TscToolExe)"
Configurations="$(TypeScriptBuildConfigurations)"
FullPathsToFiles="@(TypeScriptCompile)"
YieldDuringToolExecution="$(TscYieldDuringToolExecution)"
OutFile="$(TypeScriptOutFile)"
OutDir="$(TypeScriptOutDir)"
ProjectDir="$(ProjectDir)"
ToolsVersion="$(TypeScriptToolsVersion)"
RootDir="$(TypeScriptRootDir)"
TypeScriptCompileBlocked="$(TypeScriptCompileBlocked)"
JsxPreserve="$(JsxPreserve)"
GenerateDeclarationFiles="$(GenerateDeclarationFiles)"
GenerateSourceMaps="$(GenerateSourceMaps)"
ComputeOutputOnly="true">
<Output TaskParameter="GeneratedJavascript" ItemName="emittedFiles" />
</VsTsc>
<ItemGroup>
<GeneratedJavascript Include="@(emittedFiles)" KeepDuplicates="false" />
</ItemGroup>
</Target>
<Target Name="CompileTypeScriptWithTSConfig"
Condition="'$(BuildingProject)' != 'false' AND '@(ConfigFiles)' != ''"
DependsOnTargets="$(CompileTypeScriptDependsOn)"
Inputs="@(ConfigFiles)"
Outputs="@(GeneratedJavascript)">
<VsTsc
ToolPath="$(TscToolPath)"
ToolExe="$(TscToolExe)"
TSConfigFile="%(ConfigFiles.Identity)"
YieldDuringToolExecution="$(TscYieldDuringToolExecution)"
ProjectDir="$(ProjectDir)"
ToolsVersion="$(TypeScriptToolsVersion)"
TypeScriptCompileBlocked="$(TypeScriptCompileBlocked)"
ComputeOutputOnly="false">
<Output TaskParameter="GeneratedJavascript" ItemName="emittedFiles" />
</VsTsc>
<ItemGroup>
<GeneratedJavascript Include="@(emittedFiles)" KeepDuplicates="false" />
</ItemGroup>
<AssignTargetPath Files="@(GeneratedJavascript)" RootFolder="$(MSBuildProjectDirectory)">
<Output TaskParameter="AssignedFiles" ItemName="GeneratedJavascriptWithTargetPath" />
</AssignTargetPath>
<ItemGroup>
<FilesForPackagingFromProject Include="@(GeneratedJavascriptWithTargetPath->'%(Identity)')"/>
<ContentWithTargetPath Include="@(GeneratedJavascriptWithTargetPath->'%(Identity)')"/>
<Content Include="@(GeneratedJavascript->'%(Identity)')"/>
</ItemGroup>
</Target>
<Target Name="CompileTypeScript"
Condition="'$(BuildingProject)' != 'false' AND '@(ConfigFiles)' == ''"
DependsOnTargets="$(CompileTypeScriptDependsOn)"
Inputs="@(TypeScriptCompile)"
Outputs="@(GeneratedJavascript)">
<VsTsc
ToolPath="$(TscToolPath)"
ToolExe="$(TscToolExe)"
Configurations="$(TypeScriptBuildConfigurations)"
FullPathsToFiles="@(TypeScriptCompile)"
YieldDuringToolExecution="$(TscYieldDuringToolExecution)"
OutFile="$(TypeScriptOutFile)"
OutDir="$(TypeScriptOutDir)"
ProjectDir="$(ProjectDir)"
ToolsVersion="$(TypeScriptToolsVersion)"
RootDir="$(TypeScriptRootDir)"
TypeScriptCompileBlocked="$(TypeScriptCompileBlocked)"
JsxPreserve="$(JsxPreserve)"
ComputeOutputOnly="false">
<Output TaskParameter="GeneratedJavascript" ItemName="emittedFiles" />
</VsTsc>
<ItemGroup>
<GeneratedJavascript Include="@(emittedFiles)" KeepDuplicates="false" />
</ItemGroup>
<AssignTargetPath Files="@(GeneratedJavascript)" RootFolder="$(MSBuildProjectDirectory)">
<Output TaskParameter="AssignedFiles" ItemName="GeneratedJavascriptWithTargetPath" />
</AssignTargetPath>
<ItemGroup>
<FilesForPackagingFromProject Include="@(GeneratedJavascriptWithTargetPath->'%(Identity)')"/>
<ContentWithTargetPath Include="@(GeneratedJavascriptWithTargetPath->'%(Identity)')"/>
<Content Include="@(GeneratedJavascript->'%(Identity)')"/>
</ItemGroup>
</Target>
<Target Name="GetTypeScriptCopyToOutputDirectoryItems">
<AssignTargetPath Files="@(TypeScriptCompile)" RootFolder="$(MSBuildProjectDirectory)">
<Output TaskParameter="AssignedFiles" ItemName="TypeScriptCompileWithTargetPath" />
</AssignTargetPath>
<Message Text="Adding items with BuildAction=TypeScriptCompile to the same collections that will be populated (with items of other BuildActions) by the GetCopyToOutputDirectoryItems target"/>
<ItemGroup>
<AllItemsFullPathWithTargetPath Include="@(TypeScriptCompileWithTargetPath->'%(FullPath)')" Condition="'%(TypeScriptCompileWithTargetPath.CopyToOutputDirectory)'=='Always' OR '%(TypeScriptCompileWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
<_SourceItemsToCopyToOutputDirectoryAlways Include="@(TypeScriptCompileWithTargetPath->'%(FullPath)')" Condition="'%(TypeScriptCompileWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
<_SourceItemsToCopyToOutputDirectory Include="@(TypeScriptCompileWithTargetPath->'%(FullPath)')" Condition="'%(TypeScriptCompileWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
</ItemGroup>
</Target>
<Target Name="TypeScriptClean" DependsOnTargets="PreComputeCompileTypeScript"
Condition=" '@(ConfigFiles)' == '' ">
<Delete Files="@(GeneratedJavascript)" />
</Target>
<Target Name="TypeScriptCleanWithTSConfig" DependsOnTargets="PreComputeCompileTypeScriptWithTSConfig"
Condition=" '@(ConfigFiles)' != '' ">
<Delete Files="@(GeneratedJavascript)" />
</Target>
</Project>
@jamietre
Copy link
Author

jamietre commented Apr 29, 2016

Why

The standard msbuild config for Typescript ignores an actual npm dependency from package.json on typescript, so could try to compile with the wrong version. It is also unaware of any global npm installation of tsc. As such, you must manage the dependency with Nuget (aahhhhh!) -- not even an option in node projects -- or it will always just use whatever version of the Visual Studio extension is installed.

With this change, the build becomes aware of the local dependency installed in node_modules/.bin -- the version specified by package.json -- as well as the global npm version. In addition to letting you use the correct version of the compiler for every project, this means you can now use npm to manage the global version, without breaking any visual studio projects.

This revised script tries to find typescript compiler in this order:

  1. Local npm depdendency of the project
  2. global npm
  3. Nuget package
  4. Visual Studio extension

It also is different from the original in that it re-evaluates the paths it tests each time you build, instead of only at solution load time, so if you forget to npm install you can just do that and then rebuild and it will work. If it fails it provides you with a useful error message that says where it looked for the compiler, e.g.:

Could not locate typescript compiler. I looked in these locations:

- local npm 'c:\Users\{user}\code\my-solution\my-project\node_modules\.bin\'
- global npm    'c:\Users\{user}AppData\Roaming\npm\'
- nuget 'c:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\TypeScript\tsc\'
- Visual Studio plugin  'c:\Program Files (x86)\Microsoft SDKs\TypeScript\1.8'

You may want to run 'npm install' for this project, or check that your VS plugin or nuget package dependency is missing.    

Usage

  • Replace C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\TypeScript\Microsoft.TypeScript.targets with this file.
  • Probably delete the global installations to avoid conflicts.
    • C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\TypeScript\Microsoft.TypeScript.targets
    • c:\Program Files (x86)\Microsoft SDKs\TypeScript
  • Remove those from your path too

Now you can let every project manage its own compiler version with package.json, and manage the global CLI version with npm. Works for me. Let me know if I missed something.

Bug in v1.8.10 of typescript

This also removes the --locale argument from the command line which was causing problems for me. Seems that there's bug related to this: microsoft/TypeScript#8130

I verified it works fine again in typescript@1.9.0-dev.20160502 (latest nightly build - e.g. npm install typescript@next), so once the next official release is published, I'll change it back.

Future enhancements

Parse package.json and be aware if there is a dependency, but isn't found under node_modules/.bin, and tell them to npm install or perhaps just do it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment