Skip to content

Commit 5cb8354

Browse files
filipesilvahansl
authored andcommitted
fix(@angular-devkit/build-optimizer): add ngfactories to known side-effect free modules
1 parent 7cfbb49 commit 5cb8354

File tree

4 files changed

+21
-64
lines changed

4 files changed

+21
-64
lines changed

packages/angular_devkit/build_optimizer/src/build-optimizer/build-optimizer.ts

+16-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { getScrubFileTransformer, testScrubFile } from '../transforms/scrub-file
1515
import { getWrapEnumsTransformer, testWrapEnums } from '../transforms/wrap-enums';
1616

1717

18+
// Angular packages are known to have no side effects.
1819
const whitelistedAngularModules = [
1920
/[\\/]node_modules[\\/]@angular[\\/]animations[\\/]/,
2021
/[\\/]node_modules[\\/]@angular[\\/]common[\\/]/,
@@ -41,6 +42,20 @@ const es5AngularModules = [
4142
/\.umd\.js$/,
4243
];
4344

45+
// Factories created by AOT are known to have no side effects and contain es5 code.
46+
// In Angular 2/4 the file path for factories can be `.ts`, but in Angular 5 it is `.js`.
47+
const ngFactories = [
48+
/\.ngfactory\.[jt]s/,
49+
/\.ngstyle\.[jt]s/,
50+
];
51+
52+
function isKnownSideEffectFree(filePath: string) {
53+
return ngFactories.some((re) => re.test(filePath)) || (
54+
whitelistedAngularModules.some((re) => re.test(filePath))
55+
&& es5AngularModules.some((re) => re.test(filePath))
56+
);
57+
}
58+
4459
export interface BuildOptimizerOptions {
4560
content?: string;
4661
inputFilePath?: string;
@@ -77,10 +92,7 @@ export function buildOptimizer(options: BuildOptimizerOptions): TransformJavascr
7792
getTransforms.push(getPrefixClassesTransformer);
7893
}
7994

80-
if (inputFilePath
81-
&& whitelistedAngularModules.some((re) => re.test(inputFilePath))
82-
&& es5AngularModules.some((re) => re.test(inputFilePath))
83-
) {
95+
if (inputFilePath && isKnownSideEffectFree(inputFilePath)) {
8496
getTransforms.push(
8597
// getPrefixFunctionsTransformer is rather dangerous, apply only to known pure es5 modules.
8698
// It will mark both `require()` calls and `console.log(stuff)` as pure.

packages/angular_devkit/build_optimizer/src/build-optimizer/build-optimizer_spec.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ describe('build-optimizer', () => {
1717
const decorators = 'Clazz.decorators = [ { type: Injectable } ];';
1818

1919
describe('basic functionality', () => {
20-
it('applies class-fold, scrub-file and prefix-functions to whitelisted es5 modules', () => {
20+
fit('applies class-fold, scrub-file and prefix-functions to side-effect free modules', () => {
2121
const input = tags.stripIndent`
2222
${imports}
2323
var __extends = (this && this.__extends) || function (d, b) {
@@ -51,6 +51,7 @@ describe('build-optimizer', () => {
5151
], ComponentClazz);
5252
return ComponentClazz;
5353
}());
54+
var RenderType_MdOption = ɵcrt({ encapsulation: 2, styles: styles_MdOption});
5455
`;
5556
// tslint:disable:max-line-length
5657
const output = tags.oneLine`
@@ -68,6 +69,7 @@ describe('build-optimizer', () => {
6869
function ComponentClazz() { }
6970
return ComponentClazz;
7071
}());
72+
var RenderType_MdOption = /*@__PURE__*/ ɵcrt({ encapsulation: 2, styles: styles_MdOption });
7173
`;
7274

7375
// Check Angular 4/5 and unix/windows paths.
@@ -76,6 +78,8 @@ describe('build-optimizer', () => {
7678
'/node_modules/@angular/core/esm5/core.js',
7779
'\\node_modules\\@angular\\core\\@angular\\core.es5.js',
7880
'\\node_modules\\@angular\\core\\esm5\\core.js',
81+
'/project/file.ngfactory.js',
82+
'/project/file.ngstyle.js',
7983
];
8084

8185
inputPaths.forEach((inputFilePath) => {

packages/angular_devkit/build_optimizer/src/purify/purify.ts

-22
Original file line numberDiff line numberDiff line change
@@ -53,28 +53,6 @@ export function purifyReplacements(content: string) {
5353
},
5454
);
5555

56-
/* Prefix CCF and CMF statements */
57-
content.replace(
58-
/\w*__WEBPACK_IMPORTED_MODULE_\d+__angular_core__\["\w+" \/\* (ɵccf|ɵcmf|ɵcrt) \*\/\]\(/mg,
59-
(match, _p1, offset) => {
60-
const newContent = `/*@__PURE__*/${match}`;
61-
addReplacement(offset, match.length, newContent);
62-
63-
return newContent;
64-
},
65-
);
66-
67-
/* Prefix module statements */
68-
content.replace(
69-
/new \w*__WEBPACK_IMPORTED_MODULE_\d+__angular_core__\["\w+" \/\* NgModuleFactory \*\/\]/mg,
70-
(match, offset) => {
71-
const newContent = `/*@__PURE__*/${match}`;
72-
addReplacement(offset, match.length, newContent);
73-
74-
return newContent;
75-
},
76-
);
77-
7856
return replacements;
7957
}
8058

packages/angular_devkit/build_optimizer/src/purify/purify_spec.ts

-37
Original file line numberDiff line numberDiff line change
@@ -41,41 +41,4 @@ describe('purify', () => {
4141

4242
expect(tags.oneLine`${purify(input)}`).toEqual(tags.oneLine`${output}`);
4343
});
44-
45-
it('prefix createComponentFactory and createNgModuleFactory function calls', () => {
46-
const input = tags.stripIndent`
47-
var AppComponentNgFactory = __WEBPACK_IMPORTED_MODULE_1__angular_core__["I" /* ɵccf */]('app-root');
48-
var AppModuleNgFactory = __WEBPACK_IMPORTED_MODULE_1__angular_core__["I" /* ɵcmf */]('app-root');
49-
var SelectComponentNgFactory = select_component_ngfactory___WEBPACK_IMPORTED_MODULE_0__angular_core__["U" /* ɵccf */]('aio-select');
50-
`;
51-
const output = tags.stripIndent`
52-
var AppComponentNgFactory = /*@__PURE__*/__WEBPACK_IMPORTED_MODULE_1__angular_core__["I" /* ɵccf */]('app-root');
53-
var AppModuleNgFactory = /*@__PURE__*/__WEBPACK_IMPORTED_MODULE_1__angular_core__["I" /* ɵcmf */]('app-root');
54-
var SelectComponentNgFactory = /*@__PURE__*/select_component_ngfactory___WEBPACK_IMPORTED_MODULE_0__angular_core__["U" /* ɵccf */]('aio-select');
55-
`;
56-
57-
expect(tags.oneLine`${purify(input)}`).toEqual(tags.oneLine`${output}`);
58-
});
59-
60-
it('should prefix createRendererType2 function calls', () => {
61-
const input = tags.stripIndent`
62-
var RenderType_MdOption = index_ngfactory___WEBPACK_IMPORTED_MODULE_0__angular_core__["W" /* ɵcrt */]({ encapsulation: 2, styles: styles_MdOption});
63-
`;
64-
const output = tags.stripIndent`
65-
var RenderType_MdOption = /*@__PURE__*/index_ngfactory___WEBPACK_IMPORTED_MODULE_0__angular_core__["W" /* ɵcrt */]({ encapsulation: 2, styles: styles_MdOption});
66-
`;
67-
68-
expect(tags.oneLine`${purify(input)}`).toEqual(tags.oneLine`${output}`);
69-
});
70-
71-
it('prefix module statements', () => {
72-
const input = tags.stripIndent`
73-
var AppModuleNgFactory = new __WEBPACK_IMPORTED_MODULE_1__angular_core__["I" /* NgModuleFactory */];
74-
`;
75-
const output = tags.stripIndent`
76-
var AppModuleNgFactory = /*@__PURE__*/new __WEBPACK_IMPORTED_MODULE_1__angular_core__["I" /* NgModuleFactory */];
77-
`;
78-
79-
expect(tags.oneLine`${purify(input)}`).toEqual(tags.oneLine`${output}`);
80-
});
8144
});

0 commit comments

Comments
 (0)