Skip to content

Commit bcb41e3

Browse files
committed
fix(@angular-devkit/build-angular): wrap ES5 differential loading bundles
This change ensures that classic (ES5) script's top-level function helpers do not get overwritten by other scripts top-level functions that happen to have the same name. This is not an issue when using module script types because each module has its own scope.
1 parent f9cf7b9 commit bcb41e3

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

packages/angular_devkit/build_angular/src/browser/specs/differential_loading_spec.ts

+7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Architect } from '@angular-devkit/architect';
1010
import { PathFragment } from '@angular-devkit/core';
1111
import { browserBuild, createArchitect, host } from '../../test-utils';
1212

13+
// tslint:disable-next-line: no-big-function
1314
describe('Browser Builder with differential loading', () => {
1415
const target = { project: 'app', target: 'build' };
1516
let architect: Architect;
@@ -181,6 +182,12 @@ describe('Browser Builder with differential loading', () => {
181182
expect(await files['main-es2015.js']).toContain('const ');
182183
});
183184

185+
it('wraps ES5 scripts in an IIFE', async () => {
186+
const { files } = await browserBuild(architect, host, target, { optimization: false });
187+
expect(await files['main-es5.js']).toMatch(/^\(function \(\) \{/);
188+
expect(await files['main-es2015.js']).not.toMatch(/^\(function \(\) \{/);
189+
});
190+
184191
it('uses the right zone.js variant', async () => {
185192
const { files } = await browserBuild(architect, host, target, { optimization: false });
186193
expect(await files['polyfills-es5.js']).toContain('zone.js/dist/zone-legacy');

packages/angular_devkit/build_angular/src/utils/process-bundle.ts

+34-1
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,10 @@ export async function process(options: ProcessBundleOptions): Promise<ProcessBun
157157
exclude: ['transform-typeof-symbol'],
158158
},
159159
]],
160-
plugins: options.replacements ? [createReplacePlugin(options.replacements)] : [],
160+
plugins: [
161+
createIifeWrapperPlugin(),
162+
...(options.replacements ? [createReplacePlugin(options.replacements)] : []),
163+
],
161164
minified: allowMinify && !!options.optimize,
162165
compact: !shouldBeautify && !!options.optimize,
163166
sourceMaps: !!sourceMap,
@@ -509,6 +512,36 @@ function createReplacePlugin(replacements: [string, string][]): PluginObj {
509512
};
510513
}
511514

515+
function createIifeWrapperPlugin(): PluginObj {
516+
return {
517+
visitor: {
518+
Program: {
519+
exit(path: NodePath<types.Program>) {
520+
// Save existing body and directives
521+
const { body, directives } = path.node;
522+
523+
// Clear out body and directives for wrapper
524+
path.node.body = [];
525+
path.node.directives = [];
526+
527+
// Create the wrapper - "(function() { ... })();"
528+
const wrapper = types.expressionStatement(
529+
types.callExpression(
530+
types.parenthesizedExpression(
531+
types.functionExpression(undefined, [], types.blockStatement(body, directives)),
532+
),
533+
[],
534+
),
535+
);
536+
537+
// Insert the wrapper
538+
path.pushContainer('body', wrapper);
539+
},
540+
},
541+
},
542+
};
543+
}
544+
512545
const USE_LOCALIZE_PLUGINS = false;
513546

514547
export async function createI18nPlugins(

0 commit comments

Comments
 (0)