Skip to content

Commit 095feb1

Browse files
alan-agius4dherges
authored andcommitted
fix: inline sourcemaps as base64-encoded data URI in esm5/esm015 (#812)
Fixes an issue where sourcemaps are not working when rebuilding during webpack watch. What this change brings is: - `relocation` and `rewiring` of sourcemaps happens during flattening part. - `ESM5` and `ESM2015` has inlined sourcemaps which conforms with `APF V6`. The source mapps are inlined with `//# sourceMappingURL=data:application/json;base64,<sourcesContent>` - Downleveling of `ESM2015` to `ESM5` has been removed in favor of an `ngc` parallel build this improve the build time by approx 10% in some cases. This is also a step towards incremental builds. Closes #785 #803
1 parent f911882 commit 095feb1

27 files changed

+151
-304
lines changed

integration/consumers/ng-cli/tsconfig.json

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,12 @@
33
"compilerOptions": {
44
"outDir": "./dist/out-tsc",
55
"baseUrl": "src",
6-
"sourceMap": true,
76
"declaration": false,
87
"moduleResolution": "node",
98
"emitDecoratorMetadata": true,
109
"experimentalDecorators": true,
1110
"target": "es5",
12-
"typeRoots": [
13-
"node_modules/@types"
14-
],
15-
"lib": [
16-
"es2016",
17-
"dom"
18-
]
11+
"typeRoots": ["node_modules/@types"],
12+
"lib": ["es2016", "dom"]
1913
}
2014
}

integration/samples/apf/specs/files.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,17 @@ describe('@sample/apf', () => {
4747
});
4848

