ts-loader icon indicating copy to clipboard operation
ts-loader copied to clipboard

VSCode integration with webpack in watch mode

Open edvinv opened this issue 8 years ago • 29 comments

I'm using this loader with webpack in watch mode. In vscode you must defined start/end pattern for background task, so that vscode knows when to parse output for errors. The problem is that there is no distinguished message generated after errors are written to output stream. I also haven't found any solution to overcome this with webpack. Is it possible that this loader generates some distinguished start/end message. It is important that end message is generated after last error is streamed to output.

edvinv avatar Oct 18 '17 07:10 edvinv

Hi @edvinv,

I'm afraid I don't know what you mean about "defined start/end pattern for background task". That said, I'm an avid VS Code user. Maybe if I tell you about my workflow / setup it might be useful to you:

  • Fire up VS Code
  • Open the terminal and enter yarn start

This fires up webpack in watch mode, which allows me to see errors in the console and click upon them to get transported to the code itself. You can see examples (slightly out of date) here:

https://github.com/TypeStrong/ts-loader/tree/master/examples

Does this help at all?

johnnyreilly avatar Oct 18 '17 10:10 johnnyreilly

Note to self - I must update the examples:

  • drop the webpack 1 example
  • remove gulp entirely

johnnyreilly avatar Oct 18 '17 11:10 johnnyreilly

thx, @johnnyreilly

If you only look for errors in terminal this is ok, but if you want to make better integration and see errors in problem panel you must define problemMatcher in tasks.json. Problem matcher parses error output from compiler so that it is understood by vscode and can be correctly displayed. But for background tasks, such as webpack watch mode, vscode must know when compiling was started and when it was ended. This pattern is defined by beginsPattern and endsPattern properties in tasks.json. If you run tsc in watch mode, output is something like this:

10:09:54 AM - File change detected. Starting incremental compilation...
crosstyd/stores/dialer-campaigns-store.ts(164,47): error TS1005: ')' expected.
10:09:56 AM - Compilation complete. Watching for file changes.

So you have "Starting incremental compilation" and "Compilation complete. Watching for file changes." text that marks start/end compilation. But in the case of webpack watch mode there is no such text that can be used. Especially for marking compilation end. No text is streamed to output after last error! For example:

Hash: 4223297a8e86b7b2b6d3
Version: webpack 3.6.0
Time: 3942ms
                         Asset       Size  Chunks                    Chunk Names
.....
    + 830 hidden modules

ERROR in ./src/ui/call.ts
(20,12): error TS1005: ':' expected.

So it will be good that some start/end text will be generated, that can be used to inform vscode when background process is running. Ideally if the output will be the same as for tsc, you will be able to use "$tsc-watch" for problemMatcher and everything should work out of box.

Another benefit of knowing compilation start/end is with debugging. If you change some files and you start debugging (F5), vscode will save files what will then trigger compiler and vscode can wait for compiler to finish before debugger actually starts.

edvinv avatar Oct 19 '17 08:10 edvinv

That's interesting @edvinv - thanks for the background. For my own use case I find that the TypeScript integration in VS Code already surfaces errors in the problem pane. Don't you get the same?

johnnyreilly avatar Oct 19 '17 12:10 johnnyreilly

What you probably see is output from typescript service. As I understand those errors are auto generated for opened files and disappear when file is closed. On other side you can capture errors generated from compiler output with problem matcher as described here and here.

edvinv avatar Oct 19 '17 13:10 edvinv

Ah that's pretty cool. So what do you propose? We already have a https://github.com/typestrong/ts-loader#errorformatter-message-errorinfo-colors-boolean--string-defaultundefined option. Does that give you what you need to hook into?

johnnyreilly avatar Oct 19 '17 14:10 johnnyreilly

thx for info, I was not aware that you can configure output for ts-loader, but this is not so problematic, because for vscode you can add your own custom problem matcher or load appropriate extension like ts-loader matcher. Most problematic is the output when you run webpack in watch mode, then you don't get any message after last error and you can not inform vscode when compilation was ended. So it will be nice that ts-loader will generate start/end message when running in watch mode, like tsc does when running with --watch switch.

About output formating. IMO ts-loader should by default generate exactly the same output as tsc does, for both, normal and watch mode. This is also the most logical, if I run tsc standalone or in webpack I would expect same output result. In the case of vscode this means that you don't need any custom problem matcher or corresponding extension you just use $tsc or $tsc-watch. Of course integration of ts-loader will also be easier for other editors that already integrate tsc.

