Skip to content

Visual Studio 2017 Compile on Save only compiles the current file #18222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ghost opened this issue Sep 2, 2017 · 25 comments
Closed

Visual Studio 2017 Compile on Save only compiles the current file #18222

ghost opened this issue Sep 2, 2017 · 25 comments
Assignees
Labels
Visual Studio Integration with Visual Studio Working as Intended The behavior described is the intended behavior; this is not a bug
Milestone

Comments

@ghost
Copy link

ghost commented Sep 2, 2017

Windows 10 Version 1607

Microsoft Visual Studio Enterprise 2017
Version 15.3.3

TypeScript Version: 2.4.1 Release

Using the exact same solution (see example below) under VS2015 and VS2017, which uses "compileOnSave", VS2017 is not building any of the files listed under the "include" folders, when saving the single file listed in the "files" section. The only output is for that one file, when the file is saved. It is now also only outputting the single file being saved that is a part of the "include" section, Previously, it was building all of the files in that folder.

Can we get back the normal functionality of TSC.exe (watch), which was available in VS2015? This currently functionality is basically useless. Also, if the output files are checked-in to source control, VS2017 is not automatically checking them out like VS2015 does, which is another piece that has been broken.

Sample Project: https://developercommunity.visualstudio.com/storage/attachments/10591-typescriptbug.zip

Steps to reproduce the issue:

  1. Open the solution in VS2015.
  2. Open ~/Scripts/_apps/tsTest/tsTest.ts for edit.
  3. Save the file (CTRL-S).
  4. Look on your file system for the ~/Scripts/.tsbuild folder.
  5. You will see that all files were built.
  6. Close VS2015.
  7. Delete the ~/Scripts/.tsbuild folder.
  8. Open the solution in VS2017.
  9. Open ~/Scripts/_apps/tsTest/tsTest.ts for edit.
  10. Save the file (CTRL-S)
  11. Look on your file system for the ~/Scripts/.tsbuild folder.
  12. You will immediately see that there is no _modules folder.

VS2017 is not using TypeScript correctly.

@mhegazy
Copy link
Contributor

mhegazy commented Sep 5, 2017

looks like another report of #18130

@mhegazy mhegazy added the Duplicate An existing issue was already created label Sep 5, 2017
@ghost
Copy link
Author

ghost commented Sep 6, 2017

I created #17355, but it was marked closed as fixed, even though the problem still exists. This is not a duplicate of #18130, and covers source control issues as well.

@mhegazy mhegazy added Visual Studio Integration with Visual Studio and removed Duplicate An existing issue was already created labels Sep 6, 2017
@mhegazy mhegazy added the Bug A bug in TypeScript label Sep 6, 2017
@mhegazy mhegazy added this to the Visual Studio 15.4 milestone Sep 6, 2017
@minestarks
Copy link
Member

minestarks commented Sep 9, 2017

There's currently a more detailed discussion about this issue here: https://developercommunity.visualstudio.com/content/problem/97205/broken-typescript-compileonsave-build-tooling-for.html

Essentially, VS 2017 should probably do a full build of the project when save is invoked for the first time, and incremental builds on saves thereafter. I'm not 100% sure of the ramifications of doing so, we might have rejected it for perf reasons in the past.

The fix could be in tsserver or VS depending on how you look at it.

@ghost
Copy link
Author

ghost commented Sep 9, 2017

Here is a summary of the answers to questions that @minestarks asked:

Our solution has several individual applications that transpile many TypeScript files into single JavaScript files, and the ES5 JavaScript output files are stored in TFS (multiple tsconfig.json files). However, we also have 2 large applications (with their own tsconfig.json files) that consist of over 30 TypeScript files each. They need to be transpiled into transient output files, fed into WebPack, and the ES5 JavaScript output from WebPack is stored in TFS. The transient output files are not stored in TFS. Also, unlike VS2015, VS2017 is failing to check-out the output file prior to attempting to write to it, causing the output to silently fail.