4949
describe('ESM5', () => {
50-
it(`should contain 16 '.js.map' files`, () => {
51-
expect(glob.sync(`${DIST}/esm5/**/*.js.map`).length).equal(16);
50+
it(`should contain 0 '.js.map' files`, () => {
51+
expect(glob.sync(`${DIST}/esm5/**/*.js.map`).length).equal(0);
5252
});
5353

5454
it(`should contain 16 '.js' files`, () => {
5555
expect(glob.sync(`${DIST}/esm5/**/*.js`).length).equal(16);
5656
});
5757

5858
describe('secondary', () => {
59-
it(`should contain 8 '.js.map' files`, () => {
60-
expect(glob.sync(`${DIST}/esm5/secondary/**/*.js.map`).length).equal(8);
59+
it(`should contain 0 '.js.map' files`, () => {
60+
expect(glob.sync(`${DIST}/esm5/secondary/**/*.js.map`).length).equal(0);
6161
});
6262

6363
it(`should contain 8 '.js' files`, () => {
@@ -67,17 +67,17 @@ describe('@sample/apf', () => {
6767
});
6868

6969
describe('ESM2015', () => {
70-
it(`should contain 16 '.js.map' files`, () => {
71-
expect(glob.sync(`${DIST}/esm2015/**/*.js.map`).length).equal(16);
70+
it(`should contain 0 '.js.map' files`, () => {
71+
expect(glob.sync(`${DIST}/esm2015/**/*.js.map`).length).equal(0);
7272
});
7373

7474
it(`should contain 16 '.js' files`, () => {
7575
expect(glob.sync(`${DIST}/esm2015/**/*.js`).length).equal(16);
7676
});
7777

7878
describe('secondary', () => {
79-
it(`should contain 8 '.js.map' files`, () => {
80-
expect(glob.sync(`${DIST}/esm2015/secondary/**/*.js.map`).length).equal(8);
79+
it(`should contain 0 '.js.map' files`, () => {
80+
expect(glob.sync(`${DIST}/esm2015/secondary/**/*.js.map`).length).equal(0);
8181
});
8282

8383
it(`should contain 8 '.js' files`, () => {

integration/samples/api/tsconfig.ngc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"moduleResolution": "node",
1717
"outDir": "",
1818
"declaration": true,
19-
"sourceMap": true,
19+
"inlineSourceMap": true,
2020
"inlineSources": true,
2121
"skipLibCheck": true,
2222
"emitDecoratorMetadata": true,

integration/samples/core/specs/sourcemaps.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as fs from 'fs-extra';
33
import * as path from 'path';
44

55
describe(`@sample/core`, () => {
6-
describe(`esm5/sample-core.js.map`, () => {
6+
describe(`fesm5/sample-core.js.map`, () => {
77
let sourceMap;
88
before(() => {
99
sourceMap = fs.readJsonSync(path.resolve(__dirname, '../dist/fesm5/sample-core.js.map'));
@@ -20,8 +20,33 @@ describe(`@sample/core`, () => {
2020
});
2121

2222
it(`should reference each 'sources' path with a common prefix`, () => {
23-
const everyUeveryMe = (sourceMap.sources as string[]).every(fileName => fileName.startsWith(`ng://@sample/core`));
23+
const everyUeveryMe = (sourceMap.sources as string[]).every(
24+
fileName => fileName.startsWith('ng://@sample/core') && fileName.endsWith('.ts')
25+
);
26+
expect(everyUeveryMe).to.be.true;
27+
});
28+
});
29+
30+
describe(`bundles/sample-core.umd.min.js.map`, () => {
31+
let sourceMap;
32+
before(() => {
33+
sourceMap = fs.readJsonSync(path.resolve(__dirname, '../dist/bundles/sample-core.umd.min.js.map'));
34+
});
35+
36+
it(`should exist`, () => {
37+
expect(sourceMap).to.be.ok;
38+
});
2439

40+
it(`should have 'sources' and 'sourcesContent' property`, () => {
41+
expect(sourceMap.sources).to.be.an('array').that.is.not.empty;
42+
expect(sourceMap.sourcesContent).to.be.an('array').that.is.not.empty;
43+
expect(sourceMap.sources).to.have.lengthOf(sourceMap.sourcesContent.length);
44+
});
45+
46+
it(`should reference each 'sources' path with a common prefix`, () => {
47+
const everyUeveryMe = (sourceMap.sources as string[]).every(
48+
fileName => fileName.startsWith('ng://@sample/core') && fileName.endsWith('.ts')
49+
);
2550
expect(everyUeveryMe).to.be.true;
2651
});
2752
});

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"rollup-plugin-commonjs": "^9.1.3",
4949
"rollup-plugin-node-resolve": "^3.0.0",
5050
"rxjs": "^6.0.0",
51-
"sorcery": "^0.10.0",
51+
"rollup-plugin-sourcemaps": "^0.4.2",
5252
"strip-bom": "^3.0.0",
5353
"stylus": "^0.54.5",
5454
"uglify-js": "^3.0.7",

src/lib/ts/downlevel-transformer.ts renamed to src/lib/flatten/downlevel-transformer.ts

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,6 @@ const COMPILER_OPTIONS: CompilerOptions = {
2626
moduleResolution: ModuleResolutionKind.NodeJs
2727
};
2828

29-
/**
30-
* Downlevels a .js file from `ES2015` to `ES5`. Internally, uses `tsc`.
31-
*
32-
*/
33-
export function downlevelEmitWithTsc(entryPoint: string, outDir: string): Promise<void> {
34-
log.debug(`tsc downlevel ${entryPoint}`);
35-
36-
const compilerOptions: CompilerOptions = {
37-
...COMPILER_OPTIONS,
38-
mapRoot: path.dirname(entryPoint),
39-
outDir
40-
};
41-
42-
const compilerHost = createCompilerHost(compilerOptions);
43-
const program = createProgram([entryPoint], compilerOptions, compilerHost);
44-
const emitResult = program.emit();
45-
46-
return emitResult.emitSkipped
47-
? Promise.reject(new Error(formatDiagnostics(emitResult.diagnostics, compilerHost)))
48-
: Promise.resolve();
49-
}
50-
5129
/**
5230
* Downlevels a .js file from `ES2015` to `ES5`. Internally, uses `tsc`.
5331
*

src/lib/flatten/flatten.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { rollupBundleFile } from './rollup';
22
import { minifyJsFile } from './uglify';
3-
import { downlevelCodeWithTsc } from '../ts/downlevel-transformer';
3+
import { downlevelCodeWithTsc } from './downlevel-transformer';
44
import { DependencyList } from './external-module-id-strategy';
55

66
export interface FlattenOpts {
@@ -14,6 +14,9 @@ export interface FlattenOpts {
1414
/** UMD ID defined by the UMD bundle. */
1515
umdModuleId: string;
1616

17+
/** Specifies the location where debugger should locate the sourcemaps */
18+
sourceRoot: string;
19+
1720
/** AMD ID defined in the UMD bundle. */
1821
amdId?: string;
1922

@@ -27,21 +30,23 @@ export interface FlattenOpts {
2730
dependencyList: DependencyList;
2831
}
2932

30-
export async function flattenToFesm(opts: FlattenOpts): Promise<void> {
33+
export async function flattenToFesm(opts: FlattenOpts): Promise<void[]> {
3134
return rollupBundleFile({
3235
moduleName: opts.esmModuleId,
3336
entry: opts.entryFile,
37+
sourceRoot: opts.sourceRoot,
3438
format: 'es',
3539
dest: opts.destFile,
3640
dependencyList: opts.dependencyList
3741
});
3842
}
3943

40-
export async function flattenToUmd(opts: FlattenOpts): Promise<void> {
44+
export async function flattenToUmd(opts: FlattenOpts): Promise<void[]> {
4145
return rollupBundleFile({
4246
transform: downlevelCodeWithTsc,
4347
moduleName: opts.umdModuleId,
4448
entry: opts.entryFile,
49+
sourceRoot: opts.sourceRoot,
4550
format: 'umd',
4651
dest: opts.destFile,
4752
amd: { id: opts.amdId },

src/lib/flatten/rollup.ts

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import * as rollup from 'rollup';
22
import * as nodeResolve from 'rollup-plugin-node-resolve';
3+
import * as sourcemaps from 'rollup-plugin-sourcemaps';
34
import * as commonJs from 'rollup-plugin-commonjs';
5+
import * as path from 'path';
46
import * as log from '../util/log';
57
import { ExternalModuleIdStrategy, DependencyList } from './external-module-id-strategy';
68
import { umdModuleIdStrategy } from './umd-module-id-strategy';
79
import { TransformHook } from 'rollup';
10+
import { outputFile, outputJson } from 'fs-extra';
811

912
/**
1013
* Options used in `ng-packagr` for writing flat bundle files.
@@ -16,14 +19,15 @@ export interface RollupOptions {
1619
entry: string;
1720
format: rollup.ModuleFormat;
1821
dest: string;
22+
sourceRoot: string;
1923
umdModuleIds?: { [key: string]: string };
2024
amd?: { id: string };
2125
transform?: TransformHook;
2226
dependencyList?: DependencyList;
2327
}
2428

2529
/** Runs rollup over the given entry file, writes a bundle file. */
26-
export async function rollupBundleFile(opts: RollupOptions): Promise<void> {
30+
export async function rollupBundleFile(opts: RollupOptions): Promise<void[]> {
2731
log.debug(`rollup (v${rollup.VERSION}) ${opts.entry} to ${opts.dest} (${opts.format})`);
2832

2933
const externalModuleIdStrategy = new ExternalModuleIdStrategy(opts.format, opts.dependencyList);
@@ -33,7 +37,7 @@ export async function rollupBundleFile(opts: RollupOptions): Promise<void> {
3337
context: 'this',
3438
external: moduleId => externalModuleIdStrategy.isExternalDependency(moduleId),
3539
input: opts.entry,
36-
plugins: [nodeResolve(), commonJs(), { transform: opts.transform }],
40+
plugins: [nodeResolve(), commonJs(), sourcemaps(), { transform: opts.transform }],
3741
onwarn: warning => {
3842
if (typeof warning === 'string') {
3943
log.warn(warning);
@@ -49,13 +53,36 @@ export async function rollupBundleFile(opts: RollupOptions): Promise<void> {
4953
});
5054

5155
// Output the bundle to disk
52-
await bundle.write({
53-
name: `${opts.moduleName}`,
54-
file: opts.dest,
56+
const sourcemapFullFile = `${opts.dest}.map`;
57+
const sourcemapFile = path.basename(sourcemapFullFile);
58+
const result = await bundle.generate({
59+
name: opts.moduleName,
5560
format: opts.format,
5661
amd: opts.amd,
62+
file: opts.dest,
5763
banner: '',
5864
globals: moduleId => umdModuleIdStrategy(moduleId, opts.umdModuleIds || {}),
59-
sourcemap: true
65+
sourcemap: true,
66+
sourcemapFile
67+
});
68+
69+
// relocate sourcemaps
70+
result.map.sources = result.map.sources.map(sourcePath => {
71+
if (!sourcePath) {
72+
return sourcePath;
73+
}
74+
75+
// the replace here is because during the compilation one of the `/` gets lost sometimes
76+
const mapRootUrl = opts.sourceRoot.replace('//', '/');
77+
if (sourcePath.indexOf(mapRootUrl) > 0) {
78+
return `${opts.sourceRoot}${sourcePath.substr(sourcePath.indexOf(mapRootUrl) + mapRootUrl.length)}`;
79+
} else if (sourcePath.indexOf(opts.sourceRoot) > 0) {
80+
return sourcePath.substr(sourcePath.indexOf(mapRootUrl));
81+
}
6082
});
83+
84+
// rollup doesn't add a sourceMappingURL
85+
// https://github.com/rollup/rollup/issues/121
86+
result.code = `${result.code}\n//# sourceMappingURL=${result.map.toUrl()}`;
87+
return Promise.all([outputJson(sourcemapFullFile, result.map), outputFile(opts.dest, result.code)]);
6188
}

src/lib/ng-v5/entry-point.di.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,9 @@ import { STYLESHEET_TRANSFORM, STYLESHEET_TRANSFORM_TOKEN } from './entry-point/
55
import { TEMPLATE_TRANSFORM, TEMPLATE_TRANSFORM_TOKEN } from './entry-point/resources/template.di';
66
import { COMPILE_NGC_TOKEN, COMPILE_NGC_TRANSFORM } from './entry-point/ts/compile-ngc.di';
77
import { TRANSFORM_SOURCES_TOKEN, TRANSFORM_SOURCES_TRANSFORM } from './entry-point/ts/transform-sources.di';
8-
import {
9-
RELOCATE_SOURCE_MAPS_TRANSFORM,
10-
RELOCATE_SOURCE_MAPS_TRANSFORM_TOKEN
11-
} from './entry-point/relocate-source-maps.di';
128
import { WRITE_BUNDLES_TRANSFORM, WRITE_BUNDLES_TRANSFORM_TOKEN } from './entry-point/write-bundles.di';
139
import { WRITE_PACKAGE_TRANSFORM, WRITE_PACKAGE_TRANSFORM_TOKEN } from './entry-point/write-package.di';
1410
import { entryPointTransformFactory } from './entry-point.transform';
15-
import {
16-
DOWNLEVEL_COMPILATION_TRANSFORM,
17-
DOWNLEVEL_COMPILATION_TOKEN
18-
} from './entry-point/ts/downlevel-compilation.di';
19-
import { REMAP_SOURCE_MAPS_TRANSFORM_TOKEN, REMAP_SOURCE_MAPS_TRANSFORM } from './entry-point/remap-source-maps.di';
2011

2112
export const ENTRY_POINT_TRANSFORM_TOKEN = new InjectionToken<Transform>(`ng.v5.entryPointTransform`);
2213

@@ -28,10 +19,7 @@ export const ENTRY_POINT_TRANSFORM: TransformProvider = provideTransform({
2819
TEMPLATE_TRANSFORM_TOKEN,
2920
TRANSFORM_SOURCES_TOKEN,
3021
COMPILE_NGC_TOKEN,
31-
DOWNLEVEL_COMPILATION_TOKEN,
3222
WRITE_BUNDLES_TRANSFORM_TOKEN,
33-
REMAP_SOURCE_MAPS_TRANSFORM_TOKEN,
34-
RELOCATE_SOURCE_MAPS_TRANSFORM_TOKEN,
3523
WRITE_PACKAGE_TRANSFORM_TOKEN
3624
]
3725
});
@@ -42,9 +30,6 @@ export const ENTRY_POINT_PROVIDERS: Provider[] = [
4230
TEMPLATE_TRANSFORM,
4331
TRANSFORM_SOURCES_TRANSFORM,
4432
COMPILE_NGC_TRANSFORM,
45-
DOWNLEVEL_COMPILATION_TRANSFORM,
46-
REMAP_SOURCE_MAPS_TRANSFORM,
47-
RELOCATE_SOURCE_MAPS_TRANSFORM,
4833
WRITE_BUNDLES_TRANSFORM,
4934
WRITE_PACKAGE_TRANSFORM
5035
];

src/lib/ng-v5/entry-point.transform.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,15 @@ import { byEntryPoint } from './nodes';
3636
* @param renderStylesheets Transformation rendering xCSS stylesheets.
3737
* @param transformTsSources Transformation manipulating the typescript source files (thus inlining template and stylesheet data).
3838
* @param compileTs Transformation compiling typescript sources to ES2015 modules.
39-
* @param downlevelTs Transformation downlevel compilation from ES2015 TO ESM5.
4039
* @param writeBundles Transformation flattening ES2015 modules to ESM2015, ESM5, UMD, and minified UMD.
41-
* @param remapSourceMaps Transformation re-mapping of sourcemaps over a series of transpilations.
42-
* @param relocateSourceMaps Transformation re-locating (adapting) paths in the source maps.
4340
* @param writePackage Transformation writing a distribution-ready `package.json` (for publishing to npm registry).
4441
*/
4542
export const entryPointTransformFactory = (
4643
renderStylesheets: Transform,
4744
renderTemplates: Transform,
4845
transformTsSources: Transform,
4946
compileTs: Transform,
50-
downlevelTs: Transform,
5147
writeBundles: Transform,
52-
remapSourceMaps: Transform,
53-
relocateSourceMaps: Transform,
5448
writePackage: Transform
5549
): Transform =>
5650
pipe(
@@ -68,11 +62,9 @@ export const entryPointTransformFactory = (
6862
transformTsSources,
6963
// TypeScript sources compilation
7064
compileTs,
71-
// Downlevel es2015 to es5
72-
downlevelTs,
7365
// After TypeScript: bundling and write package
74-
pipe(writeBundles, remapSourceMaps, relocateSourceMaps, writePackage),
75-
66+
writeBundles,
67+
writePackage,
7668
transformFromPromise(async graph => {
7769
const entryPoint = graph.find(byEntryPoint().and(isInProgress));
7870
entryPoint.state = STATE_DONE;

0 commit comments

Comments
 (0)