@angular-devkit/build-angular 17.0.5 → 17.1.0-next.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 (45) hide show
  1. package/package.json +26 -26
  2. package/src/builders/app-shell/index.js +2 -2
  3. package/src/builders/application/options.d.ts +1 -0
  4. package/src/builders/application/options.js +14 -0
  5. package/src/builders/application/schema.d.ts +16 -1
  6. package/src/builders/application/schema.json +13 -1
  7. package/src/builders/browser/schema.d.ts +2 -1
  8. package/src/builders/browser/schema.json +1 -1
  9. package/src/builders/browser-esbuild/schema.d.ts +2 -1
  10. package/src/builders/browser-esbuild/schema.json +1 -1
  11. package/src/builders/dev-server/builder.d.ts +2 -0
  12. package/src/builders/dev-server/vite-server.d.ts +3 -2
  13. package/src/builders/dev-server/vite-server.js +39 -10
  14. package/src/builders/jest/index.js +1 -1
  15. package/src/builders/jest/test-files.js +1 -1
  16. package/src/builders/prerender/index.js +0 -2
  17. package/src/builders/ssr-dev-server/utils.d.ts +2 -0
  18. package/src/tools/babel/plugins/adjust-static-class-members.d.ts +2 -0
  19. package/src/tools/babel/plugins/adjust-typescript-enums.d.ts +2 -0
  20. package/src/tools/babel/plugins/elide-angular-metadata.d.ts +2 -0
  21. package/src/tools/babel/plugins/pure-toplevel-functions.d.ts +2 -0
  22. package/src/tools/babel/presets/application.js +1 -1
  23. package/src/tools/esbuild/angular/compilation/parallel-compilation.js +0 -2
  24. package/src/tools/esbuild/angular/compilation/parallel-worker.d.ts +2 -0
  25. package/src/tools/esbuild/application-code-bundle.js +2 -1
  26. package/src/tools/esbuild/commonjs-checker.d.ts +1 -1
  27. package/src/tools/esbuild/commonjs-checker.js +4 -1
  28. package/src/tools/esbuild/global-styles.js +5 -1
  29. package/src/tools/esbuild/i18n-inliner.js +0 -2
  30. package/src/tools/esbuild/index-html-generator.js +1 -1
  31. package/src/tools/esbuild/javascript-transformer.js +0 -2
  32. package/src/tools/esbuild/watcher.js +74 -13
  33. package/src/tools/webpack/configs/common.js +1 -1
  34. package/src/tools/webpack/plugins/common-js-usage-warn-plugin.d.ts +1 -1
  35. package/src/tools/webpack/plugins/common-js-usage-warn-plugin.js +3 -0
  36. package/src/tools/webpack/plugins/javascript-optimizer-plugin.js +0 -2
  37. package/src/tools/webpack/utils/helpers.js +7 -7
  38. package/src/utils/action-executor.js +0 -2
  39. package/src/utils/environment-options.js +1 -3
  40. package/src/utils/normalize-optimization.d.ts +1 -1
  41. package/src/utils/normalize-optimization.js +5 -2
  42. package/src/utils/server-rendering/esm-in-memory-loader/node-18-utils.js +1 -1
  43. package/src/utils/server-rendering/prerender.js +0 -4
  44. package/src/utils/server-rendering/render-page.js +1 -1
  45. package/src/utils/service-worker.d.ts +2 -0
