fix(compiler): make sourcemaps work in AOT mode

Inlcuded fixes:
- include preamble in generated source map
- always add a mapping for line/col 0 so that the
  generated sourcemap is not sparse
- use a uniue sourceUrl for inline templates even
  in the AOT case
This commit is contained in:
Tobias Bosch
2017-03-15 15:50:30 -07:00
committed by Chuck Jazdzewski
parent c0e05e6f03
commit 492153a986
24 changed files with 299 additions and 123 deletions

View File

@ -0,0 +1,2 @@
<div>
<span [title]="createError()"></span></div>

View File

@ -0,0 +1,14 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component} from '@angular/core';
@Component({selector: 'comp-with-error', templateUrl: 'errors.html'})
export class BindingErrorComp {
createError() { throw new Error('Test'); }
}

View File

@ -22,6 +22,7 @@ import {BasicComp} from './basic';
import {ComponentUsingThirdParty} from './comp_using_3rdp';
import {CUSTOM} from './custom_token';
import {CompWithAnalyzeEntryComponentsProvider, CompWithEntryComponents} from './entry_components';
import {BindingErrorComp} from './errors';
import {CompConsumingEvents, CompUsingPipes, CompWithProviders, CompWithReferences, DirPublishingEvents, ModuleUsingCustomElements} from './features';
import {CompUsingRootModuleDirectiveAndPipe, SomeDirectiveInRootModule, SomeLibModule, SomePipeInRootModule, SomeService} from './module_fixtures';
import {CompWithNgContent, ProjectingComp} from './projection';
@ -63,6 +64,7 @@ export const SERVER_ANIMATIONS_PROVIDERS: Provider[] = [{
SomeDirectiveInRootModule,
SomePipeInRootModule,
ComponentUsingThirdParty,
BindingErrorComp,
],
imports: [
NoopAnimationsModule,
@ -88,6 +90,7 @@ export const SERVER_ANIMATIONS_PROVIDERS: Provider[] = [{
CompWithReferences,
ProjectingComp,
ComponentUsingThirdParty,
BindingErrorComp,
]
})
export class MainModule {

View File

@ -6,6 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
require('source-map-support').install();
import './init';
import './animate_spec';
import './basic_spec';
@ -14,3 +16,4 @@ import './i18n_spec';
import './ng_module_spec';
import './projection_spec';
import './query_spec';
import './source_map_spec';

View File

@ -0,0 +1,41 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import './init';
import {BindingErrorComp} from '../src/errors';
import {createComponent} from './util';
describe('source maps', () => {
it('should report source location for binding errors', () => {
const comp = createComponent(BindingErrorComp);
let error: any;
try {
comp.detectChanges();
} catch (e) {
error = e;
}
const sourcePosition = getSourcePositionForStack(error.stack);
expect(sourcePosition.line).toBe(2);
expect(sourcePosition.column).toBe(13);
expect(sourcePosition.source.endsWith('errors.html')).toBe(true);
});
});
function getSourcePositionForStack(stack: string): {source: string, line: number, column: number} {
const htmlLocations = stack
.split('\n')
// e.g. at View_MyComp_0 (...html:153:40)
.map(line => /\((.*\.html):(\d+):(\d+)/.exec(line))
.filter(match => !!match)
.map(match => ({
source: match[1],
line: parseInt(match[2], 10),
column: parseInt(match[3], 10)
}));
return htmlLocations[0];
}

View File

@ -17,7 +17,8 @@
"baseUrl": ".",
// Prevent scanning up the directory tree for types
"typeRoots": ["node_modules/@types"],
"noUnusedLocals": true
"noUnusedLocals": true,
"sourceMap": true
},
"files": [

View File

@ -11,5 +11,9 @@ module.exports = {
entry: './test/all_spec.js',
output: {filename: './all_spec.js'},
resolve: {extensions: ['.js']},
devtool: '#source-map',
module: {
loaders:
[{test: /\.js$/, exclude: /node_modules/, loaders: ['source-map-loader'], enforce: 'pre'}]
},
};

View File

@ -45,7 +45,7 @@ export class CodeGenerator {
const sourceFile = this.program.getSourceFile(generatedModule.srcFileUrl);
const emitPath = this.ngCompilerHost.calculateEmitPath(generatedModule.genFileUrl);
const source = GENERATED_META_FILES.test(emitPath) ? generatedModule.source :
PREAMBLE + generatedModule.source;
generatedModule.source;
this.host.writeFile(emitPath, source, false, () => {}, [sourceFile]);
});
});
@ -76,6 +76,7 @@ export class CodeGenerator {
i18nFormat: cliOptions.i18nFormat,
locale: cliOptions.locale,
enableLegacyTemplate: options.enableLegacyTemplate !== false,
genFilePreamble: PREAMBLE,
});
return new CodeGenerator(options, program, tsCompilerHost, aotCompiler, ngCompilerHost);
}