X Tutup
Skip to content

Commit 87d56ac

Browse files
committed
fix(build): fix source maps
Closes #5444
1 parent 8daa9b2 commit 87d56ac

File tree

10 files changed

+234
-119
lines changed

10 files changed

+234
-119
lines changed

gulpfile.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ function launchKarmaWithExternalBrowsers(reporters, browsers, done) {
524524

525525
gulp.task('!test.unit.js/karma-server', function(done) {
526526
var watchStarted = false;
527-
var server = new karma.Server({configFile: __dirname + '/karma-js.conf.js', reporters: 'dots'});
527+
var server = new karma.Server({configFile: __dirname + '/karma-js.conf.js'});
528528
server.on('run_complete', function() {
529529
if (!watchStarted) {
530530
watchStarted = true;
@@ -548,10 +548,7 @@ gulp.task('test.unit.router', function(done) {
548548
});
549549

550550
gulp.task('!test.unit.router/karma-server', function() {
551-
new karma.Server({
552-
configFile: __dirname + '/modules/angular1_router/karma-router.conf.js',
553-
reporters: 'dots'
554-
})
551+
new karma.Server({configFile: __dirname + '/modules/angular1_router/karma-router.conf.js'})
555552
.start();
556553
});
557554

karma-js.conf.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var browserProvidersConf = require('./browser-providers.conf.js');
2+
var internalAngularReporter = require('./tools/karma/reporter.js');
23

34
// Karma configuration
45
// Generated on Thu Sep 25 2014 11:52:02 GMT-0700 (PDT)
@@ -35,6 +36,21 @@ module.exports = function(config) {
3536

3637
customLaunchers: browserProvidersConf.customLaunchers,
3738

39+
plugins: [
40+
'karma-jasmine',
41+
'karma-browserstack-launcher',
42+
'karma-sauce-launcher',
43+
'karma-chrome-launcher',
44+
'karma-sourcemap-loader',
45+
'karma-dart',
46+
internalAngularReporter
47+
],
48+
49+
preprocessors: {
50+
'**/*.js': ['sourcemap']
51+
},
52+
53+
reporters: ['internal-angular'],
3854
sauceLabs: {
3955
testName: 'Angular2',
4056
startConnect: false,

modules/playground/e2e_test/sourcemap/sourcemap_spec.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ describe('sourcemaps', function() {
2929
expect(errorColumn).not.toBeNull();
3030

3131

32-
var sourceMapData = fs.readFileSync('dist/js/prod/es5/playground/src/sourcemap/index.js.map');
32+
const content =
33+
fs.readFileSync('dist/js/dev/es5/playground/src/sourcemap/index.js').toString("utf8");
34+
const marker = "//# sourceMappingURL=data:application/json;base64,";
35+
const index = content.indexOf(marker);
36+
const sourceMapData =
37+
new Buffer(content.substring(index + marker.length), 'base64').toString("utf8");
38+
3339
var decoder = new sourceMap.SourceMapConsumer(JSON.parse(sourceMapData));
3440

3541
var originalPosition = decoder.originalPositionFor({line: errorLine, column: errorColumn});

npm-shrinkwrap.clean.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12153,6 +12153,9 @@
1215312153
}
1215412154
}
1215512155
},
12156+
"karma-sourcemap-loader": {
12157+
"version": "0.3.6"
12158+
},
1215612159
"lodash": {
1215712160
"version": "2.4.2"
1215812161
},

npm-shrinkwrap.json

Lines changed: 109 additions & 104 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
"karma-dart": "^0.3.0",
8282
"karma-jasmine": "^0.3.6",
8383
"karma-sauce-launcher": "^0.2.14",
84+
"karma-sourcemap-loader": "^0.3.6",
8485
"lodash": "^2.4.1",
8586
"madge": "0.5.0",
8687
"merge": "^1.2.0",

tools/broccoli/angular_builder.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export class AngularBuilder {
7070
{
7171
name: 'dev',
7272
typeAssertions: true,
73+
sourceMaps: true,
7374
projects: opts.projects,
7475
noTypeChecks: opts.noTypeChecks,
7576
generateEs6: opts.generateEs6
@@ -84,6 +85,7 @@ export class AngularBuilder {
8485
{
8586
name: 'prod',
8687
typeAssertions: false,
88+
sourceMaps: false,
8789
projects: opts.projects,
8890
noTypeChecks: opts.noTypeChecks,
8991
generateEs6: opts.generateEs6

tools/broccoli/broccoli-typescript.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
103103
output.outputFiles.forEach(o => {
104104
let destDirPath = path.dirname(o.name);
105105
fse.mkdirsSync(destDirPath);
106-
fs.writeFileSync(o.name, o.text, FS_OPTS);
106+
fs.writeFileSync(o.name, this.fixSourceMapSources(o.text), FS_OPTS);
107107
});
108108
}
109109
});
@@ -145,9 +145,9 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
145145

146146
private doFullBuild() {
147147
let program = this.tsService.getProgram();
148-
let emitResult = program.emit(undefined, function(absoluteFilePath, fileContent) {
148+
let emitResult = program.emit(undefined, (absoluteFilePath, fileContent) => {
149149
fse.mkdirsSync(path.dirname(absoluteFilePath));
150-
fs.writeFileSync(absoluteFilePath, fileContent, FS_OPTS);
150+
fs.writeFileSync(absoluteFilePath, this.fixSourceMapSources(fileContent), FS_OPTS);
151151
});
152152

153153
if (emitResult.emitSkipped) {
@@ -176,6 +176,33 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
176176
}
177177
}
178178

179+
/**
180+
* There is a bug in TypeScript 1.6, where the sourceRoot and inlineSourceMap properties
181+
* are exclusive. This means that the sources property always contains relative paths
182+
* (e.g, ../../../../angular2/src/di/injector.ts).
183+
*
184+
* Here, we normalize the sources property and remove the ../../../
185+
*
186+
* This issue is fixed in https://github.com/Microsoft/TypeScript/pull/5620.
187+
* Once we switch to TypeScript 1.8, we can remove this method.
188+
*/
189+
private fixSourceMapSources(content: string): string {
190+
try {
191+
const marker = "//# sourceMappingURL=data:application/json;base64,";
192+
const index = content.indexOf(marker);
193+
if (index == -1) return content;
194+
195+
const base = content.substring(0, index + marker.length);
196+
const sourceMapBit =
197+
new Buffer(content.substring(index + marker.length), 'base64').toString("utf8");
198+
const sourceMaps = JSON.parse(sourceMapBit);
199+
const source = sourceMaps.sources[0];
200+
sourceMaps.sources = [source.substring(source.lastIndexOf("../") + 3)];
201+
return `${base}${new Buffer(JSON.stringify(sourceMaps)).toString('base64')}`;
202+
} catch (e) {
203+
return content;
204+
}
205+
}
179206

180207
private removeOutputFor(tsFilePath: string) {
181208
let absoluteJsFilePath = path.join(this.cachePath, tsFilePath.replace(/\.ts$/, '.js'));

tools/broccoli/trees/browser_tree.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ module.exports = function makeBrowserTree(options, destinationPath) {
7474
const modules = options.projects;
7575
const noTypeChecks = options.noTypeChecks;
7676
const generateEs6 = options.generateEs6;
77+
const sourceMaps = options.sourceMaps;
7778

7879
if (modules.angular2) {
7980
var angular2Tree = new Funnel('modules/angular2', {
@@ -147,14 +148,13 @@ module.exports = function makeBrowserTree(options, destinationPath) {
147148
declaration: false,
148149
emitDecoratorMetadata: true,
149150
experimentalDecorators: true,
150-
mapRoot: '', // force sourcemaps to use relative path
151151
module: 'commonjs',
152152
moduleResolution: 'classic',
153153
noEmitOnError: !noTypeChecks,
154154
rootDir: './',
155155
rootFilePaths: ['angular2/manual_typings/globals.d.ts'],
156-
sourceMap: true,
157-
sourceRoot: '.',
156+
inlineSourceMap: sourceMaps,
157+
inlineSources: sourceMaps,
158158
target: 'es5'
159159
});
160160

@@ -276,12 +276,11 @@ module.exports = function makeBrowserTree(options, destinationPath) {
276276
declaration: false,
277277
emitDecoratorMetadata: true,
278278
experimentalDecorators: true,
279-
mapRoot: '', // force sourcemaps to use relative path
280279
noEmitOnError: false,
281280
rootDir: './',
282281
rootFilePaths: ['angular2/manual_typings/globals-es6.d.ts'],
283-
sourceMap: true,
284-
sourceRoot: '.',
282+
inlineSourceMap: sourceMaps,
283+
inlineSources: sourceMaps,
285284
target: 'es6'
286285
});
287286

tools/karma/reporter.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
var SourceMapConsumer = require('source-map').SourceMapConsumer;
2+
var DotsReporter = require('karma/lib/reporters/dots_color');
3+
4+
var createErrorFormatter = function (basePath, emitter, SourceMapConsumer) {
5+
var lastServedFiles = [];
6+
emitter.on('file_list_modified', function (files) {
7+
lastServedFiles = files.served
8+
});
9+
function findFile(path) {
10+
return lastServedFiles.filter(_ => _.path === path)[0];
11+
}
12+
13+
var URL_REGEXP = new RegExp('(?:https?:\\/\\/[^\\/]*)?\\/?' +
14+
'(base|absolute)' + // prefix
15+
'((?:[A-z]\\:)?[^\\?\\s\\:]*)' + // path
16+
'(\\?\\w*)?' + // sha
17+
'(\\:(\\d+))?' + // line
18+
'(\\:(\\d+))?' + // column
19+
'', 'g')
20+
21+
return function (msg, indentation) {
22+
msg = (msg || '').replace(URL_REGEXP, function (_, prefix, path, __, ___, line, ____, column) {
23+
if (prefix === 'base') {
24+
path = basePath + path;
25+
}
26+
line = parseInt(line || '0', 10);
27+
column = parseInt(column || '0', 10);
28+
29+
var file = findFile(path)
30+
if (file && file.sourceMap) {
31+
try {
32+
var original = new SourceMapConsumer(file.sourceMap).originalPositionFor({
33+
line: line,
34+
column: column
35+
});
36+
return process.cwd() + "/modules/" + original.source + ":" + original.line + ":" + original.column;
37+
} catch (e) {
38+
log.warn('SourceMap position not found for trace: %s', msg);
39+
}
40+
}
41+
return path + ':' + line + ':' + column;
42+
});
43+
44+
// indent every line
45+
if (indentation) {
46+
msg = indentation + msg.replace(/\n/g, '\n' + indentation)
47+
}
48+
return msg + '\n';
49+
}
50+
}
51+
52+
53+
var InternalAngularReporter = function (config, emitter) {
54+
var formatter = createErrorFormatter(config.basePath, emitter, SourceMapConsumer);
55+
DotsReporter.call(this, formatter, false)
56+
}
57+
InternalAngularReporter.$inject = ['config', 'emitter']
58+
59+
module.exports = {'reporter:internal-angular': ['type', InternalAngularReporter]};

0 commit comments

Comments
 (0)
X Tutup