package/package.json CHANGED
@@ -1,27 +1,27 @@
1
1
  {
2
2
  "name": "@angular-devkit/build-angular",
3
- "version": "17.0.5",
3
+ "version": "17.1.0-next.0",
4
4
  "description": "Angular Webpack Build Facade",
5
5
  "main": "src/index.js",
6
6
  "typings": "src/index.d.ts",
7
7
  "builders": "builders.json",
8
8
  "dependencies": {
9
9
  "@ampproject/remapping": "2.2.1",
10
- "@angular-devkit/architect": "0.1700.5",
11
- "@angular-devkit/build-webpack": "0.1700.5",
12
- "@angular-devkit/core": "17.0.5",
13
- "@babel/core": "7.23.2",
14
- "@babel/generator": "7.23.0",
10
+ "@angular-devkit/architect": "0.1701.0-next.0",
11
+ "@angular-devkit/build-webpack": "0.1701.0-next.0",
12
+ "@angular-devkit/core": "17.1.0-next.0",
13
+ "@babel/core": "7.23.5",
14
+ "@babel/generator": "7.23.5",
15
15
  "@babel/helper-annotate-as-pure": "7.22.5",
16
16
  "@babel/helper-split-export-declaration": "7.22.6",
17
- "@babel/plugin-transform-async-generator-functions": "7.23.2",
18
- "@babel/plugin-transform-async-to-generator": "7.22.5",
19
- "@babel/plugin-transform-runtime": "7.23.2",
20
- "@babel/preset-env": "7.23.2",
21
- "@babel/runtime": "7.23.2",
17
+ "@babel/plugin-transform-async-generator-functions": "7.23.4",
18
+ "@babel/plugin-transform-async-to-generator": "7.23.3",
19
+ "@babel/plugin-transform-runtime": "7.23.4",
20
+ "@babel/preset-env": "7.23.5",
21
+ "@babel/runtime": "7.23.5",
22
22
  "@discoveryjs/json-ext": "0.5.7",
23
- "@ngtools/webpack": "17.0.5",
24
- "@vitejs/plugin-basic-ssl": "1.0.1",
23
+ "@ngtools/webpack": "17.1.0-next.0",
24
+ "@vitejs/plugin-basic-ssl": "1.0.2",
25
25
  "ansi-colors": "4.1.3",
26
26
  "autoprefixer": "10.4.16",
27
27
  "babel-loader": "9.1.3",
@@ -32,11 +32,11 @@
32
32
  "copy-webpack-plugin": "11.0.0",
33
33
  "critters": "0.0.20",
34
34
  "css-loader": "6.8.1",
35
- "esbuild-wasm": "0.19.5",
36
- "fast-glob": "3.3.1",
35
+ "esbuild-wasm": "0.19.8",
36
+ "fast-glob": "3.3.2",
37
37
  "https-proxy-agent": "7.0.2",
38
38
  "http-proxy-middleware": "2.0.6",
39
- "inquirer": "9.2.11",
39
+ "inquirer": "9.2.12",
40
40
  "jsonc-parser": "3.2.0",
41
41
  "karma-source-map-support": "1.4.0",
42
42
  "less": "4.2.0",
@@ -50,7 +50,7 @@
50
50
  "ora": "5.4.1",
51
51
  "parse5-html-rewriting-stream": "7.0.0",
52
52
  "picomatch": "3.0.1",
53
- "piscina": "4.1.0",
53
+ "piscina": "4.2.0",
54
54
  "postcss": "8.4.31",
55
55
  "postcss-loader": "7.3.3",
56
56
  "resolve-url-loader": "5.0.0",
@@ -64,8 +64,8 @@
64
64
  "text-table": "0.2.0",
65
65
  "tree-kill": "1.2.2",
66
66
  "tslib": "2.6.2",
67
- "undici": "5.27.2",
68
- "vite": "4.5.0",
67
+ "undici": "5.28.1",
68
+ "vite": "5.0.4",
69
69
  "webpack": "5.89.0",
70
70
  "webpack-dev-middleware": "6.1.1",
71
71
  "webpack-dev-server": "4.15.1",
@@ -73,20 +73,20 @@
73
73
  "webpack-subresource-integrity": "5.1.0"
74
74
  },
75
75
  "optionalDependencies": {
76
- "esbuild": "0.19.5"
76
+ "esbuild": "0.19.8"
77
77
  },
78
78
  "peerDependencies": {
79
- "@angular/compiler-cli": "^17.0.0",
80
- "@angular/localize": "^17.0.0",
81
- "@angular/platform-server": "^17.0.0",
82
- "@angular/service-worker": "^17.0.0",
79
+ "@angular/compiler-cli": "^17.0.0 || ^17.1.0-next.0",
80
+ "@angular/localize": "^17.0.0 || ^17.1.0-next.0",
81
+ "@angular/platform-server": "^17.0.0 || ^17.1.0-next.0",
82
+ "@angular/service-worker": "^17.0.0 || ^17.1.0-next.0",
83
83
  "jest": "^29.5.0",
84
84
  "jest-environment-jsdom": "^29.5.0",
85
85
  "karma": "^6.3.0",
86
- "ng-packagr": "^17.0.0",
86
+ "ng-packagr": "^17.0.0 || ^17.1.0-next.0",
87
87
  "protractor": "^7.0.0",
88
88
  "tailwindcss": "^2.0.0 || ^3.0.0",
89
- "typescript": ">=5.2 <5.3"
89
+ "typescript": ">=5.2 <5.4"
90
90
  },
91
91
  "peerDependenciesMeta": {
92
92
  "@angular/localize": {
@@ -104,8 +104,6 @@ async function _renderUniversal(options, context, browserResult, serverResult, s
104
104
  }
105
105
  }
106
106
  finally {
107
- // Workaround piscina bug where a worker thread will be recreated after destroy to meet the minimum.
108
- renderWorker.options.minThreads = 0;
109
107
  await renderWorker.destroy();
110
108
  }
111
109
  return browserResult;
@@ -134,6 +132,8 @@ async function _appShellBuilder(options, context) {
134
132
  const browserOptions = (await context.getTargetOptions(browserTarget));
135
133
  const optimization = (0, utils_1.normalizeOptimization)(browserOptions.optimization);
136
134
  optimization.styles.inlineCritical = false;
135
+ // Webpack based builders do not have the `removeSpecialComments` option.
136
+ delete optimization.styles.removeSpecialComments;
137
137
  const browserTargetRun = await context.scheduleTarget(browserTarget, {
138
138
  watch: false,
139
139
  serviceWorker: false,
@@ -127,5 +127,6 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
127
127
  budgets: import("./schema").Budget[] | undefined;
128
128
  publicPath: string | undefined;
129
129
  plugins: Plugin[] | undefined;
130
+ loaderExtensions: Record<string, "binary" | "file" | "text"> | undefined;
130
131
  }>;
131
132
  export {};
@@ -88,6 +88,19 @@ async function normalizeOptions(context, projectName, options, plugins) {
88
88
  fileReplacements[node_path_1.default.join(workspaceRoot, replacement.replace)] = fileReplaceWith;
89
89
  }
90
90
  }
91
+ let loaderExtensions;
92
+ if (options.loader) {
93
+ for (const [extension, value] of Object.entries(options.loader)) {
94
+ if (extension[0] !== '.' || /\.[cm]?[jt]sx?$/.test(extension)) {
95
+ continue;
96
+ }
97
+ if (value !== 'text' && value !== 'binary' && value !== 'file' && value !== 'empty') {
98
+ continue;
99
+ }
100
+ loaderExtensions ??= {};
101
+ loaderExtensions[extension] = value;
102
+ }
103
+ }
91
104
  const globalStyles = [];
92
105
  if (options.styles?.length) {
93
106
  const { entryPoints: stylesheetEntrypoints, noInjectNames } = (0, helpers_1.normalizeGlobalStyles)(options.styles || []);
@@ -213,6 +226,7 @@ async function normalizeOptions(context, projectName, options, plugins) {
213
226
  budgets: budgets?.length ? budgets : undefined,
214
227
  publicPath: deployUrl ? deployUrl : undefined,
215
228
  plugins: plugins?.length ? plugins : undefined,
229
+ loaderExtensions,
216
230
  };
217
231
  }
218
232
  exports.normalizeOptions = normalizeOptions;
@@ -3,7 +3,8 @@
3
3
  */
4
4
  export interface Schema {
5
5
  /**
6
- * A list of CommonJS packages that are allowed to be used without a build time warning.
6
+ * A list of CommonJS or AMD packages that are allowed to be used without a build time
7
+ * warning. Use `'*'` to allow all.
7
8
  */
8
9
  allowedCommonJsDependencies?: string[];
9
10
  /**
@@ -69,6 +70,15 @@ export interface Schema {
69
70
  * The stylesheet language to use for the application's inline component styles.
70
71
  */
71
72
  inlineStyleLanguage?: InlineStyleLanguage;
73
+ /**
74
+ * Defines the type of loader to use with a specified file extension when used with a
75
+ * JavaScript `import`. `text` inlines the content as a string; `binary` inlines the content
76
+ * as a Uint8Array; `file` emits the file and provides the runtime location of the file;
77
+ * `empty` considers the content to be empty and not include it in bundles.
78
+ */
79
+ loader?: {
80
+ [key: string]: any;
81
+ };
72
82
  /**
73
83
  * Translate the bundles in one or more locales.
74
84
  */
@@ -344,6 +354,11 @@ export interface StylesClass {
344
354
  * identifiers and minimizing values.
345
355
  */
346
356
  minify?: boolean;
357
+ /**
358
+ * Remove comments in global CSS that contains '@license' or '@preserve' or that starts with
359
+ * '//!' or '/*!'.
360
+ */
361
+ removeSpecialComments?: boolean;
347
362
  }
348
363
  /**
349
364
  * Define the output filename cache-busting hashing mode.
@@ -162,6 +162,11 @@
162
162
  "type": "boolean",
163
163
  "description": "Extract and inline critical CSS definitions to improve first paint time.",
164
164
  "default": true
165
+ },
166
+ "removeSpecialComments": {
167
+ "type": "boolean",
168
+ "description": "Remove comments in global CSS that contains '@license' or '@preserve' or that starts with '//!' or '/*!'.",
169
+ "default": true
165
170
  }
166
171
  },
167
172
  "additionalProperties": false
@@ -199,6 +204,13 @@
199
204
  }
200
205
  ]
201
206
  },
207
+ "loader": {
208
+ "description": "Defines the type of loader to use with a specified file extension when used with a JavaScript `import`. `text` inlines the content as a string; `binary` inlines the content as a Uint8Array; `file` emits the file and provides the runtime location of the file; `empty` considers the content to be empty and not include it in bundles.",
209
+ "type": "object",
210
+ "patternProperties": {
211
+ "^\\.\\S+$": { "enum": ["text", "binary", "file", "empty"] }
212
+ }
213
+ },
202
214
  "fileReplacements": {
203
215
  "description": "Replace compilation source files with other compilation source files in the build.",
204
216
  "type": "array",
@@ -406,7 +418,7 @@
406
418
  "enum": ["none", "anonymous", "use-credentials"]
407
419
  },
408
420
  "allowedCommonJsDependencies": {
409
- "description": "A list of CommonJS packages that are allowed to be used without a build time warning.",
421
+ "description": "A list of CommonJS or AMD packages that are allowed to be used without a build time warning. Use `'*'` to allow all.",
410
422
  "type": "array",
411
423
  "items": {
412
424
  "type": "string"
@@ -3,7 +3,8 @@
3
3
  */
4
4
  export interface Schema {
5
5
  /**
6
- * A list of CommonJS packages that are allowed to be used without a build time warning.
6
+ * A list of CommonJS or AMD packages that are allowed to be used without a build time
7
+ * warning. Use `'*'` to allow all.
7
8
  */
8
9
  allowedCommonJsDependencies?: string[];
9
10
  /**
@@ -417,7 +417,7 @@
417
417
  "enum": ["none", "anonymous", "use-credentials"]
418
418
  },
419
419
  "allowedCommonJsDependencies": {
420
- "description": "A list of CommonJS packages that are allowed to be used without a build time warning.",
420
+ "description": "A list of CommonJS or AMD packages that are allowed to be used without a build time warning. Use `'*'` to allow all.",
421
421
  "type": "array",
422
422
  "items": {
423
423
  "type": "string"
@@ -3,7 +3,8 @@
3
3
  */
4
4
  export interface Schema {
5
5
  /**
6
- * A list of CommonJS packages that are allowed to be used without a build time warning.
6
+ * A list of CommonJS or AMD packages that are allowed to be used without a build time
7
+ * warning. Use `'*'` to allow all.
7
8
  */
8
9
  allowedCommonJsDependencies?: string[];
9
10
  /**
@@ -429,7 +429,7 @@
429
429
  "enum": ["none", "anonymous", "use-credentials"]
430
430
  },
431
431
  "allowedCommonJsDependencies": {
432
- "description": "A list of CommonJS packages that are allowed to be used without a build time warning.",
432
+ "description": "A list of CommonJS or AMD packages that are allowed to be used without a build time warning. Use `'*'` to allow all.",
433
433
  "type": "array",
434
434
  "items": {
435
435
  "type": "string"
@@ -6,6 +6,8 @@
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
8
  /// <reference types="node" />
9
+ /// <reference types="@types/node/http" />
10
+ /// <reference types="@types/node/ts4.8/http" />
9
11
  import type { BuilderContext } from '@angular-devkit/architect';
10
12
  import type { Plugin } from 'esbuild';
11
13
  import type http from 'node:http';
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import type { BuilderContext } from '@angular-devkit/architect';
9
9
  import type { Plugin } from 'esbuild';
10
- import type { Connect, InlineConfig } from 'vite';
10
+ import type { Connect, DepOptimizationConfig, InlineConfig } from 'vite';
11
11
  import { ExternalResultMetadata } from '../../tools/esbuild/bundler-execution-result';
12
12
  import { JavaScriptTransformer } from '../../tools/esbuild/javascript-transformer';
13
13
  import type { NormalizedDevServerOptions } from './options';
@@ -25,5 +25,6 @@ export declare function serveWithVite(serverOptions: NormalizedDevServerOptions,
25
25
  middleware?: Connect.NextHandleFunction[];
26
26
  buildPlugins?: Plugin[];
27
27
  }): AsyncIterableIterator<DevServerBuilderOutput>;
28
- export declare function setupServer(serverOptions: NormalizedDevServerOptions, outputFiles: Map<string, OutputFileRecord>, assets: Map<string, string>, preserveSymlinks: boolean | undefined, externalMetadata: ExternalResultMetadata, ssr: boolean, prebundleTransformer: JavaScriptTransformer, target: string[], extensionMiddleware?: Connect.NextHandleFunction[], indexHtmlTransformer?: (content: string) => Promise<string>, thirdPartySourcemaps?: boolean): Promise<InlineConfig>;
28
+ export declare function setupServer(serverOptions: NormalizedDevServerOptions, outputFiles: Map<string, OutputFileRecord>, assets: Map<string, string>, preserveSymlinks: boolean | undefined, externalMetadata: ExternalResultMetadata, ssr: boolean, prebundleTransformer: JavaScriptTransformer, target: string[], prebundleLoaderExtensions: EsbuildLoaderOption | undefined, extensionMiddleware?: Connect.NextHandleFunction[], indexHtmlTransformer?: (content: string) => Promise<string>, thirdPartySourcemaps?: boolean): Promise<InlineConfig>;
29
+ type EsbuildLoaderOption = Exclude<DepOptimizationConfig['esbuildOptions'], undefined>['loader'];
29
30
  export {};
@@ -45,6 +45,7 @@ const rxjs_esm_resolution_plugin_1 = require("../../tools/esbuild/rxjs-esm-resol
45
45
  const utils_1 = require("../../tools/esbuild/utils");
46
46
  const i18n_locale_plugin_1 = require("../../tools/vite/i18n-locale-plugin");
47
47
  const utils_2 = require("../../utils");
48
+ const load_esm_1 = require("../../utils/load-esm");
48
49
  const render_page_1 = require("../../utils/server-rendering/render-page");
49
50
  const supported_browsers_1 = require("../../utils/supported-browsers");
50
51
  const webpack_browser_config_1 = require("../../utils/webpack-browser-config");
@@ -99,7 +100,7 @@ async function* serveWithVite(serverOptions, builderName, context, transformers,
99
100
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
101
  const htmlIndexPath = (0, webpack_browser_config_1.getIndexOutputFile)(browserOptions.index);
101
102
  // dynamically import Vite for ESM compatibility
102
- const { createServer, normalizePath } = await Promise.resolve().then(() => __importStar(require('vite')));
103
+ const { createServer, normalizePath } = await (0, load_esm_1.loadEsmModule)('vite');
103
104
  let server;
104
105
  let serverUrl;
105
106
  let hadError = false;
@@ -176,6 +177,10 @@ async function* serveWithVite(serverOptions, builderName, context, transformers,
176
177
  externalMetadata.implicitBrowser.sort();
177
178
  }
178
179
  if (server) {
180
+ // Update fs allow list to include any new assets from the build option.
181
+ server.config.server.fs.allow = [
182
+ ...new Set(...server.config.server.fs.allow, ...assetFiles.values()),
183
+ ];
179
184
  handleUpdate(normalizePath, generatedFiles, server, serverOptions, context.logger);
180
185
  }
181
186
  else {
@@ -188,7 +193,7 @@ async function* serveWithVite(serverOptions, builderName, context, transformers,
188
193
  const browsers = (0, supported_browsers_1.getSupportedBrowsers)(projectRoot, context.logger);
189
194
  const target = (0, utils_1.transformSupportedBrowsersToTargets)(browsers);
190
195
  // Setup server and start listening
191
- const serverConfiguration = await setupServer(serverOptions, generatedFiles, assetFiles, browserOptions.preserveSymlinks, externalMetadata, !!browserOptions.ssr, prebundleTransformer, target, extensions?.middleware, transformers?.indexHtml, thirdPartySourcemaps);
196
+ const serverConfiguration = await setupServer(serverOptions, generatedFiles, assetFiles, browserOptions.preserveSymlinks, externalMetadata, !!browserOptions.ssr, prebundleTransformer, target, browserOptions.loader, extensions?.middleware, transformers?.indexHtml, thirdPartySourcemaps);
192
197
  server = await createServer(serverConfiguration);
193
198
  await server.listen();
194
199
  if (serverConfiguration.ssr?.optimizeDeps?.disabled === false) {
@@ -208,6 +213,21 @@ async function* serveWithVite(serverOptions, builderName, context, transformers,
208
213
  }
209
214
  // log connection information
210
215
  server.printUrls();
216
+ server.bindCLIShortcuts({
217
+ print: true,
218
+ customShortcuts: [
219
+ {
220
+ key: 'r',
221
+ description: 'force reload browser',
222
+ action(server) {
223
+ server.ws.send({
224
+ type: 'full-reload',
225
+ path: '*',
226
+ });
227
+ },
228
+ },
229
+ ],
230
+ });
211
231
  }
212
232
  // TODO: adjust output typings to reflect both development servers
213
233
  yield {
@@ -307,20 +327,21 @@ function analyzeResultFiles(normalizePath, htmlIndexPath, resultFiles, generated
307
327
  }
308
328
  }
309
329
  // eslint-disable-next-line max-lines-per-function
310
- async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks, externalMetadata, ssr, prebundleTransformer, target, extensionMiddleware, indexHtmlTransformer, thirdPartySourcemaps = false) {
330
+ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks, externalMetadata, ssr, prebundleTransformer, target, prebundleLoaderExtensions, extensionMiddleware, indexHtmlTransformer, thirdPartySourcemaps = false) {
311
331
  const proxy = await (0, load_proxy_config_1.loadProxyConfiguration)(serverOptions.workspaceRoot, serverOptions.proxyConfig, true);
312
332
  // dynamically import Vite for ESM compatibility
313
- const { normalizePath } = await Promise.resolve().then(() => __importStar(require('vite')));
333
+ const { normalizePath } = await (0, load_esm_1.loadEsmModule)('vite');
314
334
  // Path will not exist on disk and only used to provide separate path for Vite requests
315
335
  const virtualProjectRoot = normalizePath((0, node_path_1.join)(serverOptions.workspaceRoot, `.angular/vite-root`, serverOptions.buildTarget.project));
316
336
  const serverExplicitExternal = [
317
337
  ...(await Promise.resolve().then(() => __importStar(require('node:module')))).builtinModules,
318
338
  ...externalMetadata.explicit,
319
339
  ];
340
+ const cacheDir = (0, node_path_1.join)(serverOptions.cacheOptions.path, 'vite');
320
341
  const configuration = {
321
342
  configFile: false,
322
343
  envFile: false,
323
- cacheDir: (0, node_path_1.join)(serverOptions.cacheOptions.path, 'vite'),
344
+ cacheDir,
324
345
  root: virtualProjectRoot,
325
346
  publicDir: false,
326
347
  esbuild: false,
@@ -342,9 +363,14 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
342
363
  open: serverOptions.open,
343
364
  headers: serverOptions.headers,
344
365
  proxy,
345
- // Currently does not appear to be a way to disable file watching directly so ignore all files
346
- watch: {
347
- ignored: ['**/*'],
366
+ // File watching is handled by the build directly. `null` disables file watching for Vite.
367
+ watch: null,
368
+ fs: {
369
+ // Ensure cache directory, node modules, and all assets are accessible by the client.
370
+ // The first two are required for Vite to function in prebundling mode (the default) and to load
371
+ // the Vite client-side code for browser reloading. These would be available by default but when
372
+ // the `allow` option is explicitly configured, they must be included manually.
373
+ allow: [cacheDir, (0, node_path_1.join)(serverOptions.workspaceRoot, 'node_modules'), ...assets.values()],
348
374
  },
349
375
  // This is needed when `externalDependencies` is used to prevent Vite load errors.
350
376
  // NOTE: If Vite adds direct support for externals, this can be removed.
@@ -367,7 +393,7 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
367
393
  * - Breaks RxJs (Unless it is added as external). See: https://github.com/angular/angular-cli/issues/26235
368
394
  */
369
395
  // Only enable with caching since it causes prebundle dependencies to be cached
370
- disabled: true,
396
+ disabled: true, // !serverOptions.cacheOptions.enabled,
371
397
  // Exclude any explicitly defined dependencies (currently build defined externals and node.js built-ins)
372
398
  exclude: serverExplicitExternal,
373
399
  // Include all implict dependencies from the external packages internal option
@@ -375,6 +401,7 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
375
401
  ssr: true,
376
402
  prebundleTransformer,
377
403
  target,
404
+ loader: prebundleLoaderExtensions,
378
405
  thirdPartySourcemaps,
379
406
  }),
380
407
  },
@@ -573,6 +600,7 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
573
600
  ssr: false,
574
601
  prebundleTransformer,
575
602
  target,
603
+ loader: prebundleLoaderExtensions,
576
604
  thirdPartySourcemaps,
577
605
  }),
578
606
  };
