forked from angular/angular-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild-optimizer.ts
142 lines (122 loc) · 4.92 KB
/
build-optimizer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/**
* @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 { readFileSync } from 'fs';
import {
TransformJavascriptOptions,
TransformJavascriptOutput,
transformJavascript,
} from '../helpers/transform-javascript';
import { getFoldFileTransformer } from '../transforms/class-fold';
import { getImportTslibTransformer, testImportTslib } from '../transforms/import-tslib';
import { getPrefixClassesTransformer, testPrefixClasses } from '../transforms/prefix-classes';
import { getPrefixFunctionsTransformer } from '../transforms/prefix-functions';
import { getScrubFileTransformer, testScrubFile } from '../transforms/scrub-file';
import { getWrapEnumsTransformer } from '../transforms/wrap-enums';
// Angular packages are known to have no side effects.
const whitelistedAngularModules = [
/[\\/]node_modules[\\/]@angular[\\/]animations[\\/]/,
/[\\/]node_modules[\\/]@angular[\\/]common[\\/]/,
/[\\/]node_modules[\\/]@angular[\\/]compiler[\\/]/,
/[\\/]node_modules[\\/]@angular[\\/]core[\\/]/,
/[\\/]node_modules[\\/]@angular[\\/]forms[\\/]/,
/[\\/]node_modules[\\/]@angular[\\/]http[\\/]/,
/[\\/]node_modules[\\/]@angular[\\/]platform-browser-dynamic[\\/]/,
/[\\/]node_modules[\\/]@angular[\\/]platform-browser[\\/]/,
/[\\/]node_modules[\\/]@angular[\\/]platform-webworker-dynamic[\\/]/,
/[\\/]node_modules[\\/]@angular[\\/]platform-webworker[\\/]/,
/[\\/]node_modules[\\/]@angular[\\/]router[\\/]/,
/[\\/]node_modules[\\/]@angular[\\/]upgrade[\\/]/,
/[\\/]node_modules[\\/]@angular[\\/]material[\\/]/,
/[\\/]node_modules[\\/]@angular[\\/]cdk[\\/]/,
];
// Factories created by AOT are known to have no side effects.
// In Angular 2/4 the file path for factories can be `.ts`, but in Angular 5 it is `.js`.
const ngFactories = [
/\.ngfactory\.[jt]s/,
/\.ngstyle\.[jt]s/,
];
function isKnownSideEffectFree(filePath: string) {
return ngFactories.some((re) => re.test(filePath)) ||
whitelistedAngularModules.some((re) => re.test(filePath));
}
export interface BuildOptimizerOptions {
content?: string;
originalFilePath?: string;
inputFilePath?: string;
outputFilePath?: string;
emitSourceMap?: boolean;
strict?: boolean;
isSideEffectFree?: boolean;
}
export function buildOptimizer(options: BuildOptimizerOptions): TransformJavascriptOutput {
const { inputFilePath } = options;
let { originalFilePath, content } = options;
if (!originalFilePath && inputFilePath) {
originalFilePath = inputFilePath;
}
if (!inputFilePath && content === undefined) {
throw new Error('Either filePath or content must be specified in options.');
}
if (content === undefined) {
content = readFileSync(inputFilePath as string, 'UTF-8');
}
if (!content) {
return {
content: null,
sourceMap: null,
emitSkipped: true,
};
}
const isWebpackBundle = content.indexOf('__webpack_require__') !== -1;
// Determine which transforms to apply.
const getTransforms = [];
let typeCheck = false;
if (options.isSideEffectFree || originalFilePath && isKnownSideEffectFree(originalFilePath)) {
getTransforms.push(
// getPrefixFunctionsTransformer is rather dangerous, apply only to known pure es5 modules.
// It will mark both `require()` calls and `console.log(stuff)` as pure.
// We only apply it to whitelisted modules, since we know they are safe.
// getPrefixFunctionsTransformer needs to be before getFoldFileTransformer.
getPrefixFunctionsTransformer,
getScrubFileTransformer,
getFoldFileTransformer,
);
typeCheck = true;
} else if (testScrubFile(content)) {
// Always test as these require the type checker
getTransforms.push(
getScrubFileTransformer,
getFoldFileTransformer,
);
typeCheck = true;
}
// tests are not needed for fast path
// usage will be expanded once transformers are verified safe
const ignoreTest = !options.emitSourceMap && !typeCheck;
if (testPrefixClasses(content)) {
getTransforms.unshift(getPrefixClassesTransformer);
}
// This transform introduces import/require() calls, but this won't work properly on libraries
// built with Webpack. These libraries use __webpack_require__() calls instead, which will break
// with a new import that wasn't part of it's original module list.
// We ignore this transform for such libraries.
if (!isWebpackBundle && (ignoreTest || testImportTslib(content))) {
getTransforms.unshift(getImportTslibTransformer);
}
getTransforms.unshift(getWrapEnumsTransformer);
const transformJavascriptOpts: TransformJavascriptOptions = {
content: content,
inputFilePath: options.inputFilePath,
outputFilePath: options.outputFilePath,
emitSourceMap: options.emitSourceMap,
strict: options.strict,
getTransforms,
typeCheck,
};
return transformJavascript(transformJavascriptOpts);
}