We have disabled the TypeScript compile-on-build ability via .csproj entries, as we never want any TypeScript code to build during a solution/project build. Only developers who are actually making changes to the TypeScript code will update the JavaScript output files. The developers that don't change the TypeScript files, use the previously transpiled JavaScript files that are in TFS, which later get deployed and published to production.

@ghost
Copy link

ghost commented Sep 15, 2017

I'm not sure if this is related to my problem or not. If not, I will raise a separate issue.

We have a number of TypeScript files inside C# projects, and use the "Compile Files Not Part of a Project" setting to compile them into AMD modules (ECMAScript 5 level). In the latest Visual Studio 2017 some files are not being compiled on save (can't see any pattern in this).

The files that are being compiled are generating wildly different code from VS2015 which is not valid JavaScript (or at least, cannot be loaded by require.js).

import ko = require('knockout');
import log = require('loglevel');
import options = require('options');

var titleSource: KnockoutObservable<KnockoutObservable<string>> = ko.observable(null);

var title = ko.pureComputed(() => {
    var source = titleSource();

    if (ko.isObservable(source))
        return source();

    return options.resources['bwf_explorer'];
})

var titleViewModel = {
    pageTitle: title
};

ko.applyBindings(titleViewModel, document.getElementsByTagName("head")[0])

class Title {
    setTitle(title: KnockoutObservable<string> | string) {
        if (ko.isObservable(title))
            titleSource(title);
        else if (title != null)
            titleSource(ko.observable(title));
        else
            titleSource(null);
    }

    clearTitle() {
        titleSource(null);
    }
}

var titleFacade = new Title();
export = titleFacade;

becomes

"use strict";
var ko = require("knockout");
var options = require("options");
var titleSource = ko.observable(null);
var title = ko.pureComputed(function () {
    var source = titleSource();
    if (ko.isObservable(source))
        return source();
    return options.resources['bwf_explorer'];
});
var titleViewModel = {
    pageTitle: title
};
ko.applyBindings(titleViewModel, document.getElementsByTagName("head")[0]);
var Title = (function () {
    function Title() {
    }
    Title.prototype.setTitle = function (title) {
        if (ko.isObservable(title))
            titleSource(title);
        else if (title != null)
            titleSource(ko.observable(title));
        else
            titleSource(null);
    };
    Title.prototype.clearTitle = function () {
        titleSource(null);
    };
    return Title;
}());
var titleFacade = new Title();
module.exports = titleFacade;
//# sourceMappingURL=bwf-title.js.map

which fails to load at runtime (via requirejs 2.1.8) since module is undefined.

@minestarks
Copy link
Member

@john-cullen this sounds like an unrelated issue.

We have a number of TypeScript files inside C# projects, and use the "Compile Files Not Part of a Project" setting to compile them into AMD modules (ECMAScript 5 level).

So if I understand you correctly, the TypeScript files are part of the project? In that case, the "compile files not part of a project" setting may not apply. You may want to go into project properties -> TypeScript Build and select AMD as the module kind. Alternatively, if you're using a tsconfig.json, make sure the module kind is specified there, or if you're using MSBuild, you can use the TypeScriptModuleKind property.

The generated code in your example is valid JavaScript, it's just generating CommonJS modules, not AMD.

