diff --git a/CHANGELOG.md b/CHANGELOG.md index 763cc44d1..3109ef87c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## v8.0.10 +* [Fixed missing errors in watch mode in webpack5](https://github.com/TypeStrong/ts-loader/issues/1204) - thanks @appzuka + ## v8.0.9 * [Fixed build failing when using thread-loader](https://github.com/TypeStrong/ts-loader/pull/1207) - thanks @valerio diff --git a/package.json b/package.json index 9c12bc5cd..61d67da1d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts-loader", - "version": "8.0.9", + "version": "8.0.10", "description": "TypeScript loader for webpack", "main": "index.js", "types": "dist", diff --git a/src/after-compile.ts b/src/after-compile.ts index 1f36d1d26..7cc284a08 100644 --- a/src/after-compile.ts +++ b/src/after-compile.ts @@ -21,8 +21,16 @@ import { tsLoaderSource, } from './utils'; +/** + * This returns a function that has options to add assets and also to provide errors to webpack + * In webpack 4 we can do both during the afterCompile hook + * In webpack 5 only errors should be provided during aftercompile. Assets should be + * emitted during the afterProcessAssets hook + */ export function makeAfterCompile( instance: TSInstance, + addAssets: boolean, + provideErrors: boolean, configFilePath: string | undefined ) { let getCompilerOptionDiagnostics = true; @@ -39,18 +47,22 @@ export function makeAfterCompile( } if (instance.loaderOptions.transpileOnly) { - provideAssetsFromSolutionBuilderHost(instance, compilation); + if (addAssets) { + provideAssetsFromSolutionBuilderHost(instance, compilation); + } callback(); return; } removeCompilationTSLoaderErrors(compilation, instance.loaderOptions); - provideCompilerOptionDiagnosticErrorsToWebpack( - getCompilerOptionDiagnostics, - compilation, - instance, - configFilePath - ); + if (provideErrors) { + provideCompilerOptionDiagnosticErrorsToWebpack( + getCompilerOptionDiagnostics, + compilation, + instance, + configFilePath + ); + } getCompilerOptionDiagnostics = false; const modules = determineModules(compilation, instance); @@ -62,22 +74,25 @@ export function makeAfterCompile( checkAllFilesForErrors = false; const filesWithErrors: TSFiles = new Map(); - provideErrorsToWebpack( - filesToCheckForErrors, - filesWithErrors, - compilation, - modules, - instance - ); - provideDeclarationFilesToWebpack( - filesToCheckForErrors, - instance, - compilation - ); - provideTsBuildInfoFilesToWebpack(instance, compilation); - - provideSolutionErrorsToWebpack(compilation, modules, instance); - provideAssetsFromSolutionBuilderHost(instance, compilation); + if (provideErrors) { + provideErrorsToWebpack( + filesToCheckForErrors, + filesWithErrors, + compilation, + modules, + instance + ); + provideSolutionErrorsToWebpack(compilation, modules, instance); + } + if (addAssets) { + provideDeclarationFilesToWebpack( + filesToCheckForErrors, + instance, + compilation + ); + provideTsBuildInfoFilesToWebpack(instance, compilation); + provideAssetsFromSolutionBuilderHost(instance, compilation); + } instance.filesWithErrors = filesWithErrors; instance.modifiedFiles = undefined; diff --git a/src/instances.ts b/src/instances.ts index f7496132a..d8c29dc60 100644 --- a/src/instances.ts +++ b/src/instances.ts @@ -302,6 +302,46 @@ function getExistingSolutionBuilderHost(key: FilePathKey) { return undefined; } +// Adding assets in afterCompile is deprecated in webpack 5 so we +// need different behavior for webpack4 and 5 +const addAssetHooks = !!webpack.version!.match(/^4.*/) + ? (loader: webpack.loader.LoaderContext, instance: TSInstance) => { + // add makeAfterCompile with addAssets = true to emit assets and report errors + loader._compiler.hooks.afterCompile.tapAsync( + 'ts-loader', + makeAfterCompile(instance, true, true, instance.configFilePath) + ); + } + : (loader: webpack.loader.LoaderContext, instance: TSInstance) => { + // We must be running under webpack 5+ + + // Add makeAfterCompile with addAssets = false to suppress emitting assets + // during the afterCompile stage. Errors will be still be reported to webpack + loader._compiler.hooks.afterCompile.tapAsync( + 'ts-loader', + makeAfterCompile(instance, false, true, instance.configFilePath) + ); + + // Emit the assets at the afterProcessAssets stage + loader._compilation.hooks.afterProcessAssets.tap( + 'ts-loader', + (_: any) => { + makeAfterCompile( + instance, + true, + false, + instance.configFilePath + )(loader._compilation, () => { + return null; + }); + } + ); + + // It may be better to add assets at the processAssets stage (https://webpack.js.org/api/compilation-hooks/#processassets) + // This requires Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL, which does not exist in webpack4 + // Consider changing this when ts-loader is built using webpack5 + }; + export function initializeInstance( loader: webpack.loader.LoaderContext, instance: TSInstance @@ -350,26 +390,7 @@ export function initializeInstance( instance.transformers = getCustomTransformers(program); // Setup watch run for solution building if (instance.solutionBuilderHost) { - if (loader._compilation.hooks.afterProcessAssets) { - // afterProcessAssets does not exist in webpack4 - loader._compilation.hooks.afterProcessAssets.tap( - 'ts-loader', - (_: any) => { - makeAfterCompile(instance, instance.configFilePath)( - loader._compilation, - () => { - return null; - } - ); - } - ); - } else { - // adding assets in afterCompile is deprecated in webpack 5 - loader._compiler.hooks.afterCompile.tapAsync( - 'ts-loader', - makeAfterCompile(instance, instance.configFilePath) - ); - } + addAssetHooks(loader, instance); loader._compiler.hooks.watchRun.tapAsync( 'ts-loader', makeWatchRun(instance, loader) @@ -416,26 +437,8 @@ export function initializeInstance( instance.languageService!.getProgram() ); } - if (loader._compilation.hooks.afterProcessAssets) { - // afterProcessAssets does not exist in webpack4 - loader._compilation.hooks.afterProcessAssets.tap( - 'ts-loader', - (_: any) => { - makeAfterCompile(instance, instance.configFilePath)( - loader._compilation, - () => { - return null; - } - ); - } - ); - } else { - // adding assets in afterCompile is deprecated in webpack 5 - loader._compiler.hooks.afterCompile.tapAsync( - 'ts-loader', - makeAfterCompile(instance, instance.configFilePath) - ); - } + + addAssetHooks(loader, instance); loader._compiler.hooks.watchRun.tapAsync( 'ts-loader',