@angular-devkit/build-angular 15.0.0-next.4 → 15.0.0-next.6

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 (36) hide show
  1. package/package.json +20 -17
  2. package/src/builders/app-shell/index.js +39 -40
  3. package/src/builders/app-shell/render-worker.d.ts +36 -0
  4. package/src/builders/app-shell/render-worker.js +82 -0
  5. package/src/builders/browser/index.d.ts +2 -0
  6. package/src/builders/browser/index.js +38 -19
  7. package/src/builders/browser/schema.json +2 -2
  8. package/src/builders/browser-esbuild/compiler-plugin.d.ts +1 -0
  9. package/src/builders/browser-esbuild/compiler-plugin.js +127 -53
  10. package/src/builders/browser-esbuild/index.js +3 -2
  11. package/src/builders/browser-esbuild/profiling.d.ts +11 -0
  12. package/src/builders/browser-esbuild/profiling.js +64 -0
  13. package/src/builders/browser-esbuild/sass-plugin.js +11 -5
  14. package/src/builders/browser-esbuild/schema.json +2 -2
  15. package/src/builders/dev-server/index.d.ts +2 -0
  16. package/src/builders/dev-server/index.js +10 -7
  17. package/src/builders/karma/find-tests-plugin.js +1 -0
  18. package/src/builders/karma/index.d.ts +1 -1
  19. package/src/builders/karma/index.js +4 -5
  20. package/src/builders/server/schema.json +1 -1
  21. package/src/sass/sass-service.d.ts +12 -1
  22. package/src/sass/sass-service.js +19 -11
  23. package/src/utils/environment-options.d.ts +1 -0
  24. package/src/utils/environment-options.js +3 -1
  25. package/src/webpack/configs/common.js +29 -5
  26. package/src/webpack/configs/index.d.ts +0 -1
  27. package/src/webpack/configs/index.js +0 -1
  28. package/src/webpack/configs/styles.js +49 -25
  29. package/src/webpack/plugins/occurrences-plugin.d.ts +18 -0
  30. package/src/webpack/plugins/occurrences-plugin.js +79 -0
  31. package/src/webpack/utils/stats.d.ts +13 -8
  32. package/src/webpack/utils/stats.js +57 -6
  33. package/src/webpack/configs/analytics.d.ts +0 -11
  34. package/src/webpack/configs/analytics.js +0 -27
  35. package/src/webpack/plugins/analytics.d.ts +0 -66
  36. package/src/webpack/plugins/analytics.js +0 -236
@@ -8,9 +8,9 @@
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.SassWorkerImplementation = void 0;
11
- const path_1 = require("path");
12
- const url_1 = require("url");
13
- const worker_threads_1 = require("worker_threads");
11
+ const node_path_1 = require("node:path");
12
+ const node_url_1 = require("node:url");
13
+ const node_worker_threads_1 = require("node:worker_threads");
14
14
  const environment_options_1 = require("../utils/environment-options");