In the latest Visual Studio 2017 some files are not being compiled on save (can't see any pattern in this).

If this persists, please file a feedback item through Visual Studio -> Help -> Report a Problem.

Thanks for reporting!

@minestarks minestarks changed the title The TypeScript tooling for VS2017 is broken Visual Studio 2017 Compile on Save only compiles the current file Sep 15, 2017
@ghost
Copy link

ghost commented Sep 18, 2017

@minestarks hi, sorry I was unclear.

The typescript files we have are not part of a typescript project, they are in class library projects so there is no TypeScript Build settings in the Project itself. We aren't using a tsconfig either.

The project works as expected without modification in VS 2015.

@ghost
Copy link
Author

ghost commented Oct 11, 2017

@minestarks Is there any update on the status of this? I see that 15.4 was released today, and that it is not in the release. Thanks

@SimonSDA
Copy link

SimonSDA commented Dec 8, 2017

I am having the same issue in 15.4.5 :( Only way to compile ts files is to build the whole project. Have tried with and without a tsconfig.json file and the '"compileOnSave" : true' option set. Restarting the IDE doesn't help either.

@amcasey amcasey added Suggestion An idea for TypeScript and removed Bug A bug in TypeScript labels Jan 11, 2018
@amcasey
Copy link
Member

amcasey commented Jan 11, 2018

@amcasey
Copy link
Member

amcasey commented Jan 11, 2018

@Kaelum It sounds like you could get what you want by just building the project once when you open it. That build should be incremental (if not now, then in an upcoming release, because we've made improvements here) and, thereafter, compile-on-safe should re-emit all files depending on the saved one.

Conceivably, we could have compile-on-save re-emit all files the first time it is invoked, but that would add to the startup cost and probably do redundant work in cases where the files happened to already have been emitted (e.g. during a previous VS session).

@amcasey
Copy link
Member

amcasey commented Jan 11, 2018

@Kaelum I think you mentioned that you might also be having source control issues. If that's the case, can you please file a separate issue for them?

@amcasey
Copy link
Member

amcasey commented Jan 11, 2018

@SimonSDA I'm not sure I understand what problem you're seeing. What gets emitted when you save? Nothing? Just the file you saved?

@ghost
Copy link
Author

ghost commented Jan 12, 2018

@amcasey Building is not an option. As was previously discussed with @minestarks, we don't allow the build process to compile TypeScript, and it is disabled via the .csproj setting. CompileOnSave MUST work exactly as it does in Visual Studio 2015. This is why we agreed that Visual Studio 2017 MUST work exactly like TSC.exe -w does.

@amcasey
Copy link
Member

amcasey commented Jan 12, 2018

@Kaelum I'm not sure I understand why the TS files are in the same project as the other files if their builds are mutually exclusive. Would it make sense to separate them into their own project?

@ghost
Copy link
Author

ghost commented Jan 12, 2018

@amcasey no it does not. The TS files are compiled down to JavaScript, which are marked as Content, stored in source control, and published as a part of the web application. The TS files are basically stored in 2 different locations, and none of them are marked as Content:

  1. Under ~/Scripts/_apps we have individual siloes for each TS application/library, which uses modules stored under ~/Scripts/_modules. This allows us to define .tsconfig files for each TS application/library, and they compile down to .js files in the root ~/Scripts folder.
  2. Under ~/Views, along side the view .cshtml files of the same base name, we store the TS code for that view, easily references the TS applications/libraries, and compiles to a JavaScript file under ~/Scripts/<view folder>/<view name>.js.

This is not going to change, as it works extremely well for us. Only those who are allowed to write TS, are also allowed to compile it and update the JavaScript files. They check-out the JavaScript files that will be updated (this used to be automatic under previous VS versions), make their changes to the TS files, CompileOnSave, and when done, they check in both the TS and JavaScript files. Everyone who is just consuming the JavaScript output from TS does not need to have TS installed on their systems, nor do our build servers. It just works for them, and that is exactly what we want.

Putting the TS files in a separate project would make this extremely difficult to use, and won't be considered. I don't understand why anyone would remove this functionality from Visual Studio, when it has been there for years. That is beyond boggling to me. Can you explain that?

@amcasey
Copy link
Member

amcasey commented Jan 12, 2018

@Kaelum I'm glad you've found a setup that works for you. I think another way to set it up might have been to separate the files that you don't want non-TS devs to touch into their own project, configured to output to the same place they're outputting now. However, I understand that changing your project layout is not an option.

Between VS 2015 and VS 2017, the JS/TS language service (i.e. editor integration) was re-architected. The new design improved consistency between VS and other editors (especially VS Code) and lit up new features (as well as improving our ability to add still more features). However, not everything operates exactly as it used to.

Compile-on-Save is one thing that changed. It's a feature that has to achieve a delicate balance between performance and convenience. Some users, for example, find that it triggers too much work, affecting responsiveness.

https://developercommunity.visualstudio.com/content/problem/10762/typescript-background-compilation-too-often-causes.html
https://developercommunity.visualstudio.com/content/problem/36531/visual-studio-2017-compiles-all-typescript-files-w.html

At the moment, I don't think we have enough evidence to swing the pendulum back towards doing a larger build at the expense of degraded performance. We would, however, be happy to work with you (offline, if you prefer) to find a tailored mitigation for your scenario.

@amcasey amcasey added the Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature label Jan 12, 2018
@ghost
Copy link
Author

ghost commented Jan 12, 2018

@amcasey neither of those issues apply. There are basically only 2 people writing TS code at this time, myself, and one other person. The code that I've been writing is used throughout the entire site, uses the outFile option, and I have never experienced any problems once I siloed the applications/libraries. I understand the issues that those others are having, but I chalk that up to not truly using TS in the way that it was designed be used. Thus the issue that you fixed has much better alternatives, and doesn't apply to us.

The other developer has written 2 ReactJS applications that are only used by 2 views, and share about 80% of their code between the applications. These ReactJS TS code applications use outDir, as the compiled output is sent to temporary repository where WebPack detects changes and additional processing is performed. It is this temporary code repository that is no longer being generated, thus causing the WebPack processing to fail. So, this is a completely different situation.

@amcasey
Copy link
Member

amcasey commented Jan 12, 2018

@Kaelum, sorry, I didn't mean to suggest that those DeveloperCommunity users were on the opposite side of the same issue - merely that compiling more files on save would have negative consequences for some users.

Do I understand correctly that your own code is arranged in such a way that compile-on-save works for you in both VS 2015 and VS 2017 and that only this other developer is still having problems with VS 2017? Or are you both having problems?

If only 1-2 developers are affected, could you use a .csproj.user (or other project flavor) file on your individual boxes to specify that you do want to build TS files? These files would not be checked in to source control and the other developers would continue to skip the TS build.

@ghost
Copy link
Author

ghost commented Jan 12, 2018

@amcasey anyone who attempts to work on the 2 ReactJS TS applications, has the problem, which is why @minestarks and I agreed that the only fix is to use TSC.exe -w, or replicate the exact same functionality within Visual Studio.

To be honest, I don't know why you don't just allow the developer to chose either the Visual Studio way, or the TSC.exe -w way. Since the TS compiling options are now defined in the project file itself, why not add a switch and let the programmers decide? Is there a reason why Visual Studio 2017 can't kick off TSC.exe -w in a background process? I thought that that was whole reason Visual Studio 2017 took a complete left turn.

EDIT: Perhaps even add it to the Task Runner?

@minestarks
Copy link
Member

minestarks commented Jan 12, 2018

To clarify, while I think the specific request "do a full build on first save" is worth considering, I don't necessarily think we should implement it. The main drawback is negative perf consequences for large projects, which is something that impacts a lot of other users.

@ghost
Copy link
Author

ghost commented Jan 13, 2018

@minestarks is there a reason that there isn't a Microsoft managed extension for TSC.exe to run in the Task Runner Explorer? If there was, this would be a non-issue, as long as we can completely turn off the built-in functionality of Visual Studio 2017. We already use the Task Runner Explorer for WebPack and other Mads Kristensen extensions.

@billti
Copy link
Member

billti commented Jan 16, 2018

A couple of points after reading through this.

  • Visual Studio has never used "tsc -w" to perform compile-on-save. I believe it used to be the Web Essentials did, but that introduced issues/conflicts with the built-in compile-on-save in VS, so Web Essentials removed it.
  • If the files emitted by the TypeScript compile-on-save build are written to a temporary location and not checked in, and WebPack is separately compiling this to the output file that is checked in, then I'm not sure how VS is going to know to check out the file that WebPack is creating in a process external to VS. Are you sure this worked in a prior release?
  • Visual Studio used to compile more files when doing compile-on-save. This was due to concerns around correctness, and how some local changes can impact other files that are hard to detect (e.g. if reopening namespaces or changing const enums). However this was a MAJOR perf issue for people with very large TypeScript projects, as they would often make one trivial change in a file, save it, and Compile-On-Save would then spend 60 seconds going and reemiting all their files. Compile-on-save is now much smarter about only re-emitting impacted files (though I believe there are still some edge-cases where things can get out of date and a project build is required).
  • Compile-on-save is intended to emit code impacted by the file being saved, not ensure your entire project is up-to-date. As files may have been modified outside the VS session (e.g. other build tools that make changes, switching branches, touching a file in Notepad, etc), then this would effectively be an "incremental build" every time, dependent on knowing what files should be emitted, and if the emitted files are newer than the input files. We recently added support for this to MSBuild, but as you state, you have disabled the build in your project, so this doesn't help.

Effectively, sounds like you want incremental build (which ensures the project is up to date), not compile-on-save (which ensures code is generated for the file just saved). We have just completed adding incremental build (shipping shortly), but as the name would imply, this depends on a build, which you have disabled, so that won't help here.

Two thoughts that come to mind for your specific scenario:

  1. You mention you use Task Runner explorer. Can you use the NPM Scripts extension for this and add a script to run "tsc -w" which you can then launch to watch all files and do the incremental builds as files change?
  2. You also mention you are using WebPack to generate the final JavaScript bundle. Many teams using WebPack and TypeScript use one of the available TypeScript loaders to have WebPack manage the full pipeline, watching the TypeScript files and doing the full transform to the final JavaScript output (without the need for a temporary emit location). Is this possible? See the docs at https://www.typescriptlang.org/docs/handbook/integrating-with-build-tools.html#webpack .

Bottom line is compile-on-save is not intended to ensure your entire project emit is up to date, we have incremental build for that now, but that depends on having a build. You can mimic this outside of a VS build by using "tsc -w" or WebPack at the command-line, both of which can be launched by Task Runner Explorer as outlined above.

@ghost
Copy link
Author

ghost commented Feb 7, 2018

@billti sorry for the late reply, but it's been a little busy with our current release, and I wasn't sure how your response would go with the VP of my department, the other TypeScript coder. I informed everyone of your stance today, and left it to them whether or not they want to escalate this. For now, we'll just deal with the issues forced upon us.

Here are the answers to your questions:

Check-in/out: I was only referring to files managed by Visual Studio (my code), not the files managed by WebPack (the other code), as my code outputs directly to files that are a part of the project and checked into source control.

  1. This might be an option, but only if we can completely turn off all TypeScript building functionality within Visual Studio, yet keep the IntelliSence and other editing features. The only question then is, how do we manage the different TSC.exe versions, an ensure that everyone is using the correct version.
  2. Using the WebPack TypeScript loaders has a LOT of issues, especially when the majority of your code does not use WebPack, and we certainly don't want to use WebPack on code that doesn't need it. It is for this reason that we don't use them. We made a valiant effort, but they just don't work for our situation.

I both agree and disagree with some of your points, where I disagree is in the implementation, as there needs to be something to satisfy the issue presented. I do agree that for the code in question, that we could have possibly done things better, which may have completely eliminated the issue for us, but I have no options when the VP of my department says that this is how we are doing it.

@RyanCavanaugh RyanCavanaugh assigned minestarks and unassigned amcasey Jul 29, 2019
@RyanCavanaugh RyanCavanaugh removed Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript labels Jul 29, 2019
@minestarks
Copy link
Member

We suggest looking into incremental build (TS 3.4) as an alternative here - closing as Working as Intended.

@minestarks minestarks added the Working as Intended The behavior described is the intended behavior; this is not a bug label Jul 29, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Visual Studio Integration with Visual Studio Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

6 participants