Typescript: Visual Studio "No Compile" option

Created on 11 Mar 2015  ·  29Comments  ·  Source: microsoft/TypeScript

Hi,

We've recently developed an enhancement for the grunt-ts plugin that allows targeting a Visual Studio project file for input TS file paths and TS config info rather than having to use src: and the other options. https://github.com/TypeStrong/grunt-ts/pull/215

Grunt-ts along with Task Runner Explorer enables developers to use features not yet supported by the Visual Studio TypeScript project build config UI (such as preserveConstEnums).

One thing about using Task Runner Explorer is that it can only hook into certain Visual Studio events. Among them is "after build" and "before build". After build works great, but it has the odd issue of VS doing its own compilation step of the TypeScript followed by grunt-ts calling tsc. This doesn't seem to be an issue except for performance (the work VS is doing to compile and emit is wasted effort and the developer has to wait longer for the desired result).

I'm wondering what the best way would be for us to turn off _only_ the compile/emit in Visual Studio for TypeScript, but keep everything else the same (language service/syntax highlighting, errors list, C# or VB building, etc). Is this even currently possible? If not, could it be?

Thanks!

Question

Most helpful comment

Just FYI, in VS2015 RTM there is an easier way to disable TypeScriptCompile:
Just add <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> to the .csproj, e.g. in the first <PropertyGroup>.

All 29 comments

Hi, just a few days ago I submitted issue #2252 that's somewhat related to this. I need some way to trigger pre- and post-build events when using compile-on-save for a TS project having a single file output (while still maintaining the usual VS "Build" and "Rebuild" commands, language service, debugging etc.). As a workaround I'm currently using Task Runner Explorer with grunt-contrib-watch (launched using a binding of "Solution Open") to watch the compiled file for changes and perform additional actions every time it's modified.

However I don't find that really satisfying (I also need to perform some pre-compilation actions and generally prefer having build steps done either all using Grunt or all with VS) and consider doing exactly what is described: Turn off the VS compilation completely and implement a custom compile-on-save, full builds (that include running unit tests etc.), pre- and post- build events with a combination of grunt-contrib-watch, grunt-ts, additional grunt plugins and Task Runner Explorer.

(update: already implemented that and it works fine - it runs a custom grunt build script every time a .ts file is modified, though currently it doesn't support TRE "Before Build" and "After Build" bindings - for the above mentioned reasons).

It seems that the easiest (and least involved for TS plugin developers) way to efficiently allow these kinds of build scenarios would be to provide an option to turn off any form of compilation initiated by Visual Studio. I would, too, appreciate any ideas on how to do that?

I don't know if there's a great option for you right now. If you set every .ts file in the project to have Build Action: None in its properties that would probably do what you want but it's pretty onerous to do manually even in medium sized projects.

Build is derived by targets in MSBuild projects. If you want to disable the default typescript build, remove the reference to the typescript targets from your file.

This is going to make your language service not collect all files in the project in one context. I would say that is fine, and by next release we should have tsconfig support and then that becomes your new project. If you still want to make it work without using tsconfig, and/or waiting for the next release, define a property <TypeScriptEnabled>true</TypeScriptEnabled> in your project file.

@mhegazy did you mean <TypeScriptEnabled>false</TypeScriptEnabled> ?

well depending on what you want :)

if you want to turn off the language service project content loading, make it false,
if you want to enable it, make it true. it is already enabled by including the default targets (Microsoft.TypeScript.targets)

OK I'll mess around with it. Thanks!

Thanks @mhegazy, the configuration option seems to work so far! (while still showing syntax/complie errors and allowing debugging in IE) and can even be set for a specific solution configuration (I tried and it seemed to work), like this:

<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
...
    <TypeScriptEnabled>false</TypeScriptEnabled>
...
</PropertyGroup>

I'm not exactly sure though what "disabling the language service project content loading" means? (I'm not very familiar with VS concepts like targets, contexts etc). As far as I've tested, everything seems to work normally with this option (apart from the expected behavior of not compiling on build)? And it looks like it will still add <TypeScriptCompile Include=".."/> entries for newly added/created .ts files in the project configuration.

On a side note, now with everything done through Grunt, I somehow have to find a way to deal with collisions between grunt-watch triggered builds and "Before Build"/"After Build" bound events when invoking the VS Build(F6) and Rebuild commands, as VS automatically saves before the build starts, leading to two different Grunt instances needlessly running in parallel.

