@angular/build 20.0.0-next.2 → 20.0.0-next.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/build",
3
- "version": "20.0.0-next.2",
3
+ "version": "20.0.0-next.4",
4
4
  "description": "Official build system for Angular",
5
5
  "keywords": [
6
6
  "Angular CLI",
@@ -23,16 +23,15 @@
23
23
  "builders": "builders.json",
24
24
  "dependencies": {
25
25
  "@ampproject/remapping": "2.3.0",
26
- "@angular-devkit/architect": "0.2000.0-next.2",
26
+ "@angular-devkit/architect": "0.2000.0-next.4",
27
27
  "@babel/core": "7.26.10",
28
28
  "@babel/helper-annotate-as-pure": "7.25.9",
29
29
  "@babel/helper-split-export-declaration": "7.24.7",
30
- "@babel/plugin-syntax-import-attributes": "7.26.0",
31
30
  "@inquirer/confirm": "5.1.8",
32
31
  "@vitejs/plugin-basic-ssl": "2.0.0",
33
32
  "beasties": "0.2.0",
34
33
  "browserslist": "^4.23.0",
35
- "esbuild": "0.25.1",
34
+ "esbuild": "0.25.2",
36
35
  "https-proxy-agent": "7.0.6",
37
36
  "istanbul-lib-instrument": "6.0.3",
38
37
  "jsonc-parser": "3.3.1",
@@ -42,12 +41,12 @@
42
41
  "parse5-html-rewriting-stream": "7.0.0",
43
42
  "picomatch": "4.0.2",
44
43
  "piscina": "4.9.2",
45
- "rollup": "4.36.0",
46
- "sass": "1.86.0",
44
+ "rollup": "4.39.0",
45
+ "sass": "1.86.1",
47
46
  "semver": "7.7.1",
48
47
  "source-map-support": "0.5.21",
49
48
  "tinyglobby": "0.2.12",
50
- "vite": "6.2.2",
49
+ "vite": "6.2.4",
51
50
  "watchpack": "2.4.2"
52
51
  },
53
52
  "optionalDependencies": {
@@ -57,9 +56,10 @@
57
56
  "@angular/compiler": "^20.0.0 || ^20.0.0-next.0",
58
57
  "@angular/compiler-cli": "^20.0.0 || ^20.0.0-next.0",
59
58
  "@angular/localize": "^20.0.0 || ^20.0.0-next.0",
59
+ "@angular/platform-browser": "^20.0.0 || ^20.0.0-next.0",
60
60
  "@angular/platform-server": "^20.0.0 || ^20.0.0-next.0",
61
61
  "@angular/service-worker": "^20.0.0 || ^20.0.0-next.0",
62
- "@angular/ssr": "^20.0.0-next.2",
62
+ "@angular/ssr": "^20.0.0-next.4",
63
63
  "karma": "^6.4.0",
64
64
  "less": "^4.2.0",
65
65
  "ng-packagr": "^20.0.0 || ^20.0.0-next.0",
@@ -71,6 +71,9 @@
71
71
  "@angular/localize": {
72
72
  "optional": true
73
73
  },
74
+ "@angular/platform-browser": {
75
+ "optional": true
76
+ },
74
77
  "@angular/platform-server": {
75
78
  "optional": true
76
79
  },
@@ -102,7 +105,7 @@
102
105
  },
103
106
  "packageManager": "pnpm@9.15.6",
104
107
  "engines": {
105
- "node": "^20.11.1 || >=22.0.0",
108
+ "node": "^20.11.1 || >=22.11.0",
106
109
  "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
107
110
  "yarn": ">= 1.13.0"
108
111
  },
@@ -27,6 +27,7 @@ const build_action_1 = require("./build-action");
27
27
  const execute_build_1 = require("./execute-build");
28
28
  const options_1 = require("./options");
29
29
  const results_1 = require("./results");
30
+ const isNodeV22orHigher = Number(process.versions.node.split('.', 1)[0]) >= 22;
30
31
  async function* buildApplicationInternal(options,
31
32
  // TODO: Integrate abort signal support into builder system
32
33
  context, extensions) {
@@ -162,7 +163,18 @@ async function* buildApplication(options, context, extensions) {
162
163
  }
163
164
  else {
164
165
  // Copy file contents
165
- await promises_1.default.copyFile(file.inputPath, fullFilePath, promises_1.default.constants.COPYFILE_FICLONE);
166
+ if (isNodeV22orHigher) {
167
+ // Use newer `cp` API on Node.js 22+ (minimum v22 for CLI is 22.11)
168
+ await promises_1.default.cp(file.inputPath, fullFilePath, {
169
+ mode: promises_1.default.constants.COPYFILE_FICLONE,
170
+ preserveTimestamps: true,
171
+ });
172
+ }
173
+ else {
174
+ // For Node.js 20 use `copyFile` (`cp` is not stable for v20)
175
+ // TODO: Remove when Node.js 20 is no longer supported
176
+ await promises_1.default.copyFile(file.inputPath, fullFilePath, promises_1.default.constants.COPYFILE_FICLONE);
177
+ }
166
178
  }
167
179
  });
