@angular/build 20.0.4 → 20.1.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/build",
3
- "version": "20.0.4",
3
+ "version": "20.1.0-next.1",
4
4
  "description": "Official build system for Angular",
5
5
  "keywords": [
6
6
  "Angular CLI",
@@ -23,11 +23,11 @@
23
23
  "builders": "builders.json",
24
24
  "dependencies": {
25
25
  "@ampproject/remapping": "2.3.0",
26
- "@angular-devkit/architect": "0.2000.4",
27
- "@babel/core": "7.27.1",
28
- "@babel/helper-annotate-as-pure": "7.27.1",
26
+ "@angular-devkit/architect": "0.2001.0-next.1",
27
+ "@babel/core": "7.27.4",
28
+ "@babel/helper-annotate-as-pure": "7.27.3",
29
29
  "@babel/helper-split-export-declaration": "7.24.7",
30
- "@inquirer/confirm": "5.1.10",
30
+ "@inquirer/confirm": "5.1.12",
31
31
  "@vitejs/plugin-basic-ssl": "2.0.0",
32
32
  "beasties": "0.3.4",
33
33
  "browserslist": "^4.23.0",
@@ -40,30 +40,30 @@
40
40
  "mrmime": "2.0.1",
41
41
  "parse5-html-rewriting-stream": "7.1.0",
42
42
  "picomatch": "4.0.2",
43
- "piscina": "5.1.1",
44
- "rollup": "4.40.2",
45
- "sass": "1.88.0",
43
+ "piscina": "5.0.0",
44
+ "rollup": "4.43.0",
45
+ "sass": "1.89.2",
46
46
  "semver": "7.7.2",
47
47
  "source-map-support": "0.5.21",
48
- "tinyglobby": "0.2.13",
48
+ "tinyglobby": "0.2.14",
49
49
  "vite": "6.3.5",
50
- "watchpack": "2.4.2"
50
+ "watchpack": "2.4.4"
51
51
  },
52
52
  "optionalDependencies": {
53
- "lmdb": "3.3.0"
53
+ "lmdb": "3.4.0"
54
54
  },
55
55
  "peerDependencies": {
56
- "@angular/core": "^20.0.0",
57
- "@angular/compiler": "^20.0.0",
58
- "@angular/compiler-cli": "^20.0.0",
59
- "@angular/localize": "^20.0.0",
60
- "@angular/platform-browser": "^20.0.0",
61
- "@angular/platform-server": "^20.0.0",
62
- "@angular/service-worker": "^20.0.0",
63
- "@angular/ssr": "^20.0.4",
56
+ "@angular/core": "^20.0.0 || ^20.1.0-next.0",
57
+ "@angular/compiler": "^20.0.0 || ^20.1.0-next.0",
58
+ "@angular/compiler-cli": "^20.0.0 || ^20.1.0-next.0",
59
+ "@angular/localize": "^20.0.0 || ^20.1.0-next.0",
60
+ "@angular/platform-browser": "^20.0.0 || ^20.1.0-next.0",
61
+ "@angular/platform-server": "^20.0.0 || ^20.1.0-next.0",
62
+ "@angular/service-worker": "^20.0.0 || ^20.1.0-next.0",
63
+ "@angular/ssr": "^20.1.0-next.1",
64
64
  "karma": "^6.4.0",
65
65
  "less": "^4.2.0",
66
- "ng-packagr": "^20.0.0",
66
+ "ng-packagr": "^20.0.0 || ^20.1.0-next.0",
67
67
  "postcss": "^8.4.0",
68
68
  "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0",
69
69
  "tslib": "^2.3.0",
@@ -186,7 +186,7 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
186
186
  budgets: import("./schema").Budget[] | undefined;
187
187
  publicPath: string | undefined;
188
188
  plugins: Plugin[] | undefined;
189
- loaderExtensions: Record<string, "file" | "binary" | "text"> | undefined;
189
+ loaderExtensions: Record<string, "file" | "base64" | "binary" | "text" | "dataurl"> | undefined;
190
190
  jsonLogs: boolean;
191
191
  colors: boolean;
192
192
  clearScreen: boolean | undefined;
@@ -96,7 +96,12 @@ async function normalizeOptions(context, projectName, options, extensions) {
96
96
  if (extension[0] !== '.' || /\.[cm]?[jt]sx?$/.test(extension)) {
97
97
  continue;
98
98
  }
99
- if (value !== 'text' && value !== 'binary' && value !== 'file' && value !== 'empty') {
99
+ if (value !== 'text' &&
100
+ value !== 'binary' &&
101
+ value !== 'file' &&
102
+ value !== 'dataurl' &&
103
+ value !== 'base64' &&
104
+ value !== 'empty') {
100
105
  continue;
101
106
  }
102
107
  loaderExtensions ??= {};
@@ -102,7 +102,9 @@ export type Schema = {
102
102
  * Defines the type of loader to use with a specified file extension when used with a
103
103
  * JavaScript `import`. `text` inlines the content as a string; `binary` inlines the content
104
104
  * as a Uint8Array; `file` emits the file and provides the runtime location of the file;
105
- * `empty` considers the content to be empty and not include it in bundles.
105
+ * `dataurl` inlines the content as a data URL with best guess of MIME type; `base64`
106
+ * inlines the content as a Base64-encoded string; `empty` considers the content to be empty
107
+ * and not include it in bundles.
106
108
  */
107
109
  loader?: {
108
110
  [key: string]: any;
@@ -279,10 +279,10 @@
279
279
  ]
280
280
  },
281
281
  "loader": {
282
- "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.",
282
+ "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; `dataurl` inlines the content as a data URL with best guess of MIME type; `base64` inlines the content as a Base64-encoded string; `empty` considers the content to be empty and not include it in bundles.",
283
283
  "type": "object",
284
284
  "patternProperties": {
285
- "^\\.\\S+$": { "enum": ["text", "binary", "file", "empty"] }
285
+ "^\\.\\S+$": { "enum": ["text", "binary", "file", "dataurl", "base64", "empty"] }
286
286
  }
287
287
  },
288
288
  "define": {
@@ -112,7 +112,7 @@ class AngularAssetsMiddleware {
112
112
  class AngularPolyfillsPlugin {
113
113
  static $inject = ['config.files'];
114
114
  static NAME = 'angular-polyfills';
115
- static createPlugin(polyfillsFile, jasmineCleanupFiles, scriptsFiles) {
115
+ static createPlugin(polyfillsFile, jasmineCleanupFiles) {
116
116
  return {
117
117
  // This has to be a "reporter" because reporters run _after_ frameworks
118
118
  // and karma-jasmine-html-reporter injects additional scripts that may
@@ -155,8 +155,6 @@ class AngularPolyfillsPlugin {
155
155
  f.type = 'module';
156
156
  }
157
157
  }
158
- // Add "scripts" option files as classic scripts
159
- files.unshift(...scriptsFiles);
160
158
  // Add browser sourcemap support as a classic script
161
159
  files.unshift({
162
160
  pattern: localResolve('source-map-support/browser-source-map-support.js'),
@@ -396,25 +394,16 @@ async function initializeApplication(options, context, karmaOptions, transforms
396
394
  watched: false,
397
395
  };
398
396
  karmaOptions.basePath = outputPath;
399
- const scriptsFiles = [];
397
+ karmaOptions.files ??= [];
400
398
  if (options.scripts?.length) {
401
- const outputScripts = new Set();
402
- for (const scriptEntry of options.scripts) {
403
- const outputName = typeof scriptEntry === 'string'
404
- ? 'scripts.js'
405
- : `${scriptEntry.bundleName ?? 'scripts'}.js`;
406
- if (outputScripts.has(outputName)) {
407
- continue;
408
- }
409
- outputScripts.add(outputName);
410
- scriptsFiles.push({
411
- pattern: `${outputPath}/${outputName}`,
412
- watched: false,
413
- type: 'js',
414
- });
415
- }
399
+ // This should be more granular to support named bundles.
400
+ // However, it replicates the behavior of the Karma Webpack-based builder.
401
+ karmaOptions.files.push({
402
+ pattern: `scripts.js`,
403
+ watched: false,
404
+ type: 'js',
405
+ });
416
406
  }
417
- karmaOptions.files ??= [];
418
407
  karmaOptions.files.push(
419
408
  // Serve global setup script.
420
409
  { pattern: `${mainName}.js`, type: 'module', watched: false },
@@ -465,7 +454,7 @@ async function initializeApplication(options, context, karmaOptions, transforms
465
454
  parsedKarmaConfig.plugins.push(AngularAssetsMiddleware.createPlugin(buildOutput));
466
455
  parsedKarmaConfig.middleware ??= [];
467
456
  parsedKarmaConfig.middleware.push(AngularAssetsMiddleware.NAME);
468
- parsedKarmaConfig.plugins.push(AngularPolyfillsPlugin.createPlugin(polyfillsFile, jasmineCleanupFiles, scriptsFiles));
457
+ parsedKarmaConfig.plugins.push(AngularPolyfillsPlugin.createPlugin(polyfillsFile, jasmineCleanupFiles));
469
458
  parsedKarmaConfig.reporters ??= [];
470
459
  parsedKarmaConfig.reporters.push(AngularPolyfillsPlugin.NAME);
471
460
  // Adjust karma junit reporter outDir location to maintain previous (devkit) behavior
@@ -65,7 +65,9 @@ export type Schema = {
65
65
  * Defines the type of loader to use with a specified file extension when used with a
66
66
  * JavaScript `import`. `text` inlines the content as a string; `binary` inlines the content
67
67
  * as a Uint8Array; `file` emits the file and provides the runtime location of the file;
68
- * `empty` considers the content to be empty and not include it in bundles.
68
+ * `dataurl` inlines the content as a data URL with best guess of MIME type; `base64`
69
+ * inlines the content as a Base64-encoded string; `empty` considers the content to be empty
70
+ * and not include it in bundles.
69
71
  */
70
72
  loader?: {
71
73
  [key: string]: any;
@@ -163,10 +163,10 @@
163
163
  "default": []
164
164
  },
165
165
  "loader": {
166
- "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.",
166
+ "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; `dataurl` inlines the content as a data URL with best guess of MIME type; `base64` inlines the content as a Base64-encoded string; `empty` considers the content to be empty and not include it in bundles.",
167
167
  "type": "object",
168
168
  "patternProperties": {
169
- "^\\.\\S+$": { "enum": ["text", "binary", "file", "empty"] }
169
+ "^\\.\\S+$": { "enum": ["text", "binary", "file", "dataurl", "base64", "empty"] }
170
170
  }
171
171
  },
172
172
  "define": {
@@ -75,7 +75,7 @@ async function* execute(options, context, extensions = {}) {
75
75
  if (buildTargetOptions.polyfills?.includes('zone.js')) {
76
76
  buildTargetOptions.polyfills.push('zone.js/testing');
77
77
  }
78
- const outputPath = node_path_1.default.join(context.workspaceRoot, 'dist/test-out', (0, node_crypto_1.randomUUID)());
78
+ const outputPath = node_path_1.default.join(context.workspaceRoot, generateOutputPath());
79
79
  const buildOptions = {
80
80
  ...buildTargetOptions,
81
81
  watch: normalizedOptions.watch,
@@ -170,35 +170,61 @@ async function* execute(options, context, extensions = {}) {
170
170
  instance ??= await startVitest('test', undefined /* cliFilters */, {
171
171
  // Disable configuration file resolution/loading
172
172
  config: false,
173
- }, {
174
- test: {
175
- root: outputPath,
176
- globals: true,
177
- setupFiles,
178
- // Use `jsdom` if no browsers are explicitly configured.
179
- // `node` is effectively no "environment" and the default.
180
- environment: browser ? 'node' : 'jsdom',
181
- watch: normalizedOptions.watch,
182
- browser,
183
- reporters: normalizedOptions.reporters ?? ['default'],
184
- coverage: {
185
- enabled: normalizedOptions.codeCoverage,
186
- excludeAfterRemap: true,
187
- },
188
- ...debugOptions,
173
+ root: workspaceRoot,
174
+ project: ['base', projectName],
175
+ name: 'base',
176
+ include: [],
177
+ reporters: normalizedOptions.reporters ?? ['default'],
178
+ watch: normalizedOptions.watch,
179
+ coverage: {
180
+ enabled: !!normalizedOptions.codeCoverage,
181
+ excludeAfterRemap: true,
182
+ exclude: normalizedOptions.codeCoverage?.exclude,
183
+ // Special handling for `reporter` due to an undefined value causing upstream failures
184
+ ...(normalizedOptions.codeCoverage?.reporters
185
+ ? { reporters: normalizedOptions.codeCoverage.reporters }
186
+ : {}),
189
187
  },
188
+ ...debugOptions,
189
+ }, {
190
190
  plugins: [
191
191
  {
192
- name: 'angular-coverage-exclude',
193
- configureVitest(context) {
194
- // Adjust coverage excludes to not include the otherwise automatically inserted included unit tests.
195
- // Vite does this as a convenience but is problematic for the bundling strategy employed by the
196
- // builder's test setup. To workaround this, the excludes are adjusted here to only automatically
197
- // exclude the TypeScript source test files.
198
- context.project.config.coverage.exclude = [
199
- ...(normalizedOptions.codeCoverageExclude ?? []),
200
- '**/*.{test,spec}.?(c|m)ts',
201
- ];
192
+ name: 'angular:project-init',
193
+ async configureVitest(context) {
194
+ // Create a subproject that can be configured with plugins for browser mode.
195
+ // Plugins defined directly in the vite overrides will not be present in the
196
+ // browser specific Vite instance.
197
+ await context.injectTestProjects({
198
+ test: {
199
+ name: projectName,
200
+ root: outputPath,
201
+ globals: true,
202
+ setupFiles,
203
+ // Use `jsdom` if no browsers are explicitly configured.
204
+ // `node` is effectively no "environment" and the default.
205
+ environment: browser ? 'node' : 'jsdom',
206
+ browser,
207
+ },
208
+ plugins: [
209
+ {
210
+ name: 'angular:html-index',
211
+ transformIndexHtml() {
212
+ // Add all global stylesheets
213
+ return (Object.entries(result.files)
214
+ // TODO: Expand this to all configured global stylesheets
215
+ .filter(([file]) => file === 'styles.css')
216
+ .map(([styleUrl]) => ({
217
+ tag: 'link',
218
+ attrs: {
219
+ 'href': styleUrl,
220
+ 'rel': 'stylesheet',
221
+ },
222
+ injectTo: 'head',
223
+ })));
224
+ },
225
+ },
226
+ ],
227
+ });
202
228
  },
203
229
  },
204
230
  ],
@@ -264,3 +290,8 @@ function setupBrowserConfiguration(browsers, debug, projectSourceRoot) {
264
290
  };
265
291
  return { browser };
266
292
  }
293
+ function generateOutputPath() {
294
+ const datePrefix = new Date().toISOString().replaceAll(/[-:.]/g, '');
295
+ const uuidSuffix = (0, node_crypto_1.randomUUID)().slice(0, 8);
296
+ return node_path_1.default.join('dist', 'test-out', `${datePrefix}-${uuidSuffix}`);
297
+ }
@@ -65,8 +65,8 @@ async function useKarmaBuilder(context, unitTestOptions) {
65
65
  poll: buildTargetOptions.poll,
66
66
  preserveSymlinks: buildTargetOptions.preserveSymlinks,
67
67
  browsers: unitTestOptions.browsers?.join(','),
68
- codeCoverage: unitTestOptions.codeCoverage,
69
- codeCoverageExclude: unitTestOptions.codeCoverageExclude,
68
+ codeCoverage: !!unitTestOptions.codeCoverage,
69
+ codeCoverageExclude: unitTestOptions.codeCoverage?.exclude,
70
70
  fileReplacements: buildTargetOptions.fileReplacements,
71
71
  reporters: unitTestOptions.reporters,
72
72
  webWorkerTsConfig: buildTargetOptions.webWorkerTsConfig,
@@ -17,8 +17,10 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
17
17
  include: string[];
18
18
  exclude: string[];
19
19
  runnerName: import("./schema").Runner;
20
- codeCoverage: boolean | undefined;
21
- codeCoverageExclude: string[] | undefined;
20
+ codeCoverage: {
21
+ exclude: string[] | undefined;
22
+ reporters: [string, Record<string, unknown>][] | undefined;
23
+ } | undefined;
22
24
  tsConfig: string;
23
25
  reporters: string[] | undefined;
24
26
  browsers: string[] | undefined;
@@ -27,7 +27,7 @@ async function normalizeOptions(context, projectName, options) {
27
27
  // Target specifier defaults to the current project's build target using a development configuration
28
28
  const buildTargetSpecifier = options.buildTarget ?? `::development`;
29
29
  const buildTarget = (0, architect_1.targetFromTargetString)(buildTargetSpecifier, projectName, 'build');
30
- const { codeCoverage, codeCoverageExclude, tsConfig, runner, reporters, browsers } = options;
30
+ const { tsConfig, runner, reporters, browsers } = options;
31
31
  return {
32
32
  // Project/workspace information
33
33
  workspaceRoot,
@@ -39,8 +39,14 @@ async function normalizeOptions(context, projectName, options) {
39
39
  include: options.include ?? ['**/*.spec.ts'],
40
40
  exclude: options.exclude ?? [],
41
41
  runnerName: runner,
42
- codeCoverage,
43
- codeCoverageExclude,
42
+ codeCoverage: options.codeCoverage
43
+ ? {
44
+ exclude: options.codeCoverageExclude,
45
+ reporters: options.codeCoverageReporters?.map((entry) => typeof entry === 'string'
46
+ ? [entry, {}]
47
+ : entry),
48
+ }
49
+ : undefined,
44
50
  tsConfig,
45
51
  reporters,
46
52
  browsers,
@@ -21,6 +21,10 @@ export type Schema = {
21
21
  * Globs to exclude from code coverage.
22
22
  */
23
23
  codeCoverageExclude?: string[];
24
+ /**
25
+ * Reporters to use for code coverage results.
26
+ */
27
+ codeCoverageReporters?: SchemaCodeCoverageReporter[];
24
28
  /**
25
29
  * Initialize the test runner to support using the Node Inspector for test debugging.
26
30
  */
@@ -60,6 +64,18 @@ export type Schema = {
60
64
  */
61
65
  watch?: boolean;
62
66
  };
67
+ export type SchemaCodeCoverageReporter = CodeCoverageReporterCodeCoverageReporter[] | CoverageReporters;
68
+ export type CodeCoverageReporterCodeCoverageReporter = CoverageReporters | {
69
+ [key: string]: any;
70
+ };
71
+ export declare enum CoverageReporters {
72
+ Cobertura = "cobertura",
73
+ Html = "html",
74
+ Lcov = "lcov",
75
+ Lcovonly = "lcovonly",
76
+ Text = "text",
77
+ TextSummary = "text-summary"
78
+ }
63
79
  /**
64
80
  * The name of the test runner to use for test execution.
65
81
  */
@@ -2,7 +2,16 @@
2
2
  // THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
3
3
  // CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.Runner = void 0;
5
+ exports.Runner = exports.CoverageReporters = void 0;
6
+ var CoverageReporters;
7
+ (function (CoverageReporters) {
8
+ CoverageReporters["Cobertura"] = "cobertura";
9
+ CoverageReporters["Html"] = "html";
10
+ CoverageReporters["Lcov"] = "lcov";
11
+ CoverageReporters["Lcovonly"] = "lcovonly";
12
+ CoverageReporters["Text"] = "text";
13
+ CoverageReporters["TextSummary"] = "text-summary";
14
+ })(CoverageReporters || (exports.CoverageReporters = CoverageReporters = {}));
6
15
  /**
7
16
  * The name of the test runner to use for test execution.
8
17
  */
@@ -64,6 +64,23 @@
64
64
  },
65
65
  "default": []
66
66
  },
67
+ "codeCoverageReporters": {
68
+ "type": "array",
69
+ "description": "Reporters to use for code coverage results.",
70
+ "items": {
71
+ "oneOf": [
72
+ {
73
+ "$ref": "#/definitions/coverage-reporters"
74
+ },
75
+ {
76
+ "type": "array",
77
+ "minItems": 1,
78
+ "maxItems": 2,
79
+ "items": [{ "$ref": "#/definitions/coverage-reporters" }, { "type": "object" }]
80
+ }
81
+ ]
82
+ }
83
+ },
67
84
  "reporters": {
68
85
  "type": "array",
69
86
  "description": "Test runner reporters to use. Directly passed to the test runner.",
@@ -78,5 +95,10 @@
78
95
  }
79
96
  },
80
97
  "additionalProperties": false,
81
- "required": ["buildTarget", "tsConfig", "runner"]
98
+ "required": ["buildTarget", "tsConfig", "runner"],
99
+ "definitions": {
100
+ "coverage-reporters": {
101
+ "enum": ["html", "lcov", "lcovonly", "text", "text-summary", "cobertura"]
102
+ }
103
+ }
82
104
  }
@@ -9,7 +9,7 @@
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.createLoaderImportAttributePlugin = createLoaderImportAttributePlugin;
11
11
  const promises_1 = require("node:fs/promises");
12
- const SUPPORTED_LOADERS = ['binary', 'file', 'text'];
12
+ const SUPPORTED_LOADERS = ['base64', 'binary', 'dataurl', 'file', 'text'];
13
13
  function createLoaderImportAttributePlugin() {
14
14
  return {
15
15
  name: 'angular-loader-import-attributes',
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.normalizeCacheOptions = normalizeCacheOptions;
11
11
  const node_path_1 = require("node:path");
12
12
  /** Version placeholder is replaced during the build process with actual package version */
13
- const VERSION = '20.0.4';
13
+ const VERSION = '20.1.0-next.1';
14
14
  function hasCacheMetadata(value) {
15
15
  return (!!value &&
16
16
  typeof value === 'object' &&
@@ -161,12 +161,22 @@ function generateLazyLoadedFilesMappings(metafile, initialFiles, publicPath = ''
161
161
  if (!entryPoint || exports?.length < 1 || !fileName.endsWith('.js')) {
162
162
  continue;
163
163
  }
164
- const importedPaths = [`${publicPath}${fileName}`];
164
+ const importedPaths = [
165
+ {
166
+ path: `${publicPath}${fileName}`,
167
+ dynamicImport: false,
168
+ },
169
+ ];
165
170
  for (const { kind, external, path } of imports) {
166
- if (external || initialFiles.has(path) || kind !== 'import-statement') {
171
+ if (external ||
172
+ initialFiles.has(path) ||
173
+ (kind !== 'dynamic-import' && kind !== 'import-statement')) {
167
174
  continue;
168
175
  }
169
- importedPaths.push(`${publicPath}${path}`);
176
+ importedPaths.push({
177
+ path: `${publicPath}${path}`,
178
+ dynamicImport: kind === 'dynamic-import',
179
+ });
170
180
  }
171
181
  entryPointToBundles[entryPoint] = importedPaths;
172
182
  }
@@ -28,7 +28,7 @@ function assertCompatibleAngularVersion(projectRoot) {
28
28
  'This likely indicates a corrupted local installation. Please try reinstalling your packages.');
29
29
  process.exit(2);
30
30
  }
31
- const supportedAngularSemver = '^20.0.0';
31
+ const supportedAngularSemver = '^20.0.0 || ^20.1.0-next.0';
32
32
  if (angularPkgJson['version'] === '0.0.0' || supportedAngularSemver.startsWith('0.0.0')) {
33
33
  // Internal CLI and FW testing version.
34
34
  return;
@@ -14,7 +14,7 @@ class WorkerPool extends piscina_1.Piscina {
14
14
  constructor(options) {
15
15
  const piscinaOptions = {
16
16
  minThreads: 1,
17
- idleTimeout: 4_000,
17
+ idleTimeout: 1000,
18
18
  // Web containers do not support transferable objects with receiveOnMessagePort which
19
19
  // is used when the Atomics based wait loop is enable.
20
20
  atomics: process.versions.webcontainer ? 'disabled' : 'sync',