I was not able to get <TypeScriptEnabled>false</TypeScriptEnabled> to work (VS 2013 Update 4 with TypeScript 1.4), but removing the TypeScript targets file from the project did disable the compilation on project Build.

Here's the complete steps required to disable TypeScript compilation in VS (though still have the language services work, keep refactoring happy, etc.):

  • Remove the reference to the TypeScript ".targets" file from the project file.
  • Disable "Automatically compile TypeScript files which are not part of a project" in the Visual Studio TypeScript options.

The second step is sort of a bug (or at least the dialog is not labeled in a strictly accurate manner); Even though your TypeScript files are "part" of a project, if you disable the targets file, Visual Studio 2013 will treat them as if they are _not_ part of a project and do compile on save (if the global option is not set). I couldn't get <TypeScriptEnabled/> to do anything.

Thanks @mhegazy - it would be awesome if this could be part of the TypeScript options dialog, but at least it's fairly easy to support via project edit.

one tricky thing, is <TypeScriptEnabled>false</TypeScriptEnabled> needs to be at the end of your file specifically after the import to the targets. as the targets define it anyways, and you want to override it.

one tricky thing, is false needs to be at the end of your file specifically after the import to the targets. as the targets define it anyways, and you want to override it.

You're exactly right! This was the trick.

I think this solves the problem. Thanks, @mhegazy .

Hi @mhegazy - sorry to trouble you. Are you certain that <TypeScriptEnabled>false</TypeScriptEnabled> works in VS 2013 with TypeScript 1.4 installed? I just upgraded my current PC from VS 2013 with TS 1.3 (straight VS 2013 Update 4) to VS 2013 with TS 1.4, and now Visual Studio is trying to build the TypeScript again "on build" (meaning the errors that appear have "Build:" in front of them), even though the last five lines of my projects are as below:

  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets" Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets')" />
  <PropertyGroup>
    <TypeScriptEnabled>false</TypeScriptEnabled>
  </PropertyGroup>
</Project>

It was working correctly on this machine earlier today (when I closed this ticket), but now that I put 1.4 on here, the Build from VS is giving me errors. Commenting out the reference to the targets file (and turning off "compile on save" for TypeScript not in a project) does still disable it.

I have 1.4 at home and I couldn't get <TypeScriptEnabled>false</TypeScriptEnabled> to work at all there - I'm wondering if there was a regression on this build option?

<TypeScriptEnabled>false</TypeScriptEnabled> has nothing to do with build. it is all about Language Service treating your files as part of a project or not.

if you do not want to get build on F5, remove the reference to the targets.

That was the short answer, here is the long version:

The project file is used for two things:

  1. build, this is your normal MSBuild support, where targets call tasks, and the system finds inputs, matching targets, and execute them in order. so all what this does is aggregate all TypeScriptCompile items in the project, pass them to tsc.exe along with some options.
    Additionally, the Project property pages are derived from your project file, and are just UI over MSBuild properties.
  2. language service, this your completion, signature help, errors in VS, compile on save .. etc.. we want these to work the same way your normal build works, so we look up the same properties you define for build, and drive the LS behavior. e.g. if your target is set to ES3 in your project file (<TypeScriptTarget>ES3</TypeScriptTarget>), your language service will give you a red squiggle if you define a get/set in a class.
    This allows you to use one set of options for both build and design time behavior.
    For this to work, the targets tells the language service that it knows about typescript by defining a property <TypeScriptEnabled>true</TypeScriptEnabled>.

If you do not want build in VS to work, just remove the targets. this will disable build, but will also tell the LS that this project is not a TypeScript project. and it will then treat all files as "loose files". if this is ok with you, then no more work is needed. if you want to change that and make it still use the properties from your project file, and not include other files open in your project, etc.. then add <TypeScriptEnabled>true</TypeScriptEnabled> to your file, and the LS will treat it accordingly.

If you want the build to work in VS, but the LS not to treat it as a project, then set the flag to false.

Thanks. This is great information and everything seems to work consistently with what you've described. If I've removed the .targets file, but set TypeScriptEnabled to true, is it expected that the TypeScript Build tab should disappear from the project properties?

  <!--
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets" Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets')" />
  -->
  <PropertyGroup>
    <TypeScriptEnabled>true</TypeScriptEnabled>
  </PropertyGroup>
</Project>

If so, this seems odd because it means there would be no way to control the settings that were accessible in the UI without re-enabling the target and then using the UI (or more realistically just editing the TS project setting directly at that point since you're in there anyway).

The reason I'm asking all this is that I wrote an npm library a few weeks ago to read the TypeScript build properties out of a .csproj and .vbproj (https://www.npmjs.com/package/csproj2ts) which I'm currently integrating into grunt-ts. When it's ready, there will be an easy way to effectively "run tsc against a .csproj file" (as requested here: https://github.com/Microsoft/TypeScript/issues/1702). I want to be able to tell people the best way to set up their project to use the VS TypeScript language service for their coding experience, but entirely use grunt-ts for building. I was hoping that it would be possible to let people use the UI to configure TypeScript properties in this scenario, but perhaps it won't be.

Are you aware of a way to have the TypeScript Build tab show up with the TypeScript .targets file disabled?

Also, it seems even if I do something like this: <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets" Condition=" '$(Configuration)' == 'Debug' " />, I have to set the project config to Debug and then reload in order to get the TypeScript Build tab to appear.

Sorry, @mhegazy - I promise I'm not trolling you!!

is it expected that the TypeScript Build tab should disappear from the project properties?

yes, the property pages are wired in the targets, so removing them removes the UI, you will have to manually edit the file

The reason I'm asking all this is that I wrote an npm library a few weeks ago to read the TypeScript build properties out of a .csproj and .vbproj (https://www.npmjs.com/package/csproj2ts) which I'm currently integrating into grunt-ts.

The scenario you are trying to achieve is doable, but will have some rough edges, and you will need to hack a few places to make it work. @paulvanbrenk is currently adding support for tsconfig in VS, this allows the project property pages to use the tsconfig file if it was there. We are also working on integrating better in ASP.net 5 projects, which i believe will do all what you want, namely 1. grubt/bower support, 2. a file system based view, 3. use tsconfig to manage project properties, and 4. simple interaction with other editors/IDEs. I believe this will work nicely with the scenario you are describing and you will not have to hack your way around it. this will come in the next release though, so some waiting is involved :)

Also, it seems even if I do something like this: , I have to set the project config to Debug and then reload in order to get the TypeScript Build tab to appear.

Imports are loaded when the project is loaded. so in this import you are saying loaded only in 'Configuration' 'Debug', changing the configuration does not force a reload.

Sorry, @mhegazy - I promise I'm not trolling you!!
:D no worries. always love to get feedback, and hope that helped.

OK. Truly, thank you for such excellent information and thorough discussion.

