@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.
Files changed (40) hide show
  1. package/package.json +33 -32
  2. package/src/app-shell/index.js +3 -5
  3. package/src/babel/plugins/adjust-static-class-members.js +22 -1
  4. package/src/babel/presets/application.d.ts +0 -1
  5. package/src/babel/presets/application.js +3 -2
  6. package/src/babel/webpack-loader.js +0 -9
  7. package/src/browser/index.js +13 -3
  8. package/src/browser/schema.d.ts +1 -1
  9. package/src/browser/schema.json +1 -1
  10. package/src/dev-server/index.js +2 -2
  11. package/src/extract-i18n/index.js +1 -1
  12. package/src/extract-i18n/ivy-extract-loader.d.ts +6 -1
  13. package/src/extract-i18n/ivy-extract-loader.js +8 -12
  14. package/src/karma/index.js +1 -1
  15. package/src/server/index.js +1 -1
  16. package/src/server/tests/setup.d.ts +18 -0
  17. package/src/server/tests/setup.js +27 -0
  18. package/src/utils/action-executor.d.ts +3 -8
  19. package/src/utils/action-executor.js +19 -73
  20. package/src/utils/delete-output-dir.js +28 -2
  21. package/src/utils/index-file/inline-fonts.d.ts +3 -1
  22. package/src/utils/index-file/inline-fonts.js +112 -55
  23. package/src/utils/process-bundle.d.ts +0 -5
  24. package/src/utils/process-bundle.js +50 -140
  25. package/src/utils/version.d.ts +1 -2
  26. package/src/utils/version.js +5 -4
  27. package/src/webpack/configs/browser.js +0 -16
  28. package/src/webpack/configs/common.js +56 -67
  29. package/src/webpack/configs/server.js +0 -1
  30. package/src/webpack/configs/styles.js +92 -75
  31. package/src/webpack/plugins/builder-watch-plugin.d.ts +1 -26
  32. package/src/webpack/plugins/hmr/hmr-accept.js +1 -0
  33. package/src/webpack/plugins/javascript-optimizer-plugin.d.ts +59 -0
  34. package/src/webpack/plugins/javascript-optimizer-plugin.js +150 -0
  35. package/src/webpack/plugins/javascript-optimizer-worker.d.ts +37 -0
  36. package/src/webpack/plugins/javascript-optimizer-worker.js +74 -0
  37. package/src/webpack/plugins/postcss-cli-resources.d.ts +1 -1
  38. package/src/webpack/plugins/postcss-cli-resources.js +2 -1
  39. package/src/webpack/plugins/single-test-transform.d.ts +1 -1
  40. 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: any;
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 }).toString());
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: any, source: string): string;
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 } = loader_utils_1.getOptions(this);
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: