@angular-devkit/build-angular 12.0.0 → 12.0.4

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 (46) hide show
  1. package/package.json +21 -21
  2. package/src/browser/index.js +1 -3
  3. package/src/browser/schema.d.ts +1 -1
  4. package/src/browser/schema.json +1 -1
  5. package/src/dev-server/index.js +38 -37
  6. package/src/dev-server/schema.d.ts +2 -1
  7. package/src/dev-server/schema.json +1 -1
  8. package/src/extract-i18n/index.js +6 -3
  9. package/src/karma/index.js +1 -0
  10. package/src/karma/schema.d.ts +1 -1
  11. package/src/karma/schema.json +1 -1
  12. package/src/karma/tests/setup.d.ts +18 -0
  13. package/src/karma/tests/setup.js +29 -0
  14. package/src/sass/sass-service.d.ts +50 -0
  15. package/src/sass/sass-service.js +185 -0
  16. package/src/sass/worker.d.ts +8 -0
  17. package/src/sass/worker.js +49 -0
  18. package/src/server/schema.d.ts +1 -1
  19. package/src/server/schema.json +1 -1
  20. package/src/utils/action-executor.js +2 -2
  21. package/src/utils/environment-options.d.ts +1 -0
  22. package/src/utils/environment-options.js +12 -1
  23. package/src/utils/index.d.ts +0 -1
  24. package/src/utils/index.js +0 -1
  25. package/src/utils/service-worker.js +1 -1
  26. package/src/utils/spinner.d.ts +2 -0
  27. package/src/utils/spinner.js +14 -0
  28. package/src/webpack/configs/common.js +36 -44
  29. package/src/webpack/configs/server.js +8 -0
  30. package/src/webpack/configs/stats.d.ts +6 -14
  31. package/src/webpack/configs/stats.js +5 -8
  32. package/src/webpack/configs/styles.js +54 -7
  33. package/src/webpack/plugins/index-html-webpack-plugin.js +1 -1
  34. package/src/webpack/plugins/index.d.ts +0 -1
  35. package/src/webpack/plugins/index.js +1 -3
  36. package/src/webpack/plugins/karma/karma-context.html +1 -1
  37. package/src/webpack/plugins/karma/karma-debug.html +1 -1
  38. package/src/webpack/plugins/karma/karma.js +1 -1
  39. package/src/webpack/plugins/postcss-cli-resources.js +1 -1
  40. package/src/webpack/utils/async-chunks.js +11 -11
  41. package/src/webpack/utils/stats.d.ts +2 -2
  42. package/src/webpack/utils/stats.js +16 -9
  43. package/src/utils/workers.d.ts +0 -22
  44. package/src/utils/workers.js +0 -26
  45. package/src/webpack/plugins/optimize-css-webpack-plugin.d.ts +0 -17
  46. package/src/webpack/plugins/optimize-css-webpack-plugin.js +0 -106
@@ -0,0 +1,49 @@
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
+ const sass_1 = require("sass");
11
+ const worker_threads_1 = require("worker_threads");
12
+ if (!worker_threads_1.parentPort) {
13
+ throw new Error('Sass worker must be executed as a Worker.');
14
+ }
15
+ // The importer variables are used to proxy import requests to the main thread
16
+ let { workerImporterPort, importerSignal } = (worker_threads_1.workerData || {});
17
+ worker_threads_1.parentPort.on('message', (message) => {
18
+ // The init message is only needed to support Node.js < 12.17 and can be removed once support is dropped
19
+ if (message.init) {
20
+ workerImporterPort = message.workerImporterPort;
21
+ importerSignal = message.importerSignal;
22
+ return;
23
+ }
24
+ const { id, hasImporter, options } = message;
25
+ try {
26
+ if (hasImporter) {
27
+ // When a custom importer function is present, the importer request must be proxied
28
+ // back to the main thread where it can be executed.
29
+ // This process must be synchronous from the perspective of dart-sass. The `Atomics`
30
+ // functions combined with the shared memory `importSignal` and the Node.js
31
+ // `receiveMessageOnPort` function are used to ensure synchronous behavior.
32
+ options.importer = (url, prev) => {
33
+ var _a;
34
+ Atomics.store(importerSignal, 0, 0);
35
+ workerImporterPort.postMessage({ id, url, prev });
36
+ Atomics.wait(importerSignal, 0, 0);
37
+ return (_a = worker_threads_1.receiveMessageOnPort(workerImporterPort)) === null || _a === void 0 ? void 0 : _a.message;
38
+ };
39
+ }
40
+ // The synchronous Sass render function can be up to two times faster than the async variant
41
+ const result = sass_1.renderSync(options);
42
+ worker_threads_1.parentPort === null || worker_threads_1.parentPort === void 0 ? void 0 : worker_threads_1.parentPort.postMessage({ id, result });
43
+ }
44
+ catch (error) {
45
+ // Needed because V8 will only serialize the message and stack properties of an Error instance.
46
+ const { formatted, file, line, column, message, stack } = error;
47
+ worker_threads_1.parentPort === null || worker_threads_1.parentPort === void 0 ? void 0 : worker_threads_1.parentPort.postMessage({ id, error: { formatted, file, line, column, message, stack } });
48
+ }
49
+ });
@@ -198,7 +198,7 @@ export interface SourceMapClass {
198
198
  */
199
199
  export interface StylePreprocessorOptions {
200
200
  /**
201
- * Paths to include. Paths will be resolved to project root.
201
+ * Paths to include. Paths will be resolved to workspace root.
202
202
  */
203
203
  includePaths?: string[];
204
204
  }
@@ -24,7 +24,7 @@
24
24
  "type": "object",
25
25
  "properties": {
26
26
  "includePaths": {
27
- "description": "Paths to include. Paths will be resolved to project root.",
27
+ "description": "Paths to include. Paths will be resolved to workspace root.",
28
28
  "type": "array",
29
29
  "items": {
30
30
  "type": "string"
@@ -13,7 +13,7 @@ const os = require("os");
13
13
  const path = require("path");
14
14
  const v8_1 = require("v8");
15
15
  const action_cache_1 = require("./action-cache");
16
- const workers_1 = require("./workers");
16
+ const environment_options_1 = require("./environment-options");
17
17
  let workerFile = require.resolve('./process-bundle');
18
18
  workerFile =
19
19
  path.extname(workerFile) === '.ts' ? require.resolve('./process-bundle-bootstrap') : workerFile;
@@ -36,7 +36,7 @@ class BundleActionExecutor {
36
36
  return (this.largeWorker = new jest_worker_1.default(workerFile, {
37
37
  exposedMethods: ['process', 'inlineLocales'],
38
38
  setupArgs: [[...v8_1.serialize(this.workerOptions)]],
39
- numWorkers: workers_1.maxWorkers,
39
+ numWorkers: environment_options_1.maxWorkers,
40
40
  }));
41
41
  }
42
42
  ensureSmall() {
@@ -11,3 +11,4 @@ export declare const allowMinify: boolean;
11
11
  export declare const cachingDisabled: boolean;
12
12
  export declare const cachingBasePath: string | null;
13
13
  export declare const profilingEnabled: boolean;
14
+ export declare const maxWorkers: number;
@@ -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.profilingEnabled = exports.cachingBasePath = exports.cachingDisabled = exports.allowMinify = exports.shouldBeautify = exports.allowMangle = void 0;
10
+ exports.maxWorkers = exports.profilingEnabled = exports.cachingBasePath = exports.cachingDisabled = exports.allowMinify = exports.shouldBeautify = exports.allowMangle = void 0;
11
11
  const path = require("path");
12
12
  function isDisabled(variable) {
13
13
  return variable === '0' || variable.toLowerCase() === 'false';
@@ -72,3 +72,14 @@ exports.cachingBasePath = (() => {
72
72
  // Build profiling
73
73
  const profilingVariable = process.env['NG_BUILD_PROFILING'];
74
74
  exports.profilingEnabled = isPresent(profilingVariable) && isEnabled(profilingVariable);
75
+ /**
76
+ * Some environments, like CircleCI which use Docker report a number of CPUs by the host and not the count of available.
77
+ * This cause `Error: Call retries were exceeded` errors when trying to use them.
78
+ *
79
+ * @see https://github.com/nodejs/node/issues/28762
80
+ * @see https://github.com/webpack-contrib/terser-webpack-plugin/issues/143
81
+ * @see https://ithub.com/angular/angular-cli/issues/16860#issuecomment-588828079
82
+ *
83
+ */
84
+ const maxWorkersVariable = process.env['NG_BUILD_MAX_WORKERS'];
85
+ exports.maxWorkers = isPresent(maxWorkersVariable) ? +maxWorkersVariable : 4;
@@ -15,4 +15,3 @@ export * from './normalize-source-maps';
15
15
  export * from './normalize-optimization';
16
16
  export * from './normalize-builder-schema';
17
17
  export * from './url';
18
- export * from './workers';
@@ -27,4 +27,3 @@ __exportStar(require("./normalize-source-maps"), exports);
27
27
  __exportStar(require("./normalize-optimization"), exports);
28
28
  __exportStar(require("./normalize-builder-schema"), exports);
29
29
  __exportStar(require("./url"), exports);
30
- __exportStar(require("./workers"), exports);
@@ -40,7 +40,7 @@ class CliFilesystem {
40
40
  for await (const entry of await fs_1.promises.opendir(dir)) {
41
41
  if (entry.isFile()) {
42
42
  // Uses posix paths since the service worker expects URLs
43
- items.push('/' + path.posix.relative(this.base, path.posix.join(dir, entry.name)));
43
+ items.push('/' + path.relative(this.base, path.join(dir, entry.name)).replace(/\\/g, '/'));
44
44
  }
45
45
  else if (entry.isDirectory()) {
46
46
  subdirectories.push(path.join(dir, entry.name));
@@ -6,11 +6,13 @@
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
8
  export declare class Spinner {
9
+ #private;
9
10
  private readonly spinner;
10
11
  /** When false, only fail messages will be displayed. */
11
12
  enabled: boolean;
12
13
  constructor(text?: string);
13
14
  set text(text: string);
15
+ get isSpinning(): boolean;
14
16
  succeed(text?: string): void;
15
17
  fail(text?: string): void;
16
18
  stop(): void;
@@ -6,25 +6,38 @@
6
6
  * Use of this source code is governed by an MIT-style license that can be
7
7
  * found in the LICENSE file at https://angular.io/license
8
8
  */
9
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {
10
+ if (!privateMap.has(receiver)) {
11
+ throw new TypeError("attempted to get private field on non-instance");
12
+ }
13
+ return privateMap.get(receiver);
14
+ };
15
+ var _isTTY;
9
16
  Object.defineProperty(exports, "__esModule", { value: true });
10
17
  exports.Spinner = void 0;
11
18
  const ora = require("ora");
12
19
  const color_1 = require("./color");
20
+ const tty_1 = require("./tty");
13
21
  class Spinner {
14
22
  constructor(text) {
15
23
  /** When false, only fail messages will be displayed. */
16
24
  this.enabled = true;
25
+ _isTTY.set(this, tty_1.isTTY());
17
26
  this.spinner = ora({
18
27
  text,
19
28
  // The below 2 options are needed because otherwise CTRL+C will be delayed
20
29
  // when the underlying process is sync.
21
30
  hideCursor: false,
22
31
  discardStdin: false,
32
+ isEnabled: __classPrivateFieldGet(this, _isTTY),
23
33
  });
24
34
  }
25
35
  set text(text) {
26
36
  this.spinner.text = text;
27
37
  }
38
+ get isSpinning() {
39
+ return this.spinner.isSpinning || !__classPrivateFieldGet(this, _isTTY);
40
+ }
28
41
  succeed(text) {
29
42
  if (this.enabled) {
30
43
  this.spinner.succeed(text);
@@ -43,3 +56,4 @@ class Spinner {
43
56
  }
44
57
  }
45
58
  exports.Spinner = Spinner;
59
+ _isTTY = new WeakMap();
@@ -23,10 +23,9 @@ const webpack_diagnostics_1 = require("../../utils/webpack-diagnostics");
23
23
  const plugins_1 = require("../plugins");
24
24
  const helpers_1 = require("../utils/helpers");
25
25
  const stats_1 = require("../utils/stats");
26
- const TerserPlugin = require('terser-webpack-plugin');
27
26
  // eslint-disable-next-line max-lines-per-function
28
27
  function getCommonConfig(wco) {
29
- var _a;
28
+ var _a, _b;
30
29
  const { root, projectRoot, buildOptions, tsConfig } = wco;
31
30
  const { platform = 'browser', sourceMap: { styles: stylesSourceMap, scripts: scriptsSourceMap, vendor: vendorSourceMap }, optimization: { styles: stylesOptimization, scripts: scriptsOptimization }, } = buildOptions;
32
31
  const extraPlugins = [];
@@ -34,7 +33,30 @@ function getCommonConfig(wco) {
34
33
  const entryPoints = {};
35
34
  // determine hashing format
36
35
  const hashFormat = helpers_1.getOutputHashFormat(buildOptions.outputHashing || 'none');
36
+ const buildBrowserFeatures = new utils_1.BuildBrowserFeatures(projectRoot);
37
37
  const targetInFileName = helpers_1.getEsVersionForFileName(tsConfig.options.target, buildOptions.differentialLoadingNeeded);
38
+ if (buildOptions.progress) {
39
+ const spinner = new spinner_1.Spinner();
40
+ spinner.start(`Generating ${platform} application bundles (phase: setup)...`);
41
+ extraPlugins.push(new webpack_1.ProgressPlugin({
42
+ handler: (percentage, message) => {
43
+ const phase = message ? ` (phase: ${message})` : '';
44
+ spinner.text = `Generating ${platform} application bundles${phase}...`;
45
+ switch (percentage) {
46
+ case 1:
47
+ if (spinner.isSpinning) {
48
+ spinner.succeed(`${platform.replace(/^\w/, (s) => s.toUpperCase())} application bundle generation complete.`);
49
+ }
50
+ break;
51
+ case 0:
52
+ if (!spinner.isSpinning) {
53
+ spinner.start();
54
+ }
55
+ break;
56
+ }
57
+ },
58
+ }));
59
+ }
38
60
  if (buildOptions.main) {
39
61
  const mainPath = path.resolve(root, buildOptions.main);
40
62
  entryPoints['main'] = [mainPath];
@@ -42,7 +64,6 @@ function getCommonConfig(wco) {
42
64
  const differentialLoadingMode = buildOptions.differentialLoadingNeeded && !buildOptions.watch;
43
65
  if (platform !== 'server') {
44
66
  if (differentialLoadingMode || tsConfig.options.target === typescript_1.ScriptTarget.ES5) {
45
- const buildBrowserFeatures = new utils_1.BuildBrowserFeatures(projectRoot);
46
67
  if (buildBrowserFeatures.isEs5SupportNeeded()) {
47
68
  const polyfillsChunkName = 'polyfills-es5';
48
69
  entryPoints[polyfillsChunkName] = [path.join(__dirname, '..', 'es5-polyfills.js')];
@@ -162,32 +183,6 @@ function getCommonConfig(wco) {
162
183
  patterns: copyWebpackPluginPatterns,
163
184
  }));
164
185
  }
165
- if (buildOptions.progress) {
166
- const spinner = new spinner_1.Spinner();
167
- let previousPercentage;
168
- extraPlugins.push(new webpack_1.ProgressPlugin({
169
- handler: (percentage, message) => {
170
- if (previousPercentage === 1 && percentage !== 0) {
171
- // In some scenarios in Webpack 5 percentage goes from 1 back to 0.99.
172
- // Ex: 0.99 -> 1 -> 0.99 -> 1
173
- // This causes the "complete" message to be displayed multiple times.
174
- return;
175
- }
176
- switch (percentage) {
177
- case 0:
178
- spinner.start(`Generating ${platform} application bundles...`);
179
- break;
180
- case 1:
181
- spinner.succeed(`${platform.replace(/^\w/, (s) => s.toUpperCase())} application bundle generation complete.`);
182
- break;
183
- default:
184
- spinner.text = `Generating ${platform} application bundles (phase: ${message})...`;
185
- break;
186
- }
187
- previousPercentage = percentage;
188
- },
189
- }));
190
- }
191
186
  if (buildOptions.showCircularDependencies) {
192
187
  const CircularDependencyPlugin = require('circular-dependency-plugin');
193
188
  extraPlugins.push(new CircularDependencyPlugin({
@@ -200,7 +195,7 @@ function getCommonConfig(wco) {
200
195
  compiler.hooks.done.tapPromise('angular-cli-stats', async (stats) => {
201
196
  const { stringifyStream } = await Promise.resolve().then(() => require('@discoveryjs/json-ext'));
202
197
  const data = stats.toJson('verbose');
203
- const statsOutputPath = path.join(root, buildOptions.outputPath, 'stats.json');
198
+ const statsOutputPath = path.resolve(root, buildOptions.outputPath, 'stats.json');
204
199
  try {
205
200
  await fs_1.promises.mkdir(path.dirname(statsOutputPath), { recursive: true });
206
201
  await new Promise((resolve, reject) => stringifyStream(data)
@@ -234,14 +229,8 @@ function getCommonConfig(wco) {
234
229
  ];
235
230
  }
236
231
  const extraMinimizers = [];
237
- if (stylesOptimization.minify) {
238
- extraMinimizers.push(new plugins_1.OptimizeCssWebpackPlugin({
239
- sourceMap: stylesSourceMap,
240
- // component styles retain their original file name
241
- test: (file) => /\.(?:css|scss|sass|less|styl)$/.test(file),
242
- }));
243
- }
244
232
  if (scriptsOptimization) {
233
+ const TerserPlugin = require('terser-webpack-plugin');
245
234
  const { GLOBAL_DEFS_FOR_TERSER, GLOBAL_DEFS_FOR_TERSER_WITH_AOT, } = require('@angular/compiler-cli');
246
235
  const angularGlobalDefinitions = buildOptions.aot
247
236
  ? GLOBAL_DEFS_FOR_TERSER_WITH_AOT
@@ -285,9 +274,7 @@ function getCommonConfig(wco) {
285
274
  };
286
275
  const globalScriptsNames = globalScriptsByBundleName.map((s) => s.bundleName);
287
276
  extraMinimizers.push(new TerserPlugin({
288
- sourceMap: scriptsSourceMap,
289
- parallel: utils_1.maxWorkers,
290
- cache: !environment_options_1.cachingDisabled && cache_path_1.findCachePath('terser-webpack'),
277
+ parallel: environment_options_1.maxWorkers,
291
278
  extractComments: false,
292
279
  exclude: globalScriptsNames,
293
280
  terserOptions,
@@ -295,9 +282,7 @@ function getCommonConfig(wco) {
295
282
  // Script bundles are fully optimized here in one step since they are never downleveled.
296
283
  // They are shared between ES2015 & ES5 outputs so must support ES5.
297
284
  new TerserPlugin({
298
- sourceMap: scriptsSourceMap,
299
- parallel: utils_1.maxWorkers,
300
- cache: !environment_options_1.cachingDisabled && cache_path_1.findCachePath('terser-webpack'),
285
+ parallel: environment_options_1.maxWorkers,
301
286
  extractComments: false,
302
287
  include: globalScriptsNames,
303
288
  terserOptions: {
@@ -337,8 +322,9 @@ function getCommonConfig(wco) {
337
322
  context: root,
338
323
  entry: entryPoints,
339
324
  output: {
325
+ clean: (_a = buildOptions.deleteOutputPath) !== null && _a !== void 0 ? _a : true,
340
326
  path: path.resolve(root, buildOptions.outputPath),
341
- publicPath: (_a = buildOptions.deployUrl) !== null && _a !== void 0 ? _a : '',
327
+ publicPath: (_b = buildOptions.deployUrl) !== null && _b !== void 0 ? _b : '',
342
328
  filename: ({ chunk }) => {
343
329
  if ((chunk === null || chunk === void 0 ? void 0 : chunk.name) === 'polyfills-es5') {
344
330
  return `polyfills-es5${hashFormat.chunk}.js`;
@@ -374,6 +360,8 @@ function getCommonConfig(wco) {
374
360
  },
375
361
  {
376
362
  test: /\.[cm]?js$|\.tsx?$/,
363
+ // The below is needed due to a bug in `@babel/runtime`. See: https://github.com/babel/babel/issues/12824
364
+ resolve: { fullySpecified: false },
377
365
  exclude: [/[\/\\](?:core-js|\@babel|tslib|web-animations-js)[\/\\]/],
378
366
  use: [
379
367
  {
@@ -390,6 +378,10 @@ function getCommonConfig(wco) {
390
378
  ...extraRules,
391
379
  ],
392
380
  },
381
+ experiments: {
382
+ syncWebAssembly: true,
383
+ asyncWebAssembly: true,
384
+ },
393
385
  cache: !!buildOptions.watch &&
394
386
  !environment_options_1.cachingDisabled && {
395
387
  type: 'memory',
@@ -34,6 +34,14 @@ function getServerConfig(wco) {
34
34
  output: {
35
35
  libraryTarget: 'commonjs',
36
36
  },
37
+ module: {
38
+ parser: {
39
+ javascript: {
40
+ worker: false,
41
+ url: false,
42
+ },
43
+ },
44
+ },
37
45
  plugins: [
38
46
  // Fixes Critical dependency: the request of a dependency is an expression
39
47
  new webpack_1.ContextReplacementPlugin(/@?hapi(\\|\/)/),
@@ -13,16 +13,12 @@ export declare function getWebpackStatsConfig(verbose?: boolean): {
13
13
  timings: boolean;
14
14
  chunks: boolean;
15
15
  builtAt: boolean;
16
- chunkModules: boolean;
17
- children: boolean;
18
- modules: boolean;
19
- reasons: boolean;
20
16
  warnings: boolean;
21
17
  errors: boolean;
22
18
  assets: boolean;
23
- version: boolean;
24
- errorDetails: boolean;
25
- moduleTrace: boolean;
19
+ cachedAssets: boolean;
20
+ ids: boolean;
21
+ entrypoints: boolean;
26
22
  };
27
23
  export declare function getStatsConfig(wco: WebpackConfigOptions): {
28
24
  stats: {
@@ -32,15 +28,11 @@ export declare function getStatsConfig(wco: WebpackConfigOptions): {
32
28
  timings: boolean;
33
29
  chunks: boolean;
34
30
  builtAt: boolean;
35
- chunkModules: boolean;
36
- children: boolean;
37
- modules: boolean;
38
- reasons: boolean;
39
31
  warnings: boolean;
40
32
  errors: boolean;
41
33
  assets: boolean;
42
- version: boolean;
43
- errorDetails: boolean;
44
- moduleTrace: boolean;
34
+ cachedAssets: boolean;
35
+ ids: boolean;
36
+ entrypoints: boolean;
45
37
  };
46
38
  };
@@ -15,16 +15,13 @@ const webpackOutputOptions = {
15
15
  timings: true,
16
16
  chunks: true,
17
17
  builtAt: true,
18
- chunkModules: false,
19
- children: false,
20
- modules: false,
21
- reasons: false,
22
18
  warnings: true,
23
19
  errors: true,
24
20
  assets: true,
25
- version: false,
26
- errorDetails: false,
27
- moduleTrace: false,
21
+ cachedAssets: true,
22
+ // Needed for markAsyncChunksNonInitial.
23
+ ids: true,
24
+ entrypoints: true,
28
25
  };
29
26
  const verboseWebpackOutputOptions = {
30
27
  // The verbose output will most likely be piped to a file, so colors just mess it up.
@@ -39,8 +36,8 @@ const verboseWebpackOutputOptions = {
39
36
  errorDetails: true,
40
37
  moduleTrace: true,
41
38
  logging: 'verbose',
39
+ modulesSpace: Infinity,
42
40
  };
43
- verboseWebpackOutputOptions['modulesSpace'] = Infinity;
44
41
  function getWebpackStatsConfig(verbose = false) {
45
42
  return verbose
46
43
  ? { ...webpackOutputOptions, ...verboseWebpackOutputOptions }
@@ -10,7 +10,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.getStylesConfig = void 0;
11
11
  const fs = require("fs");
12
12
  const path = require("path");
13
+ const sass_service_1 = require("../../sass/sass-service");
13
14
  const build_browser_features_1 = require("../../utils/build-browser-features");
15
+ const environment_options_1 = require("../../utils/environment-options");
14
16
  const plugins_1 = require("../plugins");
15
17
  const helpers_1 = require("../utils/helpers");
16
18
  function resolveGlobalStyles(styleEntrypoints, root, preserveSymlinks) {
@@ -62,7 +64,7 @@ function getStylesConfig(wco) {
62
64
  // use includePaths from appConfig
63
65
  const includePaths = (_c = (_b = (_a = buildOptions.stylePreprocessorOptions) === null || _a === void 0 ? void 0 : _a.includePaths) === null || _b === void 0 ? void 0 : _b.map((p) => path.resolve(root, p))) !== null && _c !== void 0 ? _c : [];
64
66
  // Process global styles.
65
- const { entryPoints, noInjectNames, paths: globalStylePaths } = resolveGlobalStyles(buildOptions.styles, root, !!buildOptions.preserveSymlinks);
67
+ const { entryPoints, noInjectNames, paths: globalStylePaths, } = resolveGlobalStyles(buildOptions.styles, root, !!buildOptions.preserveSymlinks);
66
68
  if (noInjectNames.length > 0) {
67
69
  // Add plugin to remove hashes from lazy styles.
68
70
  extraPlugins.push(new plugins_1.RemoveHashPlugin({ chunkNames: noInjectNames, hashFormat }));
@@ -78,7 +80,14 @@ function getStylesConfig(wco) {
78
80
  `To opt-out of the deprecated behaviour and start using 'sass' uninstall 'node-sass'.`);
79
81
  }
80
82
  catch {
81
- sassImplementation = require('sass');
83
+ sassImplementation = new sass_service_1.SassWorkerImplementation();
84
+ extraPlugins.push({
85
+ apply(compiler) {
86
+ compiler.hooks.shutdown.tap('sass-worker', () => {
87
+ sassImplementation === null || sassImplementation === void 0 ? void 0 : sassImplementation.close();
88
+ });
89
+ },
90
+ });
82
91
  }
83
92
  const assetNameTemplate = helpers_1.assetNameTemplateFactory(hashFormat);
84
93
  const extraPostcssPlugins = [];
@@ -115,6 +124,11 @@ function getStylesConfig(wco) {
115
124
  }
116
125
  }
117
126
  const { supportedBrowsers } = new build_browser_features_1.BuildBrowserFeatures(wco.projectRoot);
127
+ const postcssPresetEnvPlugin = postcssPresetEnv({
128
+ browsers: supportedBrowsers,
129
+ autoprefixer: true,
130
+ stage: 3,
131
+ });
118
132
  const postcssOptionsCreator = (inlineSourcemaps, extracted) => {
119
133
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
120
134
  const optionGenerator = (loader) => ({
@@ -150,11 +164,7 @@ function getStylesConfig(wco) {
150
164
  extracted,
151
165
  }),
152
166
  ...extraPostcssPlugins,
153
- postcssPresetEnv({
154
- browsers: supportedBrowsers,
155
- autoprefixer: true,
156
- stage: 3,
157
- }),
167
+ postcssPresetEnvPlugin,
158
168
  ],
159
169
  });
160
170
  // postcss-loader fails when trying to determine configuration files for data URIs
@@ -232,6 +242,8 @@ function getStylesConfig(wco) {
232
242
  implementation: sassImplementation,
233
243
  sourceMap: true,
234
244
  sassOptions: {
245
+ // Prevent use of `fibers` package as it no longer works in newer Node.js versions
246
+ fiber: false,
235
247
  // bootstrap-sass requires a minimum precision of 8
236
248
  precision: 8,
237
249
  includePaths,
@@ -340,11 +352,46 @@ function getStylesConfig(wco) {
340
352
  ],
341
353
  });
342
354
  }
355
+ const extraMinimizers = [];
356
+ if (buildOptions.optimization.styles.minify) {
357
+ const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
358
+ const minimizerOptions = {
359
+ preset: [
360
+ 'default',
361
+ {
362
+ // Disable SVG optimizations, as this can cause optimizations which are not compatible in all browsers.
363
+ svgo: false,
364
+ // Disable `calc` optimizations, due to several issues. #16910, #16875, #17890
365
+ calc: false,
366
+ // Disable CSS rules sorted due to several issues #20693, https://github.com/ionic-team/ionic-framework/issues/23266 and https://github.com/cssnano/cssnano/issues/1054
367
+ cssDeclarationSorter: false,
368
+ },
369
+ ],
370
+ };
371
+ const globalBundlesRegExp = new RegExp(`^(${Object.keys(entryPoints).join('|')})(\.[0-9a-f]{20})?.css$`);
372
+ extraMinimizers.push(new CssMinimizerPlugin({
373
+ // Component styles retain their original file name
374
+ test: /\.(?:css|scss|sass|less|styl)$/,
375
+ parallel: false,
376
+ exclude: globalBundlesRegExp,
377
+ minify: [CssMinimizerPlugin.cssnanoMinify],
378
+ minimizerOptions,
379
+ }), new CssMinimizerPlugin({
380
+ test: /\.css$/,
381
+ include: globalBundlesRegExp,
382
+ parallel: environment_options_1.maxWorkers,
383
+ minify: [CssMinimizerPlugin.cssnanoMinify],
384
+ minimizerOptions,
385
+ }));
386
+ }
343
387
  return {
344
388
  entry: entryPoints,
345
389
  module: {
346
390
  rules: [...fileLanguageRules, ...inlineLanguageRules],
347
391
  },
392
+ optimization: {
393
+ minimizer: extraMinimizers,
394
+ },
348
395
  plugins: extraPlugins,
349
396
  };
350
397
  }
@@ -40,7 +40,7 @@ class IndexHtmlWebpackPlugin extends index_html_generator_1.IndexHtmlGenerator {
40
40
  const moduleFiles = [];
41
41
  try {
42
42
  for (const [entryName, entrypoint] of this.compilation.entrypoints) {
43
- const entryFiles = (_a = entrypoint === null || entrypoint === void 0 ? void 0 : entrypoint.getFiles()) === null || _a === void 0 ? void 0 : _a.map((f) => ({
43
+ const entryFiles = (_a = entrypoint === null || entrypoint === void 0 ? void 0 : entrypoint.getFiles()) === null || _a === void 0 ? void 0 : _a.filter((f) => !f.endsWith('.hot-update.js')).map((f) => ({
44
44
  name: entryName,
45
45
  file: f,
46
46
  extension: path_1.extname(f),
@@ -6,7 +6,6 @@
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
8
  export { AnyComponentStyleBudgetChecker } from './any-component-style-budget-checker';
9
- export { OptimizeCssWebpackPlugin, OptimizeCssWebpackPluginOptions, } from './optimize-css-webpack-plugin';
10
9
  export { ScriptsWebpackPlugin, ScriptsWebpackPluginOptions } from './scripts-webpack-plugin';
11
10
  export { SuppressExtractedTextChunksWebpackPlugin } from './suppress-entry-chunks-webpack-plugin';
12
11
  export { RemoveHashPlugin, RemoveHashPluginOptions } from './remove-hash-plugin';
@@ -7,12 +7,10 @@
7
7
  * found in the LICENSE file at https://angular.io/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.PostcssCliResources = exports.CommonJsUsageWarnPlugin = exports.DedupeModuleResolvePlugin = exports.RemoveHashPlugin = exports.SuppressExtractedTextChunksWebpackPlugin = exports.ScriptsWebpackPlugin = exports.OptimizeCssWebpackPlugin = exports.AnyComponentStyleBudgetChecker = void 0;
10
+ exports.PostcssCliResources = exports.CommonJsUsageWarnPlugin = exports.DedupeModuleResolvePlugin = exports.RemoveHashPlugin = exports.SuppressExtractedTextChunksWebpackPlugin = exports.ScriptsWebpackPlugin = exports.AnyComponentStyleBudgetChecker = void 0;
11
11
  // Exports the webpack plugins we use internally.
12
12
  var any_component_style_budget_checker_1 = require("./any-component-style-budget-checker");
13
13
  Object.defineProperty(exports, "AnyComponentStyleBudgetChecker", { enumerable: true, get: function () { return any_component_style_budget_checker_1.AnyComponentStyleBudgetChecker; } });
14
- var optimize_css_webpack_plugin_1 = require("./optimize-css-webpack-plugin");
15
- Object.defineProperty(exports, "OptimizeCssWebpackPlugin", { enumerable: true, get: function () { return optimize_css_webpack_plugin_1.OptimizeCssWebpackPlugin; } });
16
14
  var scripts_webpack_plugin_1 = require("./scripts-webpack-plugin");
17
15
  Object.defineProperty(exports, "ScriptsWebpackPlugin", { enumerable: true, get: function () { return scripts_webpack_plugin_1.ScriptsWebpackPlugin; } });
18
16
  var suppress_entry_chunks_webpack_plugin_1 = require("./suppress-entry-chunks-webpack-plugin");
@@ -9,6 +9,7 @@ Reloaded before every execution run.
9
9
  <title></title>
10
10
  <base href="/" />
11
11
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
12
+ <link rel="stylesheet" href="_karma_webpack_/styles.css" crossorigin="anonymous" />
12
13
  <meta
13
14
  name="viewport"
14
15
  content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
@@ -34,7 +35,6 @@ Reloaded before every execution run.
34
35
  <script src="_karma_webpack_/polyfills.js" crossorigin="anonymous"></script>
35
36
  <!-- Dynamically replaced with <script> tags -->
36
37
  %SCRIPTS%
37
- <script src="_karma_webpack_/styles.js" crossorigin="anonymous"></script>
38
38
  <script src="_karma_webpack_/scripts.js" crossorigin="anonymous"></script>
39
39
  <script src="_karma_webpack_/vendor.js" crossorigin="anonymous"></script>
40
40
  <script src="_karma_webpack_/main.js" crossorigin="anonymous"></script>
@@ -10,6 +10,7 @@ just for immediate execution, without reporting to Karma server.
10
10
  <title>Karma DEBUG RUNNER</title>
11
11
  <base href="/" />
12
12
  <link href="favicon.ico" rel="icon" type="image/x-icon" />
13
+ <link rel="stylesheet" href="_karma_webpack_/styles.css" crossorigin="anonymous" />
13
14
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
14
15
  <meta
15
16
  name="viewport"
@@ -36,7 +37,6 @@ just for immediate execution, without reporting to Karma server.
36
37
  <script src="_karma_webpack_/polyfills.js" crossorigin="anonymous"></script>
37
38
  <!-- Dynamically replaced with <script> tags -->
38
39
  %SCRIPTS%
39
- <script src="_karma_webpack_/styles.js" crossorigin="anonymous"></script>
40
40
  <script src="_karma_webpack_/scripts.js" crossorigin="anonymous"></script>
41
41
  <script src="_karma_webpack_/vendor.js" crossorigin="anonymous"></script>
42
42
  <script src="_karma_webpack_/main.js" crossorigin="anonymous"></script>
@@ -248,7 +248,7 @@ function fallbackMiddleware() {
248
248
  `/${KARMA_APPLICATION_PATH}/polyfills.js`,
249
249
  `/${KARMA_APPLICATION_PATH}/polyfills-es5.js`,
250
250
  `/${KARMA_APPLICATION_PATH}/scripts.js`,
251
- `/${KARMA_APPLICATION_PATH}/styles.js`,
251
+ `/${KARMA_APPLICATION_PATH}/styles.css`,
252
252
  `/${KARMA_APPLICATION_PATH}/vendor.js`,
253
253
  ];
254
254
  if (request.url && alwaysServe.includes(request.url)) {
@@ -83,7 +83,7 @@ function default_1(options) {
83
83
  }
84
84
  loader.addDependency(result);
85
85
  if (emitFile) {
86
- loader.emitFile(outputPath, content, undefined);
86
+ loader.emitFile(outputPath, content, undefined, { sourceFilename: result });
87
87
  }
88
88
  let outputUrl = outputPath.replace(/\\/g, '/');
89
89
  if (hash || search) {