Just to throw it out there to @paulvanbrenk - it would be awesome to have some sort of way even in the future state with the tsconfig to have the ability to disable the VisualStudio TypeScript build (meaning CTRL+SHIFT+B builds your C# and etc, but not TypeScript) and use an external TypeScript compiler while leaving the ability to set TypeScript options via the GUI. There are plenty of reasons why using an external compile tool can be very helpful and right now it feels like this is really only supported by accident and with some rough edges.

The tsconfig idea is awesome, but it doesn't really help with:

  • Using an old version of TypeScript
  • Using different versions of TypeScript on different projects on the same computer
  • Using an experimental version of TypeScript (such as @fdecampredon 's version that supports JSX)
  • Using a build tool like grunt-ts that automates reference management and does other chores that TypeScript doesn't support
  • Etc.

Allowing Visual Studio users to choose a community-developed TypeScript compiler system while still keeping the nice UI inside Visual Studio would be awesome (especially with the nice Task Runner Explorer add-on). I hope you'll weigh the significant benefits to the community this would enable against the time it would take you to code a checkbox that says "Disable TypeScript Build".

I hope you'll weigh the significant benefits to the community this would enable against the time it would take you to code a checkbox that says "Disable TypeScript Build".

This is the part where i get confused. to me this is removing the typescript targets reference, then replacing it with your grunt targets that will build things differently. it feels strange to me to include a .targets file with a condition that tells it to do nothing; why include it in the first place? I would be happy to help compose a .targets file that replaces the standard typescript targets, this one will include the <TypeScriptEnabled>true</TypeScriptEnabled> tag and will look to VS as if it is the default one, but it will handle build differently.

Huh. I should have thought of that - I think I've been treating the .targets file as this unchangeable thing, but of course this makes perfect sense. I'll look into the targets file format and get back to you.

an easy way to start is to copy the targets file Microsoft.TypeScript.Target, remove things that you do not care about, e.g. calling tsc, and add tasks to call grunt, and wire in the configuration, etc.. then include it in your project.

Awesome! I've gotten everything working from a minimalist perspective by setting my .csproj file with the following 4 lines.

  <Import Project="$(ProjectDir)\custom.TypeScript.targets" />
  <PropertyGroup>
    <TypeScriptEnabled>true</TypeScriptEnabled>
  </PropertyGroup>

And the minimalist custom.TypeScript.targets file is this:

<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="$(VSToolsPath)\TypeScript\TypeScript.tasks.dll" />
  <PropertyGroup>
    <CfgPropertyPagesGuidsAddCSharp>{d4683cae-88c4-4b85-863d-ac8014f3ba36}</CfgPropertyPagesGuidsAddCSharp>
    <CfgPropertyPagesGuidsAddVB>{d4683cae-88c4-4b85-863d-ac8014f3ba36}</CfgPropertyPagesGuidsAddVB>
    <CfgPropertyPagesGuidsAddTypeScript>{d4683cae-88c4-4b85-863d-ac8014f3ba36}</CfgPropertyPagesGuidsAddTypeScript>
  </PropertyGroup>
  <ItemGroup>
    <ProjectCapability Include="TypeScript" />
  </ItemGroup>
</Project>

I tried putting the <TypeScriptEnabled /> tag in the targets file, but it wasn't working (VS was treating the .ts files as loose). Any idea why that is? (I'm sure for someone that knows MSBuild this is obvious - maybe some sort of scope problem?).

I think that this solves my problem at this point. I can run my Grunt task using the Task Runner Explorer extension which can kick off Grunt or Gulp tasks when a VS Build is triggered. The build now always shows as having succeeded regardless of the TypeScript compile result, but this is fine since the user can see the output from grunt-ts in the TRX window. The "TypeScript Build" panel appears in the project properties window. Compile on save works if that option is selected. The build still shows as failed if the C# or VB code doesn't compile successfully (a good thing). The setup to get here from a default Visual Studio "HTML Application with TypeScript" or ASP.NET web project is fairly straight-forward.

Can you see any problem with us distributing the above minimalist .targets file with grunt-ts? That would mean that we'd only have to tell people to update their project's .targets line to <Import Project="$(ProjectDir)\node_modules\grunt-ts\custom.TypeScript.targets" /> and set <TypeScriptEnabled>.

Thanks again!!

I tried putting the tag in the targets file, but it wasn't working (VS was treating the .ts files as loose). Any idea why that is? (I'm sure for someone that knows MSBuild this is obvious - maybe some sort of scope problem?).

this is strange. this is how we have it in our targets, and it works fine. are you including other targets that has the property? any conditions? i tried it in a new ts project, removed the Microsoft.TypeScript.targets, and put yours, and added true and that worked.

Can you see any problem with us distributing the above minimalist .targets file with grunt-ts? That would mean that we'd only have to tell people to update their project's .targets line to and set .

I think this is the correct way to go. i would just try to get the TypeScriptEnabled in there as well. let me know how i can help diagnosing the issue

a few notes, you do not need the tasks.dll reference nor the VsToolsPath definition, unless you need it for something else.

I'm seeing the behavior you predicted on my home computer. It also worked without the reference to the DLL. I must have made some sort of mistake before, so I'll try it out again tomorrow. I think this is really great! Thanks, Mohamed. This should be released as part of grunt-ts in the next few days.

one thing that might be causing this is target files are only loaded once in VS, so if you edit the targets the changes will not be reflected in your project until you restart VS.

That could have been it; I was just unloading/reloading the project. It's possible I restarted VS at home. I'll make a note of that in the docs.

@mhegazy Thanks for all your help. We've released grunt-ts 4.0.0 which contains the "compile from Visual Studio Project" feature:

https://github.com/TypeStrong/grunt-ts#vs

Instructions to disable VS build:

https://github.com/TypeStrong/grunt-ts/blob/master/docs/DisableVisualStudioBuild.md

Very cool! I love the scenarios this enables.

Thanks, Ryan. I'm fairly pleased with how it turned out. When tsconfig comes about, it might be less necessary, but this will bridge the gap until then and of course it's compatible with TypeScript compiler versions prior to 1.5.

PS: There have been two bug reports today, so we should be pushing a 4.0.1 tonight assuming I can get them corrected.

Just FYI, in VS2015 RTM there is an easier way to disable TypeScriptCompile:
Just add <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> to the .csproj, e.g. in the first <PropertyGroup>.

Thanks.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dlaberge picture dlaberge  ·  3Comments

Zlatkovsky picture Zlatkovsky  ·  3Comments

blendsdk picture blendsdk  ·  3Comments

siddjain picture siddjain  ·  3Comments

Roam-Cooper picture Roam-Cooper  ·  3Comments