@@ -619,7 +647,7 @@ function pathnameWithoutBasePath(url, basePath) {
619
647
  ? pathname.slice(basePath.length - 1)
620
648
  : pathname;
621
649
  }
622
- function getDepOptimizationConfig({ disabled, exclude, include, target, prebundleTransformer, ssr, thirdPartySourcemaps, }) {
650
+ function getDepOptimizationConfig({ disabled, exclude, include, target, prebundleTransformer, ssr, loader, thirdPartySourcemaps, }) {
623
651
  const plugins = [
624
652
  {
625
653
  name: `angular-vite-optimize-deps${ssr ? '-ssr' : ''}${thirdPartySourcemaps ? '-vendor-sourcemap' : ''}`,
@@ -649,6 +677,7 @@ function getDepOptimizationConfig({ disabled, exclude, include, target, prebundl
649
677
  target,
650
678
  supported: (0, utils_1.getFeatureSupport)(target),
651
679
  plugins,
680
+ loader,
652
681
  },
653
682
  };
654
683
  }
@@ -78,7 +78,7 @@ exports.default = (0, architect_1.createBuilder)(async (schema, context) => {
78
78
  aot: false,
79
79
  index: false,
80
80
  outputHashing: schema_1.OutputHashing.None,
81
- outExtension: 'mjs',
81
+ outExtension: 'mjs', // Force native ESM.
82
82
  optimization: false,
83
83
  sourceMap: {
84
84
  scripts: true,
@@ -25,7 +25,7 @@ async function findTestFiles(options, workspaceRoot, glob = fast_glob_1.default)
25
25
  const globOptions = {
26
26
  cwd: workspaceRoot,
27
27
  ignore: ['node_modules/**'].concat(options.exclude),
28
- braceExpansion: false,
28
+ braceExpansion: false, // Do not expand `a{b,c}` to `ab,ac`.
29
29
  extglob: false, // Disable "extglob" patterns.
30
30
  };
31
31
  const included = await Promise.all(options.include.map((pattern) => glob(pattern, globOptions)));
@@ -191,8 +191,6 @@ async function _renderUniversal(options, context, browserResult, serverResult, b
191
191
  }
192
192
  }
193
193
  finally {
194
- // Workaround piscina bug where a worker thread will be recreated after destroy to meet the minimum.
195
- worker.options.minThreads = 0;
196
194
  void worker.destroy();
197
195
  }
198
196
  return browserResult;
@@ -5,6 +5,8 @@
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
+ /// <reference types="@types/node/child_process" />
9
+ /// <reference types="@types/node/ts4.8/child_process" />
8
10
  import { SpawnOptions } from 'child_process';
9
11
  import { Observable } from 'rxjs';
10
12
  export declare function getAvailablePort(): Promise<number>;
@@ -5,6 +5,8 @@
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
+ /// <reference path="../../../../../../../../../../packages/angular_devkit/build_angular/src/babel-bazel.d.ts" />
9
+ /// <reference types="@angular/compiler-cli/private/babel" />
8
10
  import { PluginObj } from '@babel/core';
9
11
  /**
10
12
  * Provides one or more keywords that if found within the content of a source file indicate
@@ -5,6 +5,8 @@
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
+ /// <reference path="../../../../../../../../../../packages/angular_devkit/build_angular/src/babel-bazel.d.ts" />
9
+ /// <reference types="@angular/compiler-cli/private/babel" />
8
10
  import { PluginObj } from '@babel/core';
9
11
  /**
10
12
  * Provides one or more keywords that if found within the content of a source file indicate
@@ -5,6 +5,8 @@
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
+ /// <reference path="../../../../../../../../../../packages/angular_devkit/build_angular/src/babel-bazel.d.ts" />
9
+ /// <reference types="@angular/compiler-cli/private/babel" />
8
10
  import { PluginObj } from '@babel/core';
9
11
  /**
10
12
  * Provides one or more keywords that if found within the content of a source file indicate
@@ -5,6 +5,8 @@
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
+ /// <reference path="../../../../../../../../../../packages/angular_devkit/build_angular/src/babel-bazel.d.ts" />
9
+ /// <reference types="@angular/compiler-cli/private/babel" />
8
10
  import { PluginObj } from '@babel/core';
9
11
  /**
10
12
  * A babel plugin factory function for adding the PURE annotation to top-level new and call expressions.
@@ -70,7 +70,7 @@ function createI18nPlugins(locale, translation, missingTranslationBehavior, diag
70
70
  }
71
71
  function createNgtscLogger(reporter) {
72
72
  return {
73
- level: 1,
73
+ level: 1, // Info level
74
74
  debug(...args) { },
75
75
  info(...args) {
76
76
  reporter?.('info', args.join());
@@ -116,8 +116,6 @@ class ParallelCompilation extends angular_compilation_1.AngularCompilation {
116
116
  return this.#worker.run(files, { name: 'update' });
117
117
  }
118
118
  close() {
119
- // Workaround piscina bug where a worker thread will be recreated after destroy to meet the minimum.
120
- this.#worker.options.minThreads = 0;
121
119
  return this.#worker.destroy();
122
120
  }
123
121
  }
@@ -6,6 +6,8 @@
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
8
  /// <reference types="node" />
9
+ /// <reference types="@types/node/worker_threads" />
10
+ /// <reference types="@types/node/ts4.8/worker_threads" />
9
11
  import type { PartialMessage } from 'esbuild';
10
12
  import { type MessagePort } from 'node:worker_threads';
11
13
  export interface InitRequest {
@@ -221,7 +221,7 @@ function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
221
221
  }
222
222
  exports.createServerPolyfillBundleOptions = createServerPolyfillBundleOptions;
223
223
  function getEsBuildCommonOptions(options) {
224
- const { workspaceRoot, outExtension, optimizationOptions, sourcemapOptions, tsconfig, externalDependencies, outputNames, preserveSymlinks, jit, } = options;
224
+ const { workspaceRoot, outExtension, optimizationOptions, sourcemapOptions, tsconfig, externalDependencies, outputNames, preserveSymlinks, jit, loaderExtensions, } = options;
225
225
  // Ensure unique hashes for i18n translation changes when using post-process inlining.
226
226
  // This hash value is added as a footer to each file and ensures that the output file names (with hashes)
227
227
  // change when translation files have changed. If this is not done the post processed files may have
@@ -262,6 +262,7 @@ function getEsBuildCommonOptions(options) {
262
262
  ...(optimizationOptions.scripts ? { 'ngDevMode': 'false' } : undefined),
263
263
  'ngJitMode': jit ? 'true' : 'false',
264
264
  },
265
+ loader: loaderExtensions,
265
266
  footer,
266
267
  publicPath: options.publicPath,
267
268
  };
@@ -15,7 +15,7 @@ import type { Metafile, PartialMessage } from 'esbuild';
15
15
  *
16
16
  * If any allowed dependencies are provided via the `allowedCommonJsDependencies`
17
17
  * parameter, both the direct import and any deep imports will be ignored and no
18
- * diagnostic will be generated.
18
+ * diagnostic will be generated. Use `'*'` as entry to skip the check.
19
19
  *
20
20
  * If a module has been issued a diagnostic message, then all descendant modules
21
21
  * will not be checked. This prevents a potential massive amount of inactionable
@@ -17,7 +17,7 @@ exports.checkCommonJSModules = void 0;
17
17
  *
18
18
  * If any allowed dependencies are provided via the `allowedCommonJsDependencies`
19
19
  * parameter, both the direct import and any deep imports will be ignored and no
20
- * diagnostic will be generated.
20
+ * diagnostic will be generated. Use `'*'` as entry to skip the check.
21
21
  *
22
22
  * If a module has been issued a diagnostic message, then all descendant modules
23
23
  * will not be checked. This prevents a potential massive amount of inactionable
@@ -30,6 +30,9 @@ exports.checkCommonJSModules = void 0;
30
30
  function checkCommonJSModules(metafile, allowedCommonJsDependencies) {
31
31
  const messages = [];
32
32
  const allowedRequests = new Set(allowedCommonJsDependencies);
33
+ if (allowedRequests.has('*')) {
34
+ return messages;
35
+ }
33
36
  // Ignore Angular locale definitions which are currently UMD
34
37
  allowedRequests.add('@angular/common/locales');
35
38
  // Ignore zone.js due to it currently being built with a UMD like structure.
@@ -47,7 +47,11 @@ function createGlobalStylesBundleOptions(options, target, initial) {
47
47
  tailwindConfiguration,
48
48
  publicPath: options.publicPath,
49
49
  }, loadCache);
50
- buildOptions.legalComments = options.extractLicenses ? 'none' : 'eof';
50
+ // Keep special CSS comments `/*! comment */` in place when `removeSpecialComments` is disabled.
51
+ // These comments are special for a number of CSS tools such as Critters and PurgeCSS.
52
+ buildOptions.legalComments = optimizationOptions.styles?.removeSpecialComments
53
+ ? 'none'
54
+ : 'inline';
51
55
  buildOptions.entryPoints = entryPoints;
52
56
  buildOptions.plugins.unshift((0, virtual_module_plugin_1.createVirtualModulePlugin)({
53
57
  namespace,
@@ -143,8 +143,6 @@ class I18nInliner {
143
143
  * @returns A void promise that resolves when closing is complete.
144
144
  */
145
145
  close() {
146
- // Workaround piscina bug where a worker thread will be recreated after destroy to meet the minimum.
147
- this.#workerPool.options.minThreads = 0;
148
146
  return this.#workerPool.destroy();
149
147
  }
150
148
  }
@@ -109,7 +109,7 @@ async function generateIndexHtml(initialFiles, outputFiles, buildOptions, lang)
109
109
  }
110
110
  const { InlineCriticalCssProcessor } = await Promise.resolve().then(() => __importStar(require('../../utils/index-file/inline-critical-css')));
111
111
  const inlineCriticalCssProcessor = new InlineCriticalCssProcessor({
112
- minify: false,
112
+ minify: false, // CSS has already been minified during the build.
113
113
  readAsset,
114
114
  });
115
115
  const { content, errors, warnings } = await inlineCriticalCssProcessor.process(contentWithoutCriticalCssInlined, {
@@ -105,8 +105,6 @@ class JavaScriptTransformer {
105
105
  async close() {
106
106
  this.#pendingfileResults?.clear();
107
107
  if (this.#workerPool) {
108
- // Workaround piscina bug where a worker thread will be recreated after destroy to meet the minimum.
109
- this.#workerPool.options.minThreads = 0;
110
108
  try {
111
109
  await this.#workerPool.destroy();
112
110
  }
@@ -9,6 +9,7 @@
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.createWatcher = exports.ChangedFiles = void 0;
11
11
  const chokidar_1 = require("chokidar");
12
+ const node_path_1 = require("node:path");
12
13
  class ChangedFiles {
13
14
  added = new Set();
14
15
  modified = new Set();
@@ -37,19 +38,64 @@ function createWatcher(options) {
37
38
  const nextQueue = [];
38
39
  let currentChanges;
39
40
  let nextWaitTimeout;
40
- watcher.on('all', (event, path) => {
41
+ /**
42
+ * We group the current events in a map as on Windows with certain IDE a file contents change can trigger multiple events.
43
+ *
44
+ * Example:
45
+ * rename | 'C:/../src/app/app.component.css'
46
+ * rename | 'C:/../src/app/app.component.css'
47
+ * change | 'C:/../src/app/app.component.css'
48
+ *
49
+ */
50
+ let currentEvents;
51
+ /**
52
+ * Using `watcher.on('all')` does not capture some of events fired when using Visual studio and this does not happen all the time,
53
+ * but only after a file has been changed 3 or more times.
54
+ *
55
+ * Also, some IDEs such as Visual Studio (not VS Code) will fire a rename event instead of unlink when a file is renamed or changed.
56
+ *
57
+ * Example:
58
+ * ```
59
+ * watcher.on('raw')
60
+ * Change 1
61
+ * rename | 'C:/../src/app/app.component.css'
62
+ * rename | 'C:/../src/app/app.component.css'
63
+ * change | 'C:/../src/app/app.component.css'
64
+ *
65
+ * Change 2
66
+ * rename | 'C:/../src/app/app.component.css'
67
+ * rename | 'C:/../src/app/app.component.css'
68
+ * change | 'C:/../src/app/app.component.css'
69
+ *
70
+ * Change 3
71
+ * rename | 'C:/../src/app/app.component.css'
72
+ * rename | 'C:/../src/app/app.component.css'
73
+ * change | 'C:/../src/app/app.component.css'
74
+ *
75
+ * watcher.on('all')
76
+ * Change 1
77
+ * change | 'C:\\..\\src\\app\\app.component.css'
78
+ *
79
+ * Change 2
80
+ * unlink | 'C:\\..\\src\\app\\app.component.css'
81
+ *
82
+ * Change 3
83
+ * ... (Nothing)
84
+ * ```
85
+ */
86
+ watcher.on('raw', (event, path, { watchedPath }) => {
41
87
  switch (event) {
42
88
  case 'add':
43
- currentChanges ??= new ChangedFiles();
44
- currentChanges.added.add(path);
45
- break;
46
89
  case 'change':
47
- currentChanges ??= new ChangedFiles();
48
- currentChanges.modified.add(path);
49
- break;
90
+ // When using Visual Studio the rename event is fired before a change event when the contents of the file changed
91
+ // or instead of `unlink` when the file has been renamed.
50
92
  case 'unlink':
51
- currentChanges ??= new ChangedFiles();
52
- currentChanges.removed.add(path);
93
+ case 'rename':
94
+ // When polling is enabled `watchedPath` can be undefined.
95
+ // `path` is always normalized unlike `watchedPath`.
96
+ const changedPath = watchedPath ? (0, node_path_1.normalize)(watchedPath) : path;
97
+ currentEvents ??= new Map();
98
+ currentEvents.set(changedPath, event);
53
99
  break;
54
100
  default:
55
101
  return;
@@ -59,10 +105,25 @@ function createWatcher(options) {
59
105
  nextWaitTimeout = setTimeout(() => {
60
106
  nextWaitTimeout = undefined;
61
107
  const next = nextQueue.shift();
62
- if (next) {
63
- const value = currentChanges;
64
- currentChanges = undefined;
65
- next(value);
108
+ if (next && currentEvents) {
109
+ const events = currentEvents;
110
+ currentEvents = undefined;
111
+ const currentChanges = new ChangedFiles();
112
+ for (const [path, event] of events) {
113
+ switch (event) {
114
+ case 'add':
115
+ currentChanges.added.add(path);
116
+ break;
117
+ case 'change':
118
+ currentChanges.modified.add(path);
119
+ break;
120
+ case 'unlink':
121
+ case 'rename':
122
+ currentChanges.removed.add(path);
123
+ break;
124
+ }
125
+ }
126
+ next(currentChanges);
66
127
  }
67
128
  }, 250);
68
129
  nextWaitTimeout?.unref();
@@ -270,7 +270,7 @@ async function getCommonConfig(wco) {
270
270
  externals: externalDependencies,
271
271
  output: {
272
272
  uniqueName: projectName,
273
- hashFunction: 'xxhash64',
273
+ hashFunction: 'xxhash64', // todo: remove in webpack 6. This is part of `futureDefaults`.
274
274
  clean: buildOptions.deleteOutputPath ?? true,
275
275
  path: path.resolve(root, buildOptions.outputPath),
276
276
  publicPath: buildOptions.deployUrl ?? '',
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { Compiler } from 'webpack';
9
9
  export interface CommonJsUsageWarnPluginOptions {
10
- /** A list of CommonJS packages that are allowed to be used without a warning. */
10
+ /** A list of CommonJS or AMD packages that are allowed to be used without a warning. Use `'*'` to allow all. */
11
11
  allowedDependencies?: string[];
12
12
  }
13
13
  export declare class CommonJsUsageWarnPlugin {
@@ -24,6 +24,9 @@ class CommonJsUsageWarnPlugin {
24
24
  this.allowedDependencies = new Set(this.options.allowedDependencies);
25
25
  }
26
26
  apply(compiler) {
27
+ if (this.allowedDependencies.has('*')) {
28
+ return;
29
+ }
27
30
  compiler.hooks.compilation.tap('CommonJsUsageWarnPlugin', (compilation) => {
28
31
  compilation.hooks.finishModules.tap('CommonJsUsageWarnPlugin', (modules) => {
29
32
  const mainEntry = compilation.entries.get('main');
@@ -156,8 +156,6 @@ class JavaScriptOptimizerPlugin {
156
156
  await Promise.all(tasks);
157
157
  }
158
158
  finally {
159
- // Workaround piscina bug where a worker thread will be recreated after destroy to meet the minimum.
160
- workerPool.options.minThreads = 0;
161
159
  void workerPool.destroy();
162
160
  }
163
161
  logger.timeEnd('optimize js assets');
@@ -240,16 +240,16 @@ function assetPatterns(root, assets) {
240
240
  exports.assetPatterns = assetPatterns;
241
241
  function getStatsOptions(verbose = false) {
242
242
  const webpackOutputOptions = {
243
- all: false,
243
+ all: false, // Fallback value for stats options when an option is not defined. It has precedence over local webpack defaults.
244
244
  colors: true,
245
- hash: true,
246
- timings: true,
247
- chunks: true,
248
- builtAt: true,
245
+ hash: true, // required by custom stat output
246
+ timings: true, // required by custom stat output
247
+ chunks: true, // required by custom stat output
248
+ builtAt: true, // required by custom stat output
249
249
  warnings: true,
250
250
  errors: true,
251
- assets: true,
252
- cachedAssets: true,
251
+ assets: true, // required by custom stat output
252
+ cachedAssets: true, // required for bundle size calculators
253
253
  // Needed for markAsyncChunksNonInitial.
254
254
  ids: true,
255
255
  entrypoints: true,
@@ -52,8 +52,6 @@ class BundleActionExecutor {
52
52
  }
53
53
  stop() {
54
54
  if (this.workerPool) {
55
- // Workaround piscina bug where a worker thread will be recreated after destroy to meet the minimum.
56
- this.workerPool.options.minThreads = 0;
57
55
  void this.workerPool.destroy();
58
56
  }
59
57
  }
@@ -82,6 +82,4 @@ exports.useLegacySass = (() => {
82
82
  const debugPerfVariable = process.env['NG_BUILD_DEBUG_PERF'];
83
83
  exports.debugPerformance = isPresent(debugPerfVariable) && isEnabled(debugPerfVariable);
84
84
  const watchRootVariable = process.env['NG_BUILD_WATCH_ROOT'];
85
- exports.shouldWatchRoot = process.platform === 'win32'
86
- ? !isPresent(watchRootVariable) || !isDisabled(watchRootVariable)
87
- : isPresent(watchRootVariable) && isEnabled(watchRootVariable);
85
+ exports.shouldWatchRoot = isPresent(watchRootVariable) && isEnabled(watchRootVariable);
@@ -5,7 +5,7 @@
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
- import { FontsClass, OptimizationClass, OptimizationUnion, StylesClass } from '../builders/browser/schema';
8
+ import { FontsClass, OptimizationClass, OptimizationUnion, StylesClass } from '../builders/application/schema';
9
9
  export type NormalizedOptimizationOptions = Required<Omit<OptimizationClass, 'fonts' | 'styles'>> & {
10
10
  fonts: FontsClass;
11
11
  styles: StylesClass;
@@ -10,13 +10,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.normalizeOptimization = void 0;
11
11
  function normalizeOptimization(optimization = true) {
12
12
  if (typeof optimization === 'object') {
13
+ const styleOptimization = !!optimization.styles;
13
14
  return {
14
15
  scripts: !!optimization.scripts,
15
16
  styles: typeof optimization.styles === 'object'
16
17
  ? optimization.styles
17
18
  : {
18
- minify: !!optimization.styles,
19
- inlineCritical: !!optimization.styles,
19
+ minify: styleOptimization,
20
+ removeSpecialComments: styleOptimization,
21
+ inlineCritical: styleOptimization,
20
22
  },
21
23
  fonts: typeof optimization.fonts === 'object'
22
24
  ? optimization.fonts
@@ -30,6 +32,7 @@ function normalizeOptimization(optimization = true) {
30
32
  styles: {
31
33
  minify: optimization,
32
34
  inlineCritical: optimization,
35
+ removeSpecialComments: optimization,
33
36
  },
34
37
  fonts: {
35
38
  inline: optimization,
@@ -25,7 +25,7 @@ exports.callInitializeIfNeeded = callInitializeIfNeeded;
25
25
  function getESMLoaderArgs() {
26
26
  if (isNode18()) {
27
27
  return [
28
- '--no-warnings',
28
+ '--no-warnings', // Suppress `ExperimentalWarning: Custom ESM Loaders is an experimental feature...`.
29
29
  '--loader',
30
30
  (0, node_url_1.pathToFileURL)((0, node_path_1.join)(__dirname, 'loader-hooks.js')).href, // Loader cannot be an absolute path on Windows.
31
31
  ];
@@ -124,8 +124,6 @@ async function renderPages(sourcemap, allRoutes, maxThreads, workspaceRoot, outp
124
124
  await Promise.all(renderingPromises);
125
125
  }
126
126
  finally {
127
- // Workaround piscina bug where a worker thread will be recreated after destroy to meet the minimum.
128
- renderWorker.options.minThreads = 0;
129
127
  void renderWorker.destroy();
130
128
  }
131
129
  return {
@@ -169,8 +167,6 @@ async function getAllRoutes(workspaceRoot, outputFilesForWorker, assetFilesForWo
169
167
  const { routes: extractedRoutes, warnings } = await renderWorker
170
168
  .run({})
171
169
  .finally(() => {
172
- // Workaround piscina bug where a worker thread will be recreated after destroy to meet the minimum.
173
- renderWorker.options.minThreads = 0;
174
170
  void renderWorker.destroy();
175
171
  });
176
172
  for (const route of extractedRoutes) {
@@ -82,7 +82,7 @@ async function renderPage({ route, serverContext, document, inlineCriticalCss, o
82
82
  if (inlineCriticalCss) {
83
83
  const { InlineCriticalCssProcessor } = await Promise.resolve().then(() => __importStar(require('../../utils/index-file/inline-critical-css')));
84
84
  const inlineCriticalCssProcessor = new InlineCriticalCssProcessor({
85
- minify: false,
85
+ minify: false, // CSS has already been minified during the build.
86
86
  readAsset: async (filePath) => {
87
87
  filePath = (0, node_path_1.basename)(filePath);
88
88
  const content = outputFiles[filePath];
@@ -5,6 +5,8 @@
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
+ /// <reference types="@types/node/fs" />
9
+ /// <reference types="@types/node/ts4.8/fs" />
8
10
  import type { Config, Filesystem } from '@angular/service-worker/config';
9
11
  import { promises as fsPromises } from 'node:fs';
10
12
  import { BuildOutputFile } from '../tools/esbuild/bundler-context';