Skip to content

Commit 90f1c7c

Browse files
committed
fix(@ngtools/webpack): diagnose generated files and resolve sourcemaps
Generated files were not diagnosed in AOT which led to errors not being shown properly. Also, in order to show the proper error source we now resolve the sourcemap of any errors we find. Fixes angular#5264 Fixed angular#4538
1 parent b918603 commit 90f1c7c

File tree

1 file changed

+47
-5
lines changed

1 file changed

+47
-5
lines changed

packages/@ngtools/webpack/src/plugin.ts

+47-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import * as fs from 'fs';
33
import * as path from 'path';
44
import * as ts from 'typescript';
5+
import * as SourceMap from 'source-map';
56

67
const {__NGTOOLS_PRIVATE_API_2} = require('@angular/compiler-cli');
78
const ContextElementDependency = require('webpack/lib/dependencies/ContextElementDependency');
@@ -36,6 +37,9 @@ export interface AotPluginOptions {
3637
}
3738

3839

40+
const inlineSourceMapRe = /\/\/# sourceMappingURL=data:application\/json;base64,([\s\S]+)$/;
41+
42+
3943
export class AotPlugin implements Tapable {
4044
private _options: AotPluginOptions;
4145

@@ -342,16 +346,40 @@ export class AotPlugin implements Tapable {
342346
});
343347
}
344348

349+
private _translateSourceMap(sourceText: string, fileName: string,
350+
{line, character}: {line: number, character: number}) {
351+
const match = sourceText.match(inlineSourceMapRe);
352+
353+
if (!match) {
354+
return {line, character, fileName};
355+
}
356+
357+
// On any error, return line and character.
358+
try {
359+
const sourceMapJson = JSON.parse(Buffer.from(match[1], 'base64').toString());
360+
const consumer = new SourceMap.SourceMapConsumer(sourceMapJson);
361+
362+
const original = consumer.originalPositionFor({ line, column: character });
363+
return {
364+
line: original.line,
365+
character: original.column,
366+
fileName: original.source || fileName
367+
};
368+
} catch (e) {
369+
return {line, character, fileName};
370+
}
371+
}
372+
345373
diagnose(fileName: string) {
346374
if (this._diagnoseFiles[fileName]) {
347375
return;
348376
}
349377
this._diagnoseFiles[fileName] = true;
350378

351379
const sourceFile = this._program.getSourceFile(fileName);
352-
if (!sourceFile) {
353-
return;
354-
}
380+
if (!sourceFile) {
381+
return;
382+
}
355383

356384
const diagnostics: ts.Diagnostic[] = []
357385
.concat(
@@ -364,9 +392,14 @@ export class AotPlugin implements Tapable {
364392
if (diagnostics.length > 0) {
365393
const message = diagnostics
366394
.map(diagnostic => {
367-
const {line, character} = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
395+
const position = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
396+
397+
const sourceText = diagnostic.file.getFullText();
398+
let {line, character, fileName} = this._translateSourceMap(sourceText,
399+
diagnostic.file.fileName, position);
400+
368401
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
369-
return `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message})`;
402+
return `${fileName} (${line + 1},${character + 1}): ${message}`;
370403
})
371404
.join('\n');
372405
this._compilation.errors.push(message);
@@ -404,6 +437,15 @@ export class AotPlugin implements Tapable {
404437
});
405438
})
406439
.then(() => {
440+
// Get the ngfactory that were created by the previous step, and add them to the root
441+
// file path (if those files exists).
442+
const newRootFilePath = this._compilerHost.getChangedFilePaths()
443+
.filter(x => x.match(/\.ngfactory\.ts$/));
444+
// Remove files that don't exist anymore, and add new files.
445+
this._rootFilePath = this._rootFilePath
446+
.filter(x => this._compilerHost.fileExists(x))
447+
.concat(newRootFilePath);
448+
407449
// Create a new Program, based on the old one. This will trigger a resolution of all
408450
// transitive modules, which include files that might just have been generated.
409451
// This needs to happen after the code generator has been created for generated files

0 commit comments

Comments
 (0)