168
180
  // Delete any removed files if incremental
@@ -203,6 +203,8 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
203
203
  };
204
204
  templateUpdates: boolean;
205
205
  incrementalResults: boolean;
206
+ customConditions: string[] | undefined;
207
+ frameworkVersion: string;
206
208
  }>;
207
209
  export declare function getLocaleBaseHref(baseHref: string | undefined, i18n: NormalizedApplicationBuildOptions['i18nOptions'], locale: string): string | undefined;
208
210
  export {};
@@ -132,12 +132,12 @@ async function normalizeOptions(context, projectName, options, extensions) {
132
132
  ? undefined
133
133
  : await getTailwindConfig(searchDirectories, workspaceRoot, context);
134
134
  let serverEntryPoint;
135
- if (options.server) {
135
+ if (typeof options.server === 'string') {
136
+ if (options.server === '') {
137
+ throw new Error('The "server" option cannot be an empty string.');
138
+ }
136
139
  serverEntryPoint = node_path_1.default.join(workspaceRoot, options.server);
137
140
  }
138
- else if (options.server === '') {
139
- throw new Error('The "server" option cannot be an empty string.');
140
- }
141
141
  let prerenderOptions;
142
142
  if (options.prerender) {
143
143
  const { discoverRoutes = true, routesFile = undefined } = options.prerender === true ? {} : options.prerender;
@@ -163,7 +163,7 @@ async function normalizeOptions(context, projectName, options, extensions) {
163
163
  route: 'shell',
164
164
  };
165
165
  }
166
- const outputPath = options.outputPath;
166
+ const outputPath = options.outputPath ?? node_path_1.default.join(workspaceRoot, 'dist', projectName);
167
167
  const outputOptions = {
168
168
  browser: 'browser',
169
169
  server: 'server',
@@ -191,12 +191,18 @@ async function normalizeOptions(context, projectName, options, extensions) {
191
191
  let indexHtmlOptions;
192
192
  // index can never have a value of `true` but in the schema it's of type `boolean`.
193
193
  if (typeof options.index !== 'boolean') {
194
+ let indexInput;
194
195
  let indexOutput;
195
196
  // The output file will be created within the configured output path
196
197
  if (typeof options.index === 'string') {
197
- indexOutput = options.index;
198
+ indexInput = indexOutput = node_path_1.default.join(workspaceRoot, options.index);
199
+ }
200
+ else if (typeof options.index === 'undefined') {
201
+ indexInput = node_path_1.default.join(projectSourceRoot, 'index.html');
202
+ indexOutput = 'index.html';
198
203
  }
199
204
  else {
205
+ indexInput = node_path_1.default.join(workspaceRoot, options.index.input);
200
206
  indexOutput = options.index.output || 'index.html';
201
207
  }
202
208
  /**
@@ -214,7 +220,7 @@ async function normalizeOptions(context, projectName, options, extensions) {
214
220
  ? exports.INDEX_HTML_CSR
215
221
  : indexBaseName;
216
222
  indexHtmlOptions = {
217
- input: node_path_1.default.join(workspaceRoot, typeof options.index === 'string' ? options.index : options.index.input),
223
+ input: indexInput,
218
224
  output: indexOutput,
219
225
  insertionOrder: [
220
226
  ['polyfills', true],
@@ -312,6 +318,8 @@ async function normalizeOptions(context, projectName, options, extensions) {
312
318
  security,
313
319
  templateUpdates: !!options.templateUpdates,
314
320
  incrementalResults: !!options.incrementalResults,
321
+ customConditions: options.conditions,
322
+ frameworkVersion: await findFrameworkVersion(projectRoot),
315
323
  };
316
324
  }
317
325
  async function getTailwindConfig(searchDirectories, workspaceRoot, context) {
@@ -470,3 +478,18 @@ function normalizeExternals(value) {
470
478
  }
471
479
  return [...new Set(value.map((d) => (d.endsWith('/*') ? d.slice(0, -2) : d)))];
472
480
  }
481
+ async function findFrameworkVersion(projectRoot) {
482
+ // Create a custom require function for ESM compliance.
483
+ // NOTE: The trailing slash is significant.
484
+ const projectResolve = (0, node_module_1.createRequire)(projectRoot + '/').resolve;
485
+ try {
486
+ const manifestPath = projectResolve('@angular/core/package.json');
487
+ const manifestData = await (0, promises_1.readFile)(manifestPath, 'utf-8');
488
+ const manifestObject = JSON.parse(manifestData);
489
+ const version = manifestObject.version;
490
+ return version;
491
+ }
492
+ catch {
493
+ throw new Error('Error: It appears that "@angular/core" is missing as a dependency. Please ensure it is included in your project.');
494
+ }
495
+ }
@@ -37,6 +37,13 @@ export type Schema = {
37
37
  * Automatically clear the terminal screen during rebuilds.
38
38
  */
39
39
  clearScreen?: boolean;
40
+ /**
41
+ * Custom package resolution conditions used to resolve conditional exports/imports.
42
+ * Defaults to ['module', 'development'/'production']. The following special conditions are
43
+ * always present if the requirements are satisfied: 'default', 'import', 'require',
44
+ * 'browser', 'node'.
45
+ */
46
+ conditions?: string[];
40
47
  /**
41
48
  * Define the crossorigin attribute setting of elements that provide CORS support.
42
49
  */
@@ -86,7 +93,7 @@ export type Schema = {
86
93
  /**
87
94
  * Configures the generation of the application's HTML index.
88
95
  */
89
- index: IndexUnion;
96
+ index?: IndexUnion;
90
97
  /**
91
98
  * The stylesheet language to use for the application's inline component styles.
92
99
  */
@@ -128,7 +135,7 @@ export type Schema = {
128
135
  /**
129
136
  * Specify the output path relative to workspace root.
130
137
  */
131
- outputPath: OutputPathUnion;
138
+ outputPath?: OutputPathUnion;
132
139
  /**
133
140
  * Enable and define the file watching poll time period in milliseconds.
134
141
  */
@@ -163,11 +170,11 @@ export type Schema = {
163
170
  * The full path for the server entry point to the application, relative to the current
164
171
  * workspace.
165
172
  */
166
- server?: string;
173
+ server?: Serv;
167
174
  /**
168
175
  * Generates a service worker configuration.
169
176
  */
170
- serviceWorker?: ServiceWorker;
177
+ serviceWorker?: Serv;
171
178
  /**
172
179
  * Output source maps for scripts and styles. For more information, see
173
180
  * https://angular.dev/reference/configs/workspace-config#source-map-configuration.
@@ -496,9 +503,12 @@ export type AutoCspClass = {
496
503
  unsafeEval?: boolean;
497
504
  };
498
505
  /**
506
+ * The full path for the server entry point to the application, relative to the current
507
+ * workspace.
508
+ *
499
509
  * Generates a service worker configuration.
500
510
  */
501
- export type ServiceWorker = boolean | string;
511
+ export type Serv = boolean | string;
502
512
  /**
503
513
  * Output source maps for scripts and styles. For more information, see
504
514
  * https://angular.dev/reference/configs/workspace-config#source-map-configuration.
@@ -513,6 +523,10 @@ export type SourceMapClass = {
513
523
  * Output source maps for all scripts.
514
524
  */
515
525
  scripts?: boolean;
526
+ /**
527
+ * Output original source content for files within the source map.
528
+ */
529
+ sourcesContent?: boolean;
516
530
  /**
517
531
  * Output source maps for all styles.
518
532
  */
@@ -17,7 +17,6 @@
17
17
  "description": "The full path for the browser entry point to the application, relative to the current workspace."
18
18
  },
19
19
  "server": {
20
- "type": "string",
21
20
  "description": "The full path for the server entry point to the application, relative to the current workspace.",
22
21
  "oneOf": [
23
22
  {
@@ -293,6 +292,13 @@
293
292
  "type": "string"
294
293
  }
295
294
  },
295
+ "conditions": {
296
+ "description": "Custom package resolution conditions used to resolve conditional exports/imports. Defaults to ['module', 'development'/'production']. The following special conditions are always present if the requirements are satisfied: 'default', 'import', 'require', 'browser', 'node'.",
297
+ "type": "array",
298
+ "items": {
299
+ "type": "string"
300
+ }
301
+ },
296
302
  "fileReplacements": {
297
303
  "description": "Replace compilation source files with other compilation source files in the build.",
298
304
  "type": "array",
@@ -370,6 +376,11 @@
370
376
  "type": "boolean",
371
377
  "description": "Resolve vendor packages source maps.",
372
378
  "default": false
379
+ },
380
+ "sourcesContent": {
381
+ "type": "boolean",
382
+ "description": "Output original source content for files within the source map.",
383
+ "default": true
373
384
  }
374
385
  },
375
386
  "additionalProperties": false
@@ -605,7 +616,7 @@
605
616
  }
606
617
  },
607
618
  "additionalProperties": false,
608
- "required": ["outputPath", "index", "browser", "tsConfig"],
619
+ "required": ["browser", "tsConfig"],
609
620
  "definitions": {
610
621
  "assetPattern": {
611
622
  "oneOf": [
@@ -86,6 +86,7 @@ function createComponentStyleBundler(options, target) {
86
86
  // the same as being disabled. Disabling has the advantage of avoiding the overhead
87
87
  // of sourcemap processing.
88
88
  sourcemapOptions.styles && !sourcemapOptions.hidden ? 'linked' : false,
89
+ sourcesContent: sourcemapOptions.sourcesContent,
89
90
  outputNames,
90
91
  includePaths: stylePreprocessorOptions?.includePaths,
91
92
  // string[] | undefined' is not assignable to type '(Version | DeprecationOrId)[] | undefined'.
@@ -121,12 +121,6 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
121
121
  // This will also replace file-based/inline styles as code if external runtime styles are not enabled.
122
122
  browserOptions.templateUpdates =
123
123
  serverOptions.liveReload && serverOptions.hmr && environment_options_1.useComponentTemplateHmr;
124
- if (browserOptions.templateUpdates) {
125
- context.logger.warn('Component HMR has been enabled.\n' +
126
- 'If you encounter application reload issues, you can manually reload the page to bypass HMR and/or disable this feature with the' +
127
- ' `--no-hmr` command line option.\n' +
128
- 'Please consider reporting any issues you encounter here: https://github.com/angular/angular-cli/issues\n');
129
- }
130
124
  browserOptions.incrementalResults = true;
131
125
  // Setup the prebundling transformer that will be shared across Vite prebundling requests
132
126
  const prebundleTransformer = new internal_1.JavaScriptTransformer(
@@ -54,6 +54,7 @@ const results_1 = require("../application/results");
54
54
  const schema_1 = require("../application/schema");
55
55
  const find_tests_1 = require("./find-tests");
56
56
  const localResolve = (0, node_module_1.createRequire)(__filename).resolve;
57
+ const isWindows = process.platform === 'win32';
57
58
  class ApplicationBuildError extends Error {
58
59
  constructor(message) {
59
60
  super(message);
@@ -74,7 +75,13 @@ class AngularAssetsMiddleware {
74
75
  let err = null;
75
76
  try {
76
77
  const url = new URL(`http://${req.headers['host']}${req.url}`);
77
- const file = this.latestBuildFiles.files[url.pathname.slice(1)];
78
+ // Remove the leading slash from the URL path and convert to platform specific.
79
+ // The latest build files will use the platform path separator.
80
+ let pathname = url.pathname.slice(1);
81
+ if (isWindows) {
82
+ pathname = pathname.replaceAll(path.posix.sep, path.win32.sep);
83
+ }
84
+ const file = this.latestBuildFiles.files[pathname];
78
85
  if (file?.origin === 'disk') {
79
86
  this.serveFile(file.inputPath, undefined, res);
80
87
  return;
@@ -288,6 +295,7 @@ async function collectEntrypoints(options, context, projectSourceRoot) {
288
295
  const testFiles = await (0, find_tests_1.findTests)(options.include ?? [], options.exclude ?? [], context.workspaceRoot, projectSourceRoot);
289
296
  return (0, find_tests_1.getTestEntrypoints)(testFiles, { projectSourceRoot, workspaceRoot: context.workspaceRoot });
290
297
  }
298
+ // eslint-disable-next-line max-lines-per-function
291
299
  async function initializeApplication(options, context, karmaOptions, transforms = {}) {
292
300
  const outputPath = path.join(context.workspaceRoot, 'dist/test-out', (0, node_crypto_1.randomUUID)());
293
301
  const projectSourceRoot = await getProjectSourceRoot(context);
@@ -399,6 +407,14 @@ async function initializeApplication(options, context, karmaOptions, transforms
399
407
  karmaOptions.files.push({ pattern: `*.css`, type: 'css', watched: false });
400
408
  }
401
409
  const parsedKarmaConfig = await karma.config.parseConfig(options.karmaConfig && path.resolve(context.workspaceRoot, options.karmaConfig), transforms.karmaOptions ? transforms.karmaOptions(karmaOptions) : karmaOptions, { promiseConfig: true, throwErrors: true });
410
+ // Check for jsdom which does not support executing ESM scripts.
411
+ // If present, remove jsdom and issue a warning.
412
+ const updatedBrowsers = parsedKarmaConfig.browsers?.filter((browser) => browser !== 'jsdom');
413
+ if (parsedKarmaConfig.browsers?.length !== updatedBrowsers?.length) {
414
+ parsedKarmaConfig.browsers = updatedBrowsers;
415
+ context.logger.warn(`'jsdom' does not support ESM code execution and cannot be used for karma testing.` +
416
+ ` The 'jsdom' entry has been removed from the 'browsers' option.`);
417
+ }
402
418
  // Remove the webpack plugin/framework:
403
419
  // Alternative would be to make the Karma plugin "smart" but that's a tall order
404
420
  // with managing unneeded imports etc..
@@ -76,7 +76,7 @@ function getBaseKarmaOptions(options, context) {
76
76
  karmaOptions.client.clearContext ??= singleRun ?? false; // `singleRun` defaults to `false` per Karma docs.
77
77
  // Convert browsers from a string to an array
78
78
  if (typeof options.browsers === 'string' && options.browsers) {
79
- karmaOptions.browsers = options.browsers.split(',');
79
+ karmaOptions.browsers = options.browsers.split(',').map((browser) => browser.trim());
80
80
  }
81
81
  else if (options.browsers === false) {
82
82
  karmaOptions.browsers = [];
@@ -7,13 +7,10 @@
7
7
  */
8
8
 
9
9
  import { getTestBed } from '@angular/core/testing';
10
- import {
11
- BrowserDynamicTestingModule,
12
- platformBrowserDynamicTesting,
13
- } from '@angular/platform-browser-dynamic/testing';
10
+ import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing';
14
11
 
15
12
  // Initialize the Angular testing environment.
16
- getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
13
+ getTestBed().initTestEnvironment(BrowserTestingModule, platformBrowserTesting(), {
17
14
  errorOnUnknownElements: true,
18
15
  errorOnUnknownProperties: true,
19
16
  });
@@ -382,7 +382,7 @@ function getEsBuildServerCommonOptions(options) {
382
382
  };
383
383
  }
384
384
  function getEsBuildCommonOptions(options) {
385
- const { workspaceRoot, outExtension, optimizationOptions, sourcemapOptions, tsconfig, externalDependencies, outputNames, preserveSymlinks, jit, loaderExtensions, jsonLogs, i18nOptions, } = options;
385
+ const { workspaceRoot, outExtension, optimizationOptions, sourcemapOptions, tsconfig, externalDependencies, outputNames, preserveSymlinks, jit, loaderExtensions, jsonLogs, i18nOptions, customConditions, frameworkVersion, } = options;
386
386
  // Ensure unique hashes for i18n translation changes when using post-process inlining.
387
387
  // This hash value is added as a footer to each file and ensures that the output file names (with hashes)
388
388
  // change when translation files have changed. If this is not done the post processed files may have
@@ -393,18 +393,36 @@ function getEsBuildCommonOptions(options) {
393
393
  const i18nHash = Object.values(i18nOptions.locales).reduce((data, locale) => data + locale.files.map((file) => file.integrity || '').join('|'), '');
394
394
  footer = { js: `/**i18n:${(0, node_crypto_1.createHash)('sha256').update(i18nHash).digest('hex')}*/` };
395
395
  }
396
+ // Core conditions that are always included
397
+ const conditions = [
398
+ // Required to support rxjs 7.x which will use es5 code if this condition is not present
399
+ 'es2015',
400
+ 'es2020',
401
+ ];
402
+ // The pre-linked code is not used with JIT for two reasons:
403
+ // 1) The pre-linked code may not have the metadata included that is required for JIT
404
+ // 2) The CLI is otherwise setup to use runtime linking for JIT to match the application template compilation
405
+ if (!jit) {
406
+ // The pre-linked package condition is based on the framework version.
407
+ // Currently this is specific to each patch version of the framework.
408
+ conditions.push('angular:linked-' + frameworkVersion);
409
+ }
410
+ // Append custom conditions if present
411
+ if (customConditions) {
412
+ conditions.push(...customConditions);
413
+ }
414
+ else {
415
+ // Include default conditions
416
+ conditions.push('module');
417
+ conditions.push(optimizationOptions.scripts ? 'production' : 'development');
418
+ }
396
419
  return {
397
420
  absWorkingDir: workspaceRoot,
398
421
  format: 'esm',
399
422
  bundle: true,
400
423
  packages: 'bundle',
401
424
  assetNames: outputNames.media,
402
- conditions: [
403
- 'es2020',
404
- 'es2015',
405
- 'module',
406
- optimizationOptions.scripts ? 'production' : 'development',
407
- ],
425
+ conditions,
408
426
  resolveExtensions: ['.ts', '.tsx', '.mjs', '.js', '.cjs'],
409
427
  metafile: true,
410
428
  legalComments: options.extractLicenses ? 'none' : 'eof',
@@ -416,6 +434,7 @@ function getEsBuildCommonOptions(options) {
416
434
  outdir: workspaceRoot,
417
435
  outExtension: outExtension ? { '.js': `.${outExtension}` } : undefined,
418
436
  sourcemap: sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
437
+ sourcesContent: sourcemapOptions.sourcesContent,
419
438
  splitting: true,
420
439
  chunkNames: options.namedChunks ? '[name]-[hash]' : 'chunk-[hash]',
421
440
  tsconfig,
@@ -35,6 +35,7 @@ function createGlobalStylesBundleOptions(options, target, initial) {
35
35
  optimization: !!optimizationOptions.styles.minify,
36
36
  inlineFonts: !!optimizationOptions.fonts.inline,
37
37
  sourcemap: !!sourcemapOptions.styles && (sourcemapOptions.hidden ? 'external' : true),
38
+ sourcesContent: sourcemapOptions.sourcesContent,
38
39
  preserveSymlinks,
39
40
  target,
40
41
  externalDependencies,
@@ -70,9 +70,7 @@ async function transformWithBabel(filename, data, options) {
70
70
  const shouldLink = !options.skipLinker && (await requiresLinking(filename, data));
71
71
  const useInputSourcemap = options.sourcemap &&
72
72
  (!!options.thirdPartySourcemaps || !/[\\/]node_modules[\\/]/.test(filename));
73
- // @ts-expect-error Import attribute syntax plugin does not currently have type definitions
74
- const { default: importAttributePlugin } = await Promise.resolve().then(() => __importStar(require('@babel/plugin-syntax-import-attributes')));
75
- const plugins = [importAttributePlugin];
73
+ const plugins = [];
76
74
  if (options.instrumentForCoverage) {
77
75
  const { default: coveragePlugin } = await Promise.resolve().then(() => __importStar(require('../babel/plugins/add-code-coverage.js')));
78
76
  plugins.push(coveragePlugin);
@@ -16,6 +16,7 @@ export interface BundleStylesheetOptions {
16
16
  inlineFonts: boolean;
17
17
  preserveSymlinks?: boolean;
18
18
  sourcemap: boolean | 'external' | 'inline' | 'linked';
19
+ sourcesContent?: boolean;
19
20
  outputNames: {
20
21
  bundles: string;
21
22
  media: string;
@@ -47,6 +47,7 @@ function createStylesheetBundleOptions(options, cache, inlineComponentData) {
47
47
  minify: options.optimization,
48
48
  metafile: true,
49
49
  sourcemap: options.sourcemap,
50
+ sourcesContent: options.sourcesContent,
50
51
  outdir: options.workspaceRoot,
51
52
  write: false,
52
53
  platform: 'browser',
@@ -315,7 +315,7 @@ function transformSupportedBrowsersToTargets(supportedBrowsers) {
315
315
  }
316
316
  return transformed;
317
317
  }
318
- const SUPPORTED_NODE_VERSIONS = '^20.11.1 || >=22.0.0';
318
+ const SUPPORTED_NODE_VERSIONS = '^20.11.1 || >=22.11.0';
319
319
  /**
320
320
  * Transform supported Node.js versions to esbuild target.
321
321
  * @see https://esbuild.github.io/api/#target
@@ -22,11 +22,12 @@ function createAngularSsrInternalMiddleware(server, indexHtmlTransformer) {
22
22
  // which must be processed by the runtime linker, even if they are not used.
23
23
  await (0, load_esm_1.loadEsmModule)('@angular/compiler');
24
24
  const { writeResponseToNodeResponse, createWebRequestFromNodeRequest } = await (0, load_esm_1.loadEsmModule)('@angular/ssr/node');
25
- // The following is necessary because accessing the module after invalidation may result in an empty module,
26
- // which can trigger a `TypeError: ɵgetOrCreateAngularServerApp is not a function` error.
27
- // TODO: look into why.
28
- await server.ssrLoadModule('/main.server.mjs');
29
25
  const { ɵgetOrCreateAngularServerApp } = (await server.ssrLoadModule('/main.server.mjs'));
26
+ // `ɵgetOrCreateAngularServerApp` can be undefined right after an error.
27
+ // See: https://github.com/angular/angular-cli/issues/29907
28
+ if (!ɵgetOrCreateAngularServerApp) {
29
+ return next();
30
+ }
30
31
  const angularServerApp = ɵgetOrCreateAngularServerApp({
31
32
  allowStaticRouteRender: true,
32
33
  });
@@ -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.0-next.2';
13
+ const VERSION = '20.0.0-next.4';
14
14
  function hasCacheMetadata(value) {
15
15
  return (!!value &&
16
16
  typeof value === 'object' &&
@@ -13,10 +13,12 @@ function normalizeSourceMaps(sourceMap) {
13
13
  const styles = typeof sourceMap === 'object' ? sourceMap.styles : sourceMap;
14
14
  const hidden = (typeof sourceMap === 'object' && sourceMap.hidden) || false;
15
15
  const vendor = (typeof sourceMap === 'object' && sourceMap.vendor) || false;
16
+ const sourcesContent = typeof sourceMap === 'object' ? sourceMap.sourcesContent : sourceMap;
16
17
  return {
17
18
  vendor,
18
19
  hidden,
19
20
  scripts,
20
21
  styles,
22
+ sourcesContent,
21
23
  };
22
24
  }
@@ -34,7 +34,7 @@ async function launchServer() {
34
34
  // handle request
35
35
  if ((0, utils_1.isSsrNodeRequestHandler)(reqHandler)) {
36
36
  await reqHandler(req, res, (e) => {
37
- throw e;
37
+ throw e ?? new Error(`Unable to handle request: '${req.url}'.`);
38
38
  });
39
39
  }
40
40
  else {
@@ -54,7 +54,7 @@ async function prerenderPages(workspaceRoot, baseHref, appShellOptions, prerende
54
54
  // Get routes to prerender
55
55
  const { errors: extractionErrors, serializedRouteTree: serializableRouteTreeNode, appShellRoute, } = await getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, assetsReversed, appShellOptions, prerenderOptions, sourcemap, outputMode).catch((err) => {
56
56
  return {
57
- errors: [`An error occurred while extracting routes.\n\n${err.stack ?? err.message ?? err}`],
57
+ errors: [`An error occurred while extracting routes.\n\n${err.message ?? err.stack ?? err}`],
58
58
  serializedRouteTree: [],
59
59
  appShellRoute: undefined,
60
60
  };
@@ -150,7 +150,7 @@ async function renderPages(baseHref, sourcemap, serializableRouteTreeNode, maxTh
150
150
  }
151
151
  })
152
152
  .catch((err) => {
153
- errors.push(`An error occurred while prerendering route '${route}'.\n\n${err.stack ?? err.message ?? err.code ?? err}`);
153
+ errors.push(`An error occurred while prerendering route '${route}'.\n\n${err.message ?? err.stack ?? err.code ?? err}`);
154
154
  void renderWorker.destroy();
155
155
  });
156
156
  renderingPromises.push(renderResult);
@@ -222,7 +222,7 @@ async function getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, asset
222
222
  (0, error_1.assertIsError)(err);
223
223
  return {
224
224
  errors: [
225
- `An error occurred while extracting routes.\n\n${err.stack ?? err.message ?? err.code ?? err}`,
225
+ `An error occurred while extracting routes.\n\n${err.message ?? err.stack ?? err.code ?? err}`,
226
226
  ],
227
227
  serializedRouteTree: [],
228
228
  };