diff --git a/packages/@angular/cli/commands/serve.ts b/packages/@angular/cli/commands/serve.ts index cd5b12358d3a..1550ff0d644e 100644 --- a/packages/@angular/cli/commands/serve.ts +++ b/packages/@angular/cli/commands/serve.ts @@ -135,6 +135,12 @@ const ServeCommand = Command.extend({ commandOptions.vendorChunk = !commandOptions.buildOptimizer; } + // Default evalSourcemaps to true when sourcemaps are true. + // This makes rebuilds faster. + if (commandOptions.sourcemaps === true) { + commandOptions.evalSourcemaps = true; + } + return checkPort(commandOptions.port, commandOptions.host, defaultPort) .then(port => { commandOptions.port = port; diff --git a/packages/@angular/cli/models/build-options.ts b/packages/@angular/cli/models/build-options.ts index 28cce0341396..98ed49d9cdd4 100644 --- a/packages/@angular/cli/models/build-options.ts +++ b/packages/@angular/cli/models/build-options.ts @@ -4,6 +4,7 @@ export interface BuildOptions { outputPath?: string; aot?: boolean; sourcemaps?: boolean; + evalSourcemaps?: boolean; vendorChunk?: boolean; commonChunk?: boolean; baseHref?: string; diff --git a/packages/@angular/cli/models/webpack-configs/browser.ts b/packages/@angular/cli/models/webpack-configs/browser.ts index bea9cfb97407..9a4aec0a677d 100644 --- a/packages/@angular/cli/models/webpack-configs/browser.ts +++ b/packages/@angular/cli/models/webpack-configs/browser.ts @@ -44,12 +44,22 @@ export function getBrowserConfig(wco: WebpackConfigOptions) { } if (buildOptions.sourcemaps) { - extraPlugins.push(new webpack.SourceMapDevToolPlugin({ - filename: '[file].map[query]', - moduleFilenameTemplate: '[resource-path]', - fallbackModuleFilenameTemplate: '[resource-path]?[hash]', - sourceRoot: 'webpack:///' - })); + // See https://webpack.js.org/configuration/devtool/ for sourcemap types. + if (buildOptions.evalSourcemaps && buildOptions.target === 'development') { + // Produce eval sourcemaps for development with serve, which are faster. + extraPlugins.push(new webpack.EvalSourceMapDevToolPlugin({ + moduleFilenameTemplate: '[resource-path]', + sourceRoot: 'webpack:///' + })); + } else { + // Produce full separate sourcemaps for production. + extraPlugins.push(new webpack.SourceMapDevToolPlugin({ + filename: '[file].map[query]', + moduleFilenameTemplate: '[resource-path]', + fallbackModuleFilenameTemplate: '[resource-path]?[hash]', + sourceRoot: 'webpack:///' + })); + } } if (buildOptions.commonChunk) { diff --git a/packages/@angular/cli/models/webpack-configs/common.ts b/packages/@angular/cli/models/webpack-configs/common.ts index 732427a97deb..1395f2b350bd 100644 --- a/packages/@angular/cli/models/webpack-configs/common.ts +++ b/packages/@angular/cli/models/webpack-configs/common.ts @@ -188,9 +188,6 @@ export function getCommonConfig(wco: WebpackConfigOptions) { }, module: { rules: [ - { enforce: 'pre', test: /\.js$/, loader: 'source-map-loader', exclude: [ - nodeModules, /\.ngfactory\.js$/, /\.ngstyle\.js$/ - ] }, { test: /\.html$/, loader: 'raw-loader' }, { test: /\.(eot|svg|cur)$/, loader: `file-loader?name=[name]${hashFormat.file}.[ext]` }, { diff --git a/packages/@ngtools/webpack/src/angular_compiler_plugin.ts b/packages/@ngtools/webpack/src/angular_compiler_plugin.ts index 811138ba4b0b..22eaa993a781 100644 --- a/packages/@ngtools/webpack/src/angular_compiler_plugin.ts +++ b/packages/@ngtools/webpack/src/angular_compiler_plugin.ts @@ -212,13 +212,17 @@ export class AngularCompilerPlugin implements Tapable { this._compilerOptions.sourceMap = true; this._compilerOptions.inlineSources = true; this._compilerOptions.inlineSourceMap = false; - this._compilerOptions.sourceRoot = basePath; + this._compilerOptions.mapRoot = undefined; + // We will set the source to the full path of the file in the loader, so we don't + // need sourceRoot here. + this._compilerOptions.sourceRoot = undefined; } else { this._compilerOptions.sourceMap = false; this._compilerOptions.sourceRoot = undefined; this._compilerOptions.inlineSources = undefined; this._compilerOptions.inlineSourceMap = undefined; this._compilerOptions.mapRoot = undefined; + this._compilerOptions.sourceRoot = undefined; } // Compose Angular Compiler Options. diff --git a/packages/@ngtools/webpack/src/loader.ts b/packages/@ngtools/webpack/src/loader.ts index e02a4609fea9..1d5074e74c38 100644 --- a/packages/@ngtools/webpack/src/loader.ts +++ b/packages/@ngtools/webpack/src/loader.ts @@ -14,6 +14,8 @@ interface Platform { const loaderUtils = require('loader-utils'); const NormalModule = require('webpack/lib/NormalModule'); +const sourceMappingUrlRe = /^\/\/# sourceMappingURL=[^\r\n]*/gm; + // This is a map of changes which need to be made const changeMap: {[key: string]: Platform} = { platformBrowserDynamic: { @@ -544,6 +546,17 @@ export function ngcLoader(this: LoaderContext & { _compilation: any }, source: s .then(() => { timeEnd(timeLabel + '.ngcLoader.AngularCompilerPlugin'); const result = plugin.getFile(sourceFileName); + + if (result.sourceMap) { + // Process sourcemaps for Webpack. + // Remove the sourceMappingURL. + result.outputText = result.outputText.replace(sourceMappingUrlRe, ''); + // Set the map source to use the full path of the file. + const sourceMap = JSON.parse(result.sourceMap); + sourceMap.sources[0] = sourceFileName; + result.sourceMap = JSON.stringify(sourceMap); + } + if (plugin.failedCompilation) { // Return an empty string if there is no result to prevent extra loader errors. // Plugin errors were already pushed to the compilation errors. @@ -551,12 +564,12 @@ export function ngcLoader(this: LoaderContext & { _compilation: any }, source: s cb(null, result.outputText || '', result.sourceMap); } else { timeEnd(timeLabel); - cb(null, result.outputText, result.sourceMap); - } - }) - .catch(err => { - timeEnd(timeLabel + '.ngcLoader.AngularCompilerPlugin'); - cb(err); + cb(null, result.outputText, result.sourceMap); + } + }) + .catch(err => { + timeEnd(timeLabel + '.ngcLoader.AngularCompilerPlugin'); + cb(err); }); } else if (plugin instanceof AotPlugin) { time(timeLabel + '.ngcLoader.AotPlugin'); @@ -686,7 +699,7 @@ export function ngcLoader(this: LoaderContext & { _compilation: any }, source: s const result = refactor.transpile(compilerOptions); // Webpack is going to take care of this. - result.outputText = result.outputText.replace(/^\/\/# sourceMappingURL=[^\r\n]*/gm, ''); + result.outputText = result.outputText.replace(sourceMappingUrlRe, ''); timeEnd(timeLabel); cb(null, result.outputText, result.sourceMap); }