15
15
  /**
16
16
  * The maximum number of Workers that will be created to execute render requests.
@@ -27,7 +27,7 @@ class SassWorkerImplementation {
27
27
  this.workers = [];
28
28
  this.availableWorkers = [];
29
29
  this.requests = new Map();
30
- this.workerPath = (0, path_1.join)(__dirname, './worker.js');
30
+ this.workerPath = (0, node_path_1.join)(__dirname, './worker.js');
31
31
  this.idCounter = 1;
32
32
  this.nextWorkerIndex = 0;
33
33
  }
@@ -76,7 +76,7 @@ class SassWorkerImplementation {
76
76
  if (error) {
77
77
  const url = error === null || error === void 0 ? void 0 : error.span.url;
78
78
  if (url) {
79
- error.span.url = (0, url_1.pathToFileURL)(url);
79
+ error.span.url = (0, node_url_1.pathToFileURL)(url);
80
80
  }
81
81
  reject(error);
82
82
  return;
@@ -96,7 +96,7 @@ class SassWorkerImplementation {
96
96
  options: {
97
97
  ...serializableOptions,
98
98
  // URL is not serializable so to convert to string here and back to URL in the worker.
99
- url: url ? (0, url_1.fileURLToPath)(url) : undefined,
99
+ url: url ? (0, node_url_1.fileURLToPath)(url) : undefined,
100
100
  },
101
101
  });
102
102
  });
@@ -115,9 +115,9 @@ class SassWorkerImplementation {
115
115
  this.requests.clear();
116
116
  }
117
117
  createWorker() {
118
- const { port1: mainImporterPort, port2: workerImporterPort } = new worker_threads_1.MessageChannel();
118
+ const { port1: mainImporterPort, port2: workerImporterPort } = new node_worker_threads_1.MessageChannel();
119
119
  const importerSignal = new Int32Array(new SharedArrayBuffer(4));
120
- const worker = new worker_threads_1.Worker(this.workerPath, {
120
+ const worker = new node_worker_threads_1.Worker(this.workerPath, {
121
121
  workerData: { workerImporterPort, importerSignal },
122
122
  transferList: [workerImporterPort],
123
123
  });
@@ -132,7 +132,7 @@ class SassWorkerImplementation {
132
132
  request.callback(undefined, {
133
133
  ...response.result,
134
134
  // URL is not serializable so in the worker we convert to string and here back to URL.
135
- loadedUrls: response.result.loadedUrls.map((p) => (0, url_1.pathToFileURL)(p)),
135
+ loadedUrls: response.result.loadedUrls.map((p) => (0, node_url_1.pathToFileURL)(p)),
136
136
  });
137
137
  }
138
138
  else {
@@ -147,8 +147,16 @@ class SassWorkerImplementation {
147
147
  Atomics.notify(importerSignal, 0);
148
148
  return;
149
149
  }
150
- this.processImporters(request.importers, url, options)
150
+ this.processImporters(request.importers, url, {
151
+ ...options,
152
+ previousResolvedModules: request.previousResolvedModules,
153
+ })
151
154
  .then((result) => {
155
+ var _a;
156
+ if (result) {
157
+ (_a = request.previousResolvedModules) !== null && _a !== void 0 ? _a : (request.previousResolvedModules = new Set());
158
+ request.previousResolvedModules.add((0, node_path_1.dirname)(result));
159
+ }
152
160
  mainImporterPort.postMessage(result);
153
161
  })
154
162
  .catch((error) => {
@@ -171,7 +179,7 @@ class SassWorkerImplementation {
171
179
  // File importer (Can be sync or aync).
172
180
  const result = await importer.findFileUrl(url, options);
173
181
  if (result) {
174
- return (0, url_1.fileURLToPath)(result);
182
+ return (0, node_url_1.fileURLToPath)(result);
175
183
  }
176
184
  }
177
185
  return null;
@@ -10,3 +10,4 @@ export declare const shouldBeautify: boolean;
10
10
  export declare const allowMinify: boolean;
11
11
  export declare const maxWorkers: number;
12
12
  export declare const useLegacySass: boolean;
13
+ export declare const debugPerformance: boolean;
@@ -7,7 +7,7 @@
7
7
  * found in the LICENSE file at https://angular.io/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.useLegacySass = exports.maxWorkers = exports.allowMinify = exports.shouldBeautify = exports.allowMangle = void 0;
10
+ exports.debugPerformance = exports.useLegacySass = exports.maxWorkers = exports.allowMinify = exports.shouldBeautify = exports.allowMangle = void 0;
11
11
  const color_1 = require("./color");
12
12
  function isDisabled(variable) {
13
13
  return variable === '0' || variable.toLowerCase() === 'false';
@@ -77,3 +77,5 @@ exports.useLegacySass = (() => {
77
77
  console.warn(color_1.colors.yellow(`Warning: 'NG_BUILD_LEGACY_SASS' environment variable support will be removed in version 16.`));
78
78
  return isEnabled(legacySassVariable);
79
79
  })();
80
+ const debugPerfVariable = process.env['NG_BUILD_DEBUG_PERF'];
81
+ exports.debugPerformance = isPresent(debugPerfVariable) && isEnabled(debugPerfVariable);
@@ -44,6 +44,7 @@ const load_esm_1 = require("../../utils/load-esm");
44
44
  const plugins_1 = require("../plugins");
45
45
  const devtools_ignore_plugin_1 = require("../plugins/devtools-ignore-plugin");
46
46
  const named_chunks_plugin_1 = require("../plugins/named-chunks-plugin");
47
+ const occurrences_plugin_1 = require("../plugins/occurrences-plugin");
47
48
  const progress_plugin_1 = require("../plugins/progress-plugin");
48
49
  const transfer_size_plugin_1 = require("../plugins/transfer-size-plugin");
49
50
  const typescript_1 = require("../plugins/typescript");
@@ -52,7 +53,7 @@ const helpers_1 = require("../utils/helpers");
52
53
  const VENDORS_TEST = /[\\/]node_modules[\\/]/;
53
54
  // eslint-disable-next-line max-lines-per-function
54
55
  async function getCommonConfig(wco) {
55
- var _a, _b;
56
+ var _a, _b, _c;
56
57
  const { root, projectRoot, buildOptions, tsConfig, projectName, sourceRoot, tsConfigPath } = wco;
57
58
  const { cache, codeCoverage, crossOrigin = 'none', platform = 'browser', aot = true, codeCoverageExclude = [], main, polyfills, sourceMap: { styles: stylesSourceMap, scripts: scriptsSourceMap, vendor: vendorSourceMap, hidden: hiddenSourceMap, }, optimization: { styles: stylesOptimization, scripts: scriptsOptimization }, commonChunk, vendorChunk, subresourceIntegrity, verbose, poll, webWorkerTsConfig, externalDependencies = [], allowedCommonJsDependencies, } = buildOptions;
58
59
  const isPlatformServer = buildOptions.platform === 'server';
@@ -68,13 +69,28 @@ async function getCommonConfig(wco) {
68
69
  if (buildOptions.progress) {
69
70
  extraPlugins.push(new progress_plugin_1.ProgressPlugin(platform));
70
71
  }
72
+ const localizePackageInitEntryPoint = '@angular/localize/init';
73
+ const hasLocalizeType = (_a = tsConfig.options.types) === null || _a === void 0 ? void 0 : _a.some((t) => t === '@angular/localize' || t === localizePackageInitEntryPoint);
74
+ if (hasLocalizeType) {
75
+ entryPoints['main'] = [localizePackageInitEntryPoint];
76
+ }
71
77
  if (buildOptions.main) {
72
78
  const mainPath = path.resolve(root, buildOptions.main);
73
- entryPoints['main'] = [mainPath];
79
+ if (Array.isArray(entryPoints['main'])) {
80
+ entryPoints['main'].push(mainPath);
81
+ }
82
+ else {
83
+ entryPoints['main'] = [mainPath];
84
+ }
74
85
  }
75
86
  if (isPlatformServer) {
76
87
  // Fixes Critical dependency: the request of a dependency is an expression
77
88
  extraPlugins.push(new webpack_2.ContextReplacementPlugin(/@?hapi|express[\\/]/));
89
+ if (Array.isArray(entryPoints['main'])) {
90
+ // This import must come before any imports (direct or transitive) that rely on DOM built-ins being
91
+ // available, such as `@angular/elements`.
92
+ entryPoints['main'].unshift('@angular/platform-server/init');
93
+ }
78
94
  }
79
95
  if (polyfills === null || polyfills === void 0 ? void 0 : polyfills.length) {
80
96
  // `zone.js/testing` is a **special** polyfill because when not imported in the main it fails with the below errors:
@@ -253,9 +269,9 @@ async function getCommonConfig(wco) {
253
269
  output: {
254
270
  uniqueName: projectName,
255
271
  hashFunction: 'xxhash64',
256
- clean: (_a = buildOptions.deleteOutputPath) !== null && _a !== void 0 ? _a : true,
272
+ clean: (_b = buildOptions.deleteOutputPath) !== null && _b !== void 0 ? _b : true,
257
273
  path: path.resolve(root, buildOptions.outputPath),
258
- publicPath: (_b = buildOptions.deployUrl) !== null && _b !== void 0 ? _b : '',
274
+ publicPath: (_c = buildOptions.deployUrl) !== null && _c !== void 0 ? _c : '',
259
275
  filename: `[name]${hashFormat.chunk}.js`,
260
276
  chunkFilename: `[name]${hashFormat.chunk}.js`,
261
277
  libraryTarget: isPlatformServer ? 'commonjs' : undefined,
@@ -385,7 +401,15 @@ async function getCommonConfig(wco) {
385
401
  },
386
402
  },
387
403
  },
388
- plugins: [new named_chunks_plugin_1.NamedChunksPlugin(), new plugins_1.DedupeModuleResolvePlugin({ verbose }), ...extraPlugins],
404
+ plugins: [
405
+ new named_chunks_plugin_1.NamedChunksPlugin(),
406
+ new occurrences_plugin_1.OccurrencesPlugin({
407
+ aot,
408
+ scriptsOptimization,
409
+ }),
410
+ new plugins_1.DedupeModuleResolvePlugin({ verbose }),
411
+ ...extraPlugins,
412
+ ],
389
413
  node: false,
390
414
  };
391
415
  }
@@ -5,7 +5,6 @@
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
- export * from './analytics';
9
8
  export * from './common';
10
9
  export * from './dev-server';
11
10
  export * from './styles';
@@ -21,7 +21,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
21
21
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
22
22
  };
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
- __exportStar(require("./analytics"), exports);
25
24
  __exportStar(require("./common"), exports);
26
25
  __exportStar(require("./dev-server"), exports);
27
26
  __exportStar(require("./styles"), exports);
@@ -34,10 +34,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
34
34
  };
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.getStylesConfig = void 0;
37
- const fs = __importStar(require("fs"));
38
37
  const mini_css_extract_plugin_1 = __importDefault(require("mini-css-extract-plugin"));
39
- const path = __importStar(require("path"));
40
- const url_1 = require("url");
38
+ const fs = __importStar(require("node:fs"));
39
+ const path = __importStar(require("node:path"));
40
+ const node_url_1 = require("node:url");
41
41
  const sass_service_1 = require("../../sass/sass-service");
42
42
  const sass_service_legacy_1 = require("../../sass/sass-service-legacy");
43
43
  const environment_options_1 = require("../../utils/environment-options");
@@ -48,7 +48,7 @@ const helpers_1 = require("../utils/helpers");
48
48
  // eslint-disable-next-line max-lines-per-function
49
49
  function getStylesConfig(wco) {
50
50
  var _a, _b, _c;
51
- const { root, projectRoot, buildOptions } = wco;
51
+ const { root, buildOptions } = wco;
52
52
  const extraPlugins = [];
53
53
  extraPlugins.push(new plugins_1.AnyComponentStyleBudgetChecker(buildOptions.budgets));
54
54
  const cssSourceMap = buildOptions.sourceMap.styles;
@@ -101,10 +101,8 @@ function getStylesConfig(wco) {
101
101
  extraPostcssPlugins.push(require(tailwindPackagePath)({ config: tailwindConfigPath }));
102
102
  }
103
103
  }
104
- const postcssImports = require('postcss-import');
105
104
  const autoprefixer = require('autoprefixer');
106
105
  const postcssOptionsCreator = (inlineSourcemaps, extracted) => {
107
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
108
106
  const optionGenerator = (loader) => ({
109
107
  map: inlineSourcemaps
110
108
  ? {
@@ -113,20 +111,6 @@ function getStylesConfig(wco) {
113
111
  }
114
112
  : undefined,
115
113
  plugins: [
116
- postcssImports({
117
- load: (filename) => {
118
- return new Promise((resolve, reject) => {
119
- loader.fs.readFile(filename, (err, data) => {
120
- if (err) {
121
- reject(err);
122
- return;
123
- }
124
- const content = data.toString();
125
- resolve(content);
126
- });
127
- });
128
- },
129
- }),
130
114
  (0, plugins_1.PostcssCliResources)({
131
115
  baseHref: buildOptions.baseHref,
132
116
  deployUrl: buildOptions.deployUrl,
@@ -165,6 +149,16 @@ function getStylesConfig(wco) {
165
149
  const postCss = require('postcss');
166
150
  const postCssLoaderPath = require.resolve('postcss-loader');
167
151
  const componentStyleLoaders = [
152
+ {
153
+ loader: require.resolve('css-loader'),
154
+ options: {
155
+ url: false,
156
+ sourceMap: componentsSourceMap,
157
+ importLoaders: 1,
158
+ exportType: 'string',
159
+ esModule: false,
160
+ },
161
+ },
168
162
  {
169
163
  loader: postCssLoaderPath,
170
164
  options: {
@@ -182,6 +176,7 @@ function getStylesConfig(wco) {
182
176
  options: {
183
177
  url: false,
184
178
  sourceMap: !!cssSourceMap,
179
+ importLoaders: 1,
185
180
  },
186
181
  },
187
182
  {
@@ -261,7 +256,6 @@ function getStylesConfig(wco) {
261
256
  // Component styles are all styles except defined global styles
262
257
  {
263
258
  use: componentStyleLoaders,
264
- type: 'asset/source',
265
259
  resourceQuery: /\?ngResource/,
266
260
  },
267
261
  ],
@@ -370,11 +364,41 @@ function getSassResolutionImporter(loaderContext, root, preserveSymlinks) {
370
364
  mainFiles: ['_index', 'index', '...'],
371
365
  });
372
366
  return {
373
- findFileUrl: (url, { fromImport }) => {
367
+ findFileUrl: async (url, { fromImport, previousResolvedModules }) => {
368
+ if (url.charAt(0) === '.') {
369
+ // Let Sass handle relative imports.
370
+ return null;
371
+ }
374
372
  const resolve = fromImport ? resolveImport : resolveModule;
375
- return resolve(root, url)
376
- .then((file) => (0, url_1.pathToFileURL)(file))
377
- .catch(() => null);
373
+ // Try to resolve from root of workspace
374
+ let result = await tryResolve(resolve, root, url);
375
+ // Try to resolve from previously resolved modules.
376
+ if (!result && previousResolvedModules) {
377
+ for (const path of previousResolvedModules) {
378
+ result = await tryResolve(resolve, path, url);
379
+ if (result) {
380
+ break;
381
+ }
382
+ }
383
+ }
384
+ return result ? (0, node_url_1.pathToFileURL)(result) : null;
378
385
  },
379
386
  };
380
387
  }
388
+ async function tryResolve(resolve, root, url) {
389
+ try {
390
+ return await resolve(root, url);
391
+ }
392
+ catch {
393
+ // Try to resolve a partial file
394
+ // @use '@material/button/button' as mdc-button;
395
+ // `@material/button/button` -> `@material/button/_button`
396
+ const lastSlashIndex = url.lastIndexOf('/');
397
+ const underscoreIndex = lastSlashIndex + 1;
398
+ if (underscoreIndex > 0 && url.charAt(underscoreIndex) !== '_') {
399
+ const partialFileUrl = `${url.slice(0, underscoreIndex)}_${url.slice(underscoreIndex)}`;
400
+ return resolve(root, partialFileUrl).catch(() => undefined);
401
+ }
402
+ }
403
+ return undefined;
404
+ }
@@ -0,0 +1,18 @@
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
+ import { Compiler } from 'webpack';
9
+ export interface OccurrencesPluginOptions {
10
+ aot?: boolean;
11
+ scriptsOptimization?: boolean;
12
+ }
13
+ export declare class OccurrencesPlugin {
14
+ private options;
15
+ constructor(options: OccurrencesPluginOptions);
16
+ apply(compiler: Compiler): void;
17
+ private countOccurrences;
18
+ }
@@ -0,0 +1,79 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.OccurrencesPlugin = void 0;
11
+ const PLUGIN_NAME = 'angular-occurrences-plugin';
12
+ class OccurrencesPlugin {
13
+ constructor(options) {
14
+ this.options = options;
15
+ }
16
+ apply(compiler) {
17
+ compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
18
+ compilation.hooks.processAssets.tapPromise({
19
+ name: PLUGIN_NAME,
20
+ stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ANALYSE,
21
+ }, async (compilationAssets) => {
22
+ for (const assetName of Object.keys(compilationAssets)) {
23
+ if (!assetName.endsWith('.js')) {
24
+ continue;
25
+ }
26
+ const scriptAsset = compilation.getAsset(assetName);
27
+ if (!scriptAsset || scriptAsset.source.size() <= 0) {
28
+ continue;
29
+ }
30
+ const src = scriptAsset.source.source().toString('utf-8');
31
+ let ngComponentCount = 0;
32
+ if (!this.options.aot) {
33
+ // Count the number of `Component({` strings (case sensitive), which happens in __decorate().
34
+ ngComponentCount += this.countOccurrences(src, 'Component({');
35
+ }
36
+ if (this.options.scriptsOptimization) {
37
+ // for ascii_only true
38
+ ngComponentCount += this.countOccurrences(src, '.\\u0275cmp', false);
39
+ }
40
+ else {
41
+ // For Ivy we just count ɵcmp.src
42
+ ngComponentCount += this.countOccurrences(src, '.ɵcmp', true);
43
+ }
44
+ compilation.updateAsset(assetName, (s) => s, (assetInfo) => ({
45
+ ...assetInfo,
46
+ ngComponentCount,
47
+ }));
48
+ }
49
+ });
50
+ });
51
+ }
52
+ countOccurrences(source, match, wordBreak = false) {
53
+ let count = 0;
54
+ // We condition here so branch prediction happens out of the loop, not in it.
55
+ if (wordBreak) {
56
+ const re = /\w/;
57
+ for (let pos = source.lastIndexOf(match); pos >= 0; pos = source.lastIndexOf(match, pos)) {
58
+ if (!(re.test(source[pos - 1] || '') || re.test(source[pos + match.length] || ''))) {
59
+ count++; // 1 match, AH! AH! AH! 2 matches, AH! AH! AH!
60
+ }
61
+ pos -= match.length;
62
+ if (pos < 0) {
63
+ break;
64
+ }
65
+ }
66
+ }
67
+ else {
68
+ for (let pos = source.lastIndexOf(match); pos >= 0; pos = source.lastIndexOf(match, pos)) {
69
+ count++; // 1 match, AH! AH! AH! 2 matches, AH! AH! AH!
70
+ pos -= match.length;
71
+ if (pos < 0) {
72
+ break;
73
+ }
74
+ }
75
+ }
76
+ return count;
77
+ }
78
+ }
79
+ exports.OccurrencesPlugin = OccurrencesPlugin;
@@ -22,17 +22,22 @@ export interface BundleStats {
22
22
  initial: boolean;
23
23
  stats: BundleStatsData;
24
24
  }
25
- export declare function generateBundleStats(info: {
26
- rawSize?: number;
27
- estimatedTransferSize?: number;
28
- files?: string[];
29
- names?: string[];
30
- initial?: boolean;
31
- rendered?: boolean;
32
- }): BundleStats;
33
25
  export declare function statsWarningsToString(json: StatsCompilation, statsConfig: WebpackStatsOptions): string;
34
26
  export declare function statsErrorsToString(json: StatsCompilation, statsConfig: WebpackStatsOptions): string;
35
27
  export declare function statsHasErrors(json: StatsCompilation): boolean;
36
28
  export declare function statsHasWarnings(json: StatsCompilation): boolean;
37
29
  export declare function createWebpackLoggingCallback(options: BrowserBuilderOptions, logger: logging.LoggerApi): WebpackLoggingCallback;
30
+ export interface BuildEventStats {
31
+ aot: boolean;
32
+ optimization: boolean;
33
+ allChunksCount: number;
34
+ lazyChunksCount: number;
35
+ initialChunksCount: number;
36
+ changedChunksCount?: number;
37
+ durationInMs: number;
38
+ cssSizeInBytes: number;
39
+ jsSizeInBytes: number;
40
+ ngComponentCount: number;
41
+ }
42
+ export declare function generateBuildEventStats(webpackStats: StatsCompilation, browserBuilderOptions: BrowserBuilderOptions): BuildEventStats;
38
43
  export declare function webpackStatsLogger(logger: logging.LoggerApi, json: StatsCompilation, config: Configuration, budgetFailures?: BudgetCalculatorResult[]): void;
@@ -33,10 +33,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
33
33
  return (mod && mod.__esModule) ? mod : { "default": mod };
34
34
  };
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.webpackStatsLogger = exports.createWebpackLoggingCallback = exports.statsHasWarnings = exports.statsHasErrors = exports.statsErrorsToString = exports.statsWarningsToString = exports.generateBundleStats = exports.formatSize = void 0;
36
+ exports.webpackStatsLogger = exports.generateBuildEventStats = exports.createWebpackLoggingCallback = exports.statsHasWarnings = exports.statsHasErrors = exports.statsErrorsToString = exports.statsWarningsToString = exports.formatSize = void 0;
37
37
  const core_1 = require("@angular-devkit/core");
38
+ const assert_1 = __importDefault(require("assert"));
38
39
  const path = __importStar(require("path"));
39
40
  const text_table_1 = __importDefault(require("text-table"));
41
+ const utils_1 = require("../../utils");
40
42
  const color_1 = require("../../utils/color");
41
43
  const async_chunks_1 = require("./async-chunks");
42
44
  const helpers_1 = require("./helpers");
@@ -52,6 +54,11 @@ function formatSize(size) {
52
54
  return `${roundedSize.toFixed(fractionDigits)} ${abbreviations[index]}`;
53
55
  }
54
56
  exports.formatSize = formatSize;
57
+ function getBuildDuration(webpackStats) {
58
+ (0, assert_1.default)(webpackStats.builtAt, 'buildAt cannot be undefined');
59
+ (0, assert_1.default)(webpackStats.time, 'time cannot be undefined');
60
+ return Date.now() - webpackStats.builtAt + webpackStats.time;
61
+ }
55
62
  function generateBundleStats(info) {
56
63
  var _a, _b, _c;
57
64
  const rawSize = typeof info.rawSize === 'number' ? info.rawSize : '-';
@@ -64,7 +71,6 @@ function generateBundleStats(info) {
64
71
  stats: [files, names, rawSize, estimatedTransferSize],
65
72
  };
66
73
  }
67
- exports.generateBundleStats = generateBundleStats;
68
74
  function generateBuildStatsTable(data, colors, showTotalSize, showEstimatedTransferSize, budgetFailures) {
69
75
  const g = (x) => (colors ? color_1.colors.greenBright(x) : x);
70
76
  const c = (x) => (colors ? color_1.colors.cyanBright(x) : x);
@@ -238,10 +244,7 @@ statsConfig, budgetFailures) {
238
244
  // In some cases we do things outside of webpack context
239
245
  // Such us index generation, service worker augmentation etc...
240
246
  // This will correct the time and include these.
241
- let time = 0;
242
- if (json.builtAt !== undefined && json.time !== undefined) {
243
- time = Date.now() - json.builtAt + json.time;
244
- }
247
+ const time = getBuildDuration(json);
245
248
  if (unchangedChunkNumber > 0) {
246
249
  return ('\n' +
247
250
  rs(core_1.tags.stripIndents `
@@ -370,6 +373,54 @@ function createWebpackLoggingCallback(options, logger) {
370
373
  };
371
374
  }
372
375
  exports.createWebpackLoggingCallback = createWebpackLoggingCallback;
376
+ function generateBuildEventStats(webpackStats, browserBuilderOptions) {
377
+ var _a, _b;
378
+ const { chunks = [], assets = [] } = webpackStats;
379
+ let jsSizeInBytes = 0;
380
+ let cssSizeInBytes = 0;
381
+ let initialChunksCount = 0;
382
+ let ngComponentCount = 0;
383
+ let changedChunksCount = 0;
384
+ const allChunksCount = chunks.length;
385
+ const isFirstRun = !runsCache.has(webpackStats.outputPath || '');
386
+ const chunkFiles = new Set();
387
+ for (const chunk of chunks) {
388
+ if (!isFirstRun && chunk.rendered) {
389
+ changedChunksCount++;
390
+ }
391
+ if (chunk.initial) {
392
+ initialChunksCount++;
393
+ }
394
+ for (const file of (_a = chunk.files) !== null && _a !== void 0 ? _a : []) {
395
+ chunkFiles.add(file);
396
+ }
397
+ }
398
+ for (const asset of assets) {
399
+ if (asset.name.endsWith('.map') || !chunkFiles.has(asset.name)) {
400
+ continue;
401
+ }
402
+ if (asset.name.endsWith('.js')) {
403
+ jsSizeInBytes += asset.size;
404
+ ngComponentCount += (_b = asset.info.ngComponentCount) !== null && _b !== void 0 ? _b : 0;
405
+ }
406
+ else if (asset.name.endsWith('.css')) {
407
+ cssSizeInBytes += asset.size;
408
+ }
409
+ }
410
+ return {
411
+ optimization: !!(0, utils_1.normalizeOptimization)(browserBuilderOptions.optimization).scripts,
412
+ aot: browserBuilderOptions.aot !== false,
413
+ allChunksCount,
414
+ lazyChunksCount: allChunksCount - initialChunksCount,
415
+ initialChunksCount,
416
+ changedChunksCount,
417
+ durationInMs: getBuildDuration(webpackStats),
418
+ cssSizeInBytes,
419
+ jsSizeInBytes,
420
+ ngComponentCount,
421
+ };
422
+ }
423
+ exports.generateBuildEventStats = generateBuildEventStats;
373
424
  function webpackStatsLogger(logger, json, config, budgetFailures) {
374
425
  logger.info(statsToString(json, config.stats, budgetFailures));
375
426
  if (typeof config.stats !== 'object') {
@@ -1,11 +0,0 @@
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
- import { BuilderContext } from '@angular-devkit/architect';
9
- import { Configuration } from 'webpack';
10
- import { WebpackConfigOptions } from '../../utils/build-options';
11
- export declare function getAnalyticsConfig(wco: WebpackConfigOptions, context: BuilderContext): Configuration;
@@ -1,27 +0,0 @@
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
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.getAnalyticsConfig = void 0;
11
- const analytics_1 = require("../plugins/analytics");
12
- function getAnalyticsConfig(wco, context) {
13
- if (!context.analytics) {
14
- return {};
15
- }
16
- // If there's analytics, add our plugin. Otherwise no need to slow down the build.
17
- let category = 'build';
18
- if (context.builder) {
19
- // We already vetted that this is a "safe" package, otherwise the analytics would be noop.
20
- category = context.builder.builderName.split(':')[1] || context.builder.builderName || 'build';
21
- }
22
- // The category is the builder name if it's an angular builder.
23
- return {
24
- plugins: [new analytics_1.NgBuildAnalyticsPlugin(wco.projectRoot, context.analytics, category)],
25
- };
26
- }
27
- exports.getAnalyticsConfig = getAnalyticsConfig;