edvinv avatar Oct 23 '17 07:10 edvinv

About output formatting. IMO ts-loader should by default generate exactly the same output as tsc does, for both, normal and watch mode.

I'd be open to having an in-build formatter that supports this.

So it will be nice that ts-loader will generate start/end message when running in watch mode,

This doesn't seem unreasonable.

Would you like to submit a PR to provide this support?

johnnyreilly avatar Oct 24 '17 13:10 johnnyreilly

@johnnyreilly, sorry for late reply. Having ts-loader generate same output as tsc is good and most logical solution. This will simplify integration in vs-code and other tools.

About generating start/end message in watch mode, I have found an open issue webpack/webpack#5895. Implementing this on web-pack side is better and more general solution, so I will postpone this and wait for web-pack response.

edvinv avatar Nov 01 '17 09:11 edvinv

Any progress on this matter? I would also like to see easy integration of webpack watchmode within vs code.

JohnPascololo avatar May 19 '18 09:05 JohnPascololo

While I agree that webpack should fix the start/end watch mode issue, https://github.com/webpack/webpack/issues/5895 is closed. Hopefully it can be reconsidered. But it would be great if the error output matched tsc

eamodio avatar Aug 05 '18 23:08 eamodio

If someone wants to submit a PR I'll take a look.

johnnyreilly avatar Aug 06 '18 05:08 johnnyreilly

I was able to get it working using the following tasks.json for webpack-dev-server: https://github.com/go-faast/faast-portfolio/blob/81877b7ce302748f25d48a458cd6680cad36ace9/.vscode/tasks.json

dylanseago avatar Aug 10 '18 20:08 dylanseago

I've gotten things working decently well with this problem matcher for both ts-loader and tslint-loader:

"problemMatcher": [
	{
		"fileLocation": "absolute",
		"owner": "typescript",
		"pattern": [
			{
				"regexp": "\\[tsl\\] ERROR in (.*)?\\((\\d+),(\\d+)\\)",
				"file": 1,
				"line": 2,
				"column": 3
			},
			{
				"regexp": "\\s*TS\\d+:\\s*(.*)",
				"message": 1
			}
		],
		"severity": "error",
		"source": "ts",
		"background": {
			"activeOnStart": true,
			"beginsPattern": {
				"regexp": "webpack is watching the files..."
			},
			"endsPattern": {
				"regexp": "Built at\\:(.*)"
			}
		}
	},
	{
		"fileLocation": "relative",
		"owner": "typescript",
		"pattern": [
			{
				"regexp": "WARNING in (.*)",
				"file": 1
			},
			{
				"regexp": "Module Warning (.*)"
			},
			{
				"regexp": "\\[(\\d+), (\\d+)\\]: (.*)",
				"line": 1,
				"column": 2,
				"message": 3
			}
		],
		"severity": "warning",
		"source": "tslint",
		"background": {
			"activeOnStart": true,
			"beginsPattern": {
				"regexp": "webpack is watching the files..."
			},
			"endsPattern": {
				"regexp": "Built at\\:(.*)"
			}
		}
	}
]

The big issue is since there is no good start/stop message at the start/end of each recompile problems that have been resolved often stick around in vscode. I thought this was originally a vscode issue, but you can see the resolution here: https://github.com/Microsoft/vscode/issues/55964

eamodio avatar Aug 16 '18 18:08 eamodio

If you aren't using multiple configs (i.e. returning an array from your webpack config) (See: https://github.com/webpack/webpack/issues/7906), it looks like you can use webpack --watch --info-verbosity verbose to get lifecycle start and end messages

Using that and changing the problem matcher to the following seems to work well:

"problemMatcher": [
	{
		"fileLocation": "absolute",
		"owner": "typescript",
		"pattern": [
			{
				"regexp": "\\[tsl\\] ERROR in (.*)?\\((\\d+),(\\d+)\\)",
				"file": 1,
				"line": 2,
				"column": 3
			},
			{
				"regexp": "\\s*TS\\d+:\\s*(.*)",
				"message": 1
			}
		],
		"severity": "error",
		"source": "ts",
		"background": {
			"activeOnStart": true,
			"beginsPattern": {
				"regexp": "Compilation starting…"
			},
			"endsPattern": {
				"regexp": "Compilation finished"
			}
		}
	},
	{
		"fileLocation": "relative",
		"owner": "typescript",
		"pattern": [
			{
				"regexp": "WARNING in (.*)",
				"file": 1
			},
			{
				"regexp": "Module Warning (.*)"
			},
			{
				"regexp": "\\[(\\d+), (\\d+)\\]: (.*)",
				"line": 1,
				"column": 2,
				"message": 3
			}
		],
		"severity": "warning",
		"source": "tslint",
		"background": {
			"activeOnStart": true,
			"beginsPattern": {
				"regexp": "Compilation starting…"
			},
			"endsPattern": {
				"regexp": "Compilation finished"
			}
		}
	}
]

eamodio avatar Aug 16 '18 19:08 eamodio

If someone wants to submit a docs PR to cover this I'll happily take a look.

johnnyreilly avatar Aug 16 '18 22:08 johnnyreilly

Sorry no docs PR yet, but I published TypeScript + Webpack Problem Matchers for vscode that provides a set of problem matchers for ts-loader and tslint-loader

eamodio avatar Aug 17 '18 06:08 eamodio

@eamodio i don't understand how this solution can correctly work. Actually, when i use webpack --watch --info-verbosity verbose i get the following output:

Compilation starting…


Compilation finished

Hash: 9f5804b616b6b7ae6618
Version: webpack 4.17.2
Time: 1583ms

How does the begin/endPattern can work correctly with this kind of output ? Effective error output is not in between those two patterns ...

ClementVidal avatar Oct 07 '18 17:10 ClementVidal

@ClementVidal Yeah, I was wrong that it would be enough to be very accurate -- although it gets a lot closer than any other options right now. I still do get errors to show up in the problems pane in vscode and they often clear when resolved -- although not always because of the inaccuracy of the pattern matching.

eamodio avatar Oct 08 '18 02:10 eamodio

@eamodio Do problem 'not always' clear when you fix them, or do they never clear until you trigger a new compilation (by changing a file), in which case old problem disappear and new one replace them ? ( This is what is actually have )

ClementVidal avatar Oct 08 '18 06:10 ClementVidal

AFAIK, problems will never clear until there is a new compile when using the problem matchers, since there is no trigger to update them.

eamodio avatar Oct 08 '18 17:10 eamodio

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jan 19 '19 09:01 stale[bot]

Please don't close this -- this is a very important feature for using webpack in watch mode

eamodio avatar Jan 19 '19 20:01 eamodio

Marked as pinned - would be better to get this into the docs

johnnyreilly avatar Jan 19 '19 20:01 johnnyreilly

Its not just about docs -- and it might be more of a webpack than ts-loader issue, but there is still no way to really setup a problem matcher for vscode -- it kind of works with my published matcher, but still fails too often and if you have more than 1 webpack build it almost always fails to work. It really comes down to not having good messages to key the problem matcher regex to -- the message would need to have a structure of start, errors (if any), and then a completion.

eamodio avatar Jan 19 '19 22:01 eamodio

FWIW, this is my solution to incremental builds and problem matchers until Webpack adds a better solution. Just add this as a plugin to your Webpack config:

import webpack from "webpack";

export class ProblemMatcherMarkerPlugin implements webpack.Plugin {
    private pluginName = "ProblemMatcherMarkerPlugin";

    apply( compiler: webpack.Compiler ): void {
        compiler.hooks.done.tap( this.pluginName, stats => {
            // We're going to hook the toString function of the "stats" object
            // to put a marker at the end of the stats to signal the end of
            // error reporting

            let _toString = stats.toString;

            stats.toString = function ( options?: webpack.compiler.StatsToStringOptions ) {
                let statsString = _toString.call( this, options );

                return `${statsString}\r\n\r\n# Finished compiling!`;
            };
        } );
    }
}

It "hijacks" the toString function on Webpack's stats object to add a signal to the end. You can then use a regex to match the # Finished compiling! message as the endsPattern for your problem matchers. This works for me until Webpack adds a less-hacky solution.

ArcanoxDragon avatar Jan 15 '20 15:01 ArcanoxDragon

I've created this extension to make it more reliable. I've not check it with ts-loader for now, but in case something didn't work as expected it should be quite easy to add.

KnisterPeter avatar May 21 '20 16:05 KnisterPeter

@KnisterPeter FYI, there is a problem matcher extension for ts-loader/fork-ts-checker. And I've just added support for fork-ts-checker v5

eamodio avatar May 25 '20 19:05 eamodio

@eamodio I know, and there are a lot of shortcommings and required configuration to use it. The extension is an alternative for it.

KnisterPeter avatar May 26 '20 07:05 KnisterPeter