@angular-devkit/build-angular 12.2.0-next.0 → 12.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +33 -32
- package/src/app-shell/index.js +3 -5
- package/src/babel/plugins/adjust-static-class-members.js +22 -1
- package/src/babel/presets/application.d.ts +0 -1
- package/src/babel/presets/application.js +3 -2
- package/src/babel/webpack-loader.js +0 -9
- package/src/browser/index.js +13 -3
- package/src/browser/schema.d.ts +1 -1
- package/src/browser/schema.json +1 -1
- package/src/dev-server/index.js +2 -2
- package/src/extract-i18n/index.js +1 -1
- package/src/extract-i18n/ivy-extract-loader.d.ts +6 -1
- package/src/extract-i18n/ivy-extract-loader.js +8 -12
- package/src/karma/index.js +1 -1
- package/src/server/index.js +1 -1
- package/src/server/tests/setup.d.ts +18 -0
- package/src/server/tests/setup.js +27 -0
- package/src/utils/action-executor.d.ts +3 -8
- package/src/utils/action-executor.js +19 -73
- package/src/utils/delete-output-dir.js +28 -2
- package/src/utils/index-file/inline-fonts.d.ts +3 -1
- package/src/utils/index-file/inline-fonts.js +112 -55
- package/src/utils/process-bundle.d.ts +0 -5
- package/src/utils/process-bundle.js +50 -140
- package/src/utils/version.d.ts +1 -2
- package/src/utils/version.js +5 -4
- package/src/webpack/configs/browser.js +0 -16
- package/src/webpack/configs/common.js +56 -67
- package/src/webpack/configs/server.js +0 -1
- package/src/webpack/configs/styles.js +92 -75
- package/src/webpack/plugins/builder-watch-plugin.d.ts +1 -26
- package/src/webpack/plugins/hmr/hmr-accept.js +1 -0
- package/src/webpack/plugins/javascript-optimizer-plugin.d.ts +59 -0
- package/src/webpack/plugins/javascript-optimizer-plugin.js +150 -0
- package/src/webpack/plugins/javascript-optimizer-worker.d.ts +37 -0
- package/src/webpack/plugins/javascript-optimizer-worker.js +74 -0
- package/src/webpack/plugins/postcss-cli-resources.d.ts +1 -1
- package/src/webpack/plugins/postcss-cli-resources.js +2 -1
- package/src/webpack/plugins/single-test-transform.d.ts +1 -1
- package/src/webpack/plugins/single-test-transform.js +1 -2
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright Google LLC All Rights Reserved.
|
|
5
|
+
*
|
|
6
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
7
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8
|
+
*/
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.JavaScriptOptimizerPlugin = void 0;
|
|
14
|
+
const piscina_1 = __importDefault(require("piscina"));
|
|
15
|
+
const typescript_1 = require("typescript");
|
|
16
|
+
const environment_options_1 = require("../../utils/environment-options");
|
|
17
|
+
/**
|
|
18
|
+
* The maximum number of Workers that will be created to execute optimize tasks.
|
|
19
|
+
*/
|
|
20
|
+
const MAX_OPTIMIZE_WORKERS = environment_options_1.maxWorkers;
|
|
21
|
+
/**
|
|
22
|
+
* The name of the plugin provided to Webpack when tapping Webpack compiler hooks.
|
|
23
|
+
*/
|
|
24
|
+
const PLUGIN_NAME = 'angular-javascript-optimizer';
|
|
25
|
+
/**
|
|
26
|
+
* A Webpack plugin that provides JavaScript optimization capabilities.
|
|
27
|
+
*
|
|
28
|
+
* The plugin uses both `esbuild` and `terser` to provide both fast and highly-optimized
|
|
29
|
+
* code output. `esbuild` is used as an initial pass to remove the majority of unused code
|
|
30
|
+
* as well as shorten identifiers. `terser` is then used as a secondary pass to apply
|
|
31
|
+
* optimizations not yet implemented by `esbuild`.
|
|
32
|
+
*/
|
|
33
|
+
class JavaScriptOptimizerPlugin {
|
|
34
|
+
constructor(options = {}) {
|
|
35
|
+
this.options = options;
|
|
36
|
+
}
|
|
37
|
+
apply(compiler) {
|
|
38
|
+
const { OriginalSource, SourceMapSource } = compiler.webpack.sources;
|
|
39
|
+
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
|
|
40
|
+
compilation.hooks.processAssets.tapPromise({
|
|
41
|
+
name: PLUGIN_NAME,
|
|
42
|
+
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,
|
|
43
|
+
}, async (compilationAssets) => {
|
|
44
|
+
const scriptsToOptimize = [];
|
|
45
|
+
const cache = compilation.options.cache && compilation.getCache('JavaScriptOptimizerPlugin');
|
|
46
|
+
// Analyze the compilation assets for scripts that require optimization
|
|
47
|
+
for (const assetName of Object.keys(compilationAssets)) {
|
|
48
|
+
if (!assetName.endsWith('.js')) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const scriptAsset = compilation.getAsset(assetName);
|
|
52
|
+
if (scriptAsset && !scriptAsset.info.minimized) {
|
|
53
|
+
const { source: scriptAssetSource, name } = scriptAsset;
|
|
54
|
+
let cacheItem;
|
|
55
|
+
if (cache) {
|
|
56
|
+
const eTag = cache.getLazyHashedEtag(scriptAssetSource);
|
|
57
|
+
cacheItem = cache.getItemCache(name, eTag);
|
|
58
|
+
const cachedOutput = await cacheItem.getPromise();
|
|
59
|
+
if (cachedOutput) {
|
|
60
|
+
compilation.updateAsset(name, cachedOutput.source, {
|
|
61
|
+
minimized: true,
|
|
62
|
+
});
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const { source, map } = scriptAssetSource.sourceAndMap();
|
|
67
|
+
scriptsToOptimize.push({
|
|
68
|
+
name: scriptAsset.name,
|
|
69
|
+
code: typeof source === 'string' ? source : source.toString(),
|
|
70
|
+
map,
|
|
71
|
+
cacheItem,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (scriptsToOptimize.length === 0) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// Ensure all replacement values are strings which is the expected type for esbuild
|
|
79
|
+
let define;
|
|
80
|
+
if (this.options.define) {
|
|
81
|
+
define = {};
|
|
82
|
+
for (const [key, value] of Object.entries(this.options.define)) {
|
|
83
|
+
define[key] = String(value);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
let target = 2017;
|
|
87
|
+
if (this.options.target) {
|
|
88
|
+
if (this.options.target <= typescript_1.ScriptTarget.ES5) {
|
|
89
|
+
target = 5;
|
|
90
|
+
}
|
|
91
|
+
else if (this.options.target < typescript_1.ScriptTarget.ESNext) {
|
|
92
|
+
target = Number(typescript_1.ScriptTarget[this.options.target].slice(2));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
target = 2020;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Setup the options used by all worker tasks
|
|
99
|
+
const optimizeOptions = {
|
|
100
|
+
sourcemap: this.options.sourcemap,
|
|
101
|
+
define,
|
|
102
|
+
keepNames: this.options.keepNames,
|
|
103
|
+
target,
|
|
104
|
+
removeLicenses: this.options.removeLicenses,
|
|
105
|
+
advanced: this.options.advanced,
|
|
106
|
+
};
|
|
107
|
+
// Sort scripts so larger scripts start first - worker pool uses a FIFO queue
|
|
108
|
+
scriptsToOptimize.sort((a, b) => a.code.length - b.code.length);
|
|
109
|
+
// Initialize the task worker pool
|
|
110
|
+
const workerPath = require.resolve('./javascript-optimizer-worker');
|
|
111
|
+
const workerPool = new piscina_1.default({
|
|
112
|
+
filename: workerPath,
|
|
113
|
+
maxThreads: MAX_OPTIMIZE_WORKERS,
|
|
114
|
+
});
|
|
115
|
+
// Enqueue script optimization tasks and update compilation assets as the tasks complete
|
|
116
|
+
try {
|
|
117
|
+
const tasks = [];
|
|
118
|
+
for (const { name, code, map, cacheItem } of scriptsToOptimize) {
|
|
119
|
+
tasks.push(workerPool
|
|
120
|
+
.run({
|
|
121
|
+
asset: {
|
|
122
|
+
name,
|
|
123
|
+
code,
|
|
124
|
+
map,
|
|
125
|
+
},
|
|
126
|
+
options: optimizeOptions,
|
|
127
|
+
})
|
|
128
|
+
.then(({ code, name, map }) => {
|
|
129
|
+
const optimizedAsset = map
|
|
130
|
+
? new SourceMapSource(code, name, map)
|
|
131
|
+
: new OriginalSource(code, name);
|
|
132
|
+
compilation.updateAsset(name, optimizedAsset, { minimized: true });
|
|
133
|
+
return cacheItem === null || cacheItem === void 0 ? void 0 : cacheItem.storePromise({
|
|
134
|
+
source: optimizedAsset,
|
|
135
|
+
});
|
|
136
|
+
}, (error) => {
|
|
137
|
+
const optimizationError = new compiler.webpack.WebpackError(`Optimization error [${name}]: ${error.stack || error.message}`);
|
|
138
|
+
compilation.errors.push(optimizationError);
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
await Promise.all(tasks);
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
void workerPool.destroy();
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exports.JavaScriptOptimizerPlugin = JavaScriptOptimizerPlugin;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright Google LLC All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
6
|
+
* found in the LICENSE file at https://angular.io/license
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* A request to optimize JavaScript using the supplied options.
|
|
10
|
+
*/
|
|
11
|
+
interface OptimizeRequest {
|
|
12
|
+
/**
|
|
13
|
+
* The options to use when optimizing.
|
|
14
|
+
*/
|
|
15
|
+
options: {
|
|
16
|
+
advanced: boolean;
|
|
17
|
+
define?: Record<string, string>;
|
|
18
|
+
keepNames: boolean;
|
|
19
|
+
removeLicenses: boolean;
|
|
20
|
+
sourcemap: boolean;
|
|
21
|
+
target: 5 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* The JavaScript asset to optimize.
|
|
25
|
+
*/
|
|
26
|
+
asset: {
|
|
27
|
+
name: string;
|
|
28
|
+
code: string;
|
|
29
|
+
map: object;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export default function ({ asset, options }: OptimizeRequest): Promise<{
|
|
33
|
+
name: string;
|
|
34
|
+
code: string;
|
|
35
|
+
map: import("@ampproject/remapping/dist/types/source-map").default | undefined;
|
|
36
|
+
}>;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright Google LLC All Rights Reserved.
|
|
5
|
+
*
|
|
6
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
7
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8
|
+
*/
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
const remapping_1 = __importDefault(require("@ampproject/remapping"));
|
|
14
|
+
const esbuild_1 = require("esbuild");
|
|
15
|
+
const terser_1 = require("terser");
|
|
16
|
+
async function default_1({ asset, options }) {
|
|
17
|
+
// esbuild is used as a first pass
|
|
18
|
+
const esbuildResult = await esbuild_1.transform(asset.code, {
|
|
19
|
+
minifyIdentifiers: !options.keepNames,
|
|
20
|
+
minifySyntax: true,
|
|
21
|
+
// NOTE: Disabling whitespace ensures unused pure annotations are kept
|
|
22
|
+
minifyWhitespace: false,
|
|
23
|
+
pure: ['forwardRef'],
|
|
24
|
+
legalComments: options.removeLicenses ? 'none' : 'inline',
|
|
25
|
+
sourcefile: asset.name,
|
|
26
|
+
sourcemap: options.sourcemap && 'external',
|
|
27
|
+
define: options.define,
|
|
28
|
+
keepNames: options.keepNames,
|
|
29
|
+
target: `es${options.target}`,
|
|
30
|
+
});
|
|
31
|
+
// terser is used as a second pass
|
|
32
|
+
const terserResult = await optimizeWithTerser(asset.name, esbuildResult.code, options.sourcemap, options.target, options.advanced);
|
|
33
|
+
// Merge intermediate sourcemaps with input sourcemap if enabled
|
|
34
|
+
let fullSourcemap;
|
|
35
|
+
if (options.sourcemap) {
|
|
36
|
+
const partialSourcemaps = [];
|
|
37
|
+
if (esbuildResult.map) {
|
|
38
|
+
partialSourcemaps.unshift(JSON.parse(esbuildResult.map));
|
|
39
|
+
}
|
|
40
|
+
if (terserResult.map) {
|
|
41
|
+
partialSourcemaps.unshift(terserResult.map);
|
|
42
|
+
}
|
|
43
|
+
partialSourcemaps.push(asset.map);
|
|
44
|
+
fullSourcemap = remapping_1.default(partialSourcemaps, () => null);
|
|
45
|
+
}
|
|
46
|
+
return { name: asset.name, code: terserResult.code, map: fullSourcemap };
|
|
47
|
+
}
|
|
48
|
+
exports.default = default_1;
|
|
49
|
+
async function optimizeWithTerser(name, code, sourcemaps, target, advanced) {
|
|
50
|
+
const result = await terser_1.minify({ [name]: code }, {
|
|
51
|
+
compress: {
|
|
52
|
+
passes: advanced ? 2 : 1,
|
|
53
|
+
pure_getters: advanced,
|
|
54
|
+
},
|
|
55
|
+
ecma: target,
|
|
56
|
+
// esbuild in the first pass is used to minify identifiers instead of mangle here
|
|
57
|
+
mangle: false,
|
|
58
|
+
format: {
|
|
59
|
+
// ASCII output is enabled here as well to prevent terser from converting back to UTF-8
|
|
60
|
+
ascii_only: true,
|
|
61
|
+
wrap_func_args: false,
|
|
62
|
+
},
|
|
63
|
+
sourceMap: sourcemaps &&
|
|
64
|
+
{
|
|
65
|
+
asObject: true,
|
|
66
|
+
// typings don't include asObject option
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
if (!result.code) {
|
|
71
|
+
throw new Error('Terser failed for unknown reason.');
|
|
72
|
+
}
|
|
73
|
+
return { code: result.code, map: result.map };
|
|
74
|
+
}
|
|
@@ -14,7 +14,7 @@ export interface PostcssCliResourcesOptions {
|
|
|
14
14
|
/** CSS is extracted to a `.css` or is embedded in a `.js` file. */
|
|
15
15
|
extracted?: boolean;
|
|
16
16
|
filename: (resourcePath: string) => string;
|
|
17
|
-
loader:
|
|
17
|
+
loader: import('webpack').LoaderContext<unknown>;
|
|
18
18
|
emitFile: boolean;
|
|
19
19
|
}
|
|
20
20
|
export declare const postcss = true;
|
|
@@ -102,6 +102,7 @@ function default_1(options) {
|
|
|
102
102
|
}
|
|
103
103
|
loader.addDependency(result);
|
|
104
104
|
if (emitFile) {
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
105
106
|
loader.emitFile(outputPath, content, undefined, { sourceFilename: result });
|
|
106
107
|
}
|
|
107
108
|
let outputUrl = outputPath.replace(/\\/g, '/');
|
|
@@ -141,7 +142,7 @@ function default_1(options) {
|
|
|
141
142
|
processedUrl = await process(originalUrl, context, resourceCache);
|
|
142
143
|
}
|
|
143
144
|
catch (err) {
|
|
144
|
-
loader.emitError(decl.error(err.message, { word: originalUrl })
|
|
145
|
+
loader.emitError(decl.error(err.message, { word: originalUrl }));
|
|
145
146
|
continue;
|
|
146
147
|
}
|
|
147
148
|
if (lastIndex < match.index) {
|
|
@@ -24,4 +24,4 @@ export declare const SingleTestTransformLoader: string;
|
|
|
24
24
|
* Then it adds import statements for each file in the files options
|
|
25
25
|
* array to import them directly, and thus run the tests there.
|
|
26
26
|
*/
|
|
27
|
-
export default function loader(this:
|
|
27
|
+
export default function loader(this: import('webpack').LoaderContext<SingleTestTransformLoaderOptions>, source: string): string;
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.SingleTestTransformLoader = void 0;
|
|
11
11
|
const core_1 = require("@angular-devkit/core");
|
|
12
|
-
const loader_utils_1 = require("loader-utils");
|
|
13
12
|
const path_1 = require("path");
|
|
14
13
|
exports.SingleTestTransformLoader = __filename;
|
|
15
14
|
/**
|
|
@@ -27,7 +26,7 @@ exports.SingleTestTransformLoader = __filename;
|
|
|
27
26
|
*/
|
|
28
27
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
28
|
function loader(source) {
|
|
30
|
-
const { files = [], logger = console } =
|
|
29
|
+
const { files = [], logger = console } = this.getOptions();
|
|
31
30
|
// signal the user that expected content is not present.
|
|
32
31
|
if (!source.includes('require.context(')) {
|
|
33
32
|
logger.error(core_1.tags.stripIndent `The 'include' option requires that the 'main' file for tests includes the below line:
|