@angular/build 19.0.0-next.0 → 19.0.0-next.10

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 (116) hide show
  1. package/LICENSE +5 -5
  2. package/package.json +20 -16
  3. package/src/builders/application/build-action.js +9 -9
  4. package/src/builders/application/chunk-optimizer.js +1 -4
  5. package/src/builders/application/execute-build.js +19 -2
  6. package/src/builders/application/execute-post-bundle.d.ts +2 -2
  7. package/src/builders/application/execute-post-bundle.js +58 -20
  8. package/src/builders/application/i18n.d.ts +2 -2
  9. package/src/builders/application/i18n.js +6 -16
  10. package/src/builders/application/index.js +8 -5
  11. package/src/builders/application/options.d.ts +36 -1
  12. package/src/builders/application/options.js +60 -3
  13. package/src/builders/application/schema.d.ts +15 -0
  14. package/src/builders/application/schema.js +11 -1
  15. package/src/builders/application/schema.json +5 -0
  16. package/src/builders/application/setup-bundling.js +12 -9
  17. package/src/builders/dev-server/internal.d.ts +0 -1
  18. package/src/builders/dev-server/internal.js +1 -3
  19. package/src/builders/dev-server/vite-server.d.ts +8 -2
  20. package/src/builders/dev-server/vite-server.js +111 -56
  21. package/src/builders/extract-i18n/application-extraction.js +7 -3
  22. package/src/tools/angular/angular-host.d.ts +2 -1
  23. package/src/tools/angular/angular-host.js +20 -1
  24. package/src/tools/angular/compilation/angular-compilation.d.ts +1 -0
  25. package/src/tools/angular/compilation/aot-compilation.d.ts +1 -0
  26. package/src/tools/angular/compilation/aot-compilation.js +9 -1
  27. package/src/tools/angular/compilation/jit-compilation.js +2 -1
  28. package/src/tools/angular/compilation/parallel-compilation.d.ts +2 -1
  29. package/src/tools/angular/compilation/parallel-compilation.js +2 -10
  30. package/src/tools/angular/compilation/parallel-worker.d.ts +1 -0
  31. package/src/tools/angular/compilation/parallel-worker.js +2 -1
  32. package/src/tools/babel/plugins/add-code-coverage.d.ts +14 -0
  33. package/src/tools/babel/plugins/add-code-coverage.js +44 -0
  34. package/src/tools/babel/plugins/types.d.ts +20 -0
  35. package/src/tools/esbuild/angular/compiler-plugin.d.ts +2 -0
  36. package/src/tools/esbuild/angular/compiler-plugin.js +46 -4
  37. package/src/tools/esbuild/angular/component-stylesheets.d.ts +8 -3
  38. package/src/tools/esbuild/angular/component-stylesheets.js +46 -11
  39. package/src/tools/esbuild/angular/file-reference-tracker.d.ts +1 -1
  40. package/src/tools/esbuild/application-code-bundle.d.ts +2 -6
  41. package/src/tools/esbuild/application-code-bundle.js +208 -92
  42. package/src/tools/esbuild/budget-stats.js +1 -1
  43. package/src/tools/esbuild/bundler-context.d.ts +4 -3
  44. package/src/tools/esbuild/bundler-context.js +21 -13
  45. package/src/tools/esbuild/bundler-execution-result.d.ts +5 -2
  46. package/src/tools/esbuild/bundler-execution-result.js +7 -3
  47. package/src/tools/esbuild/cache.d.ts +6 -1
  48. package/src/tools/esbuild/cache.js +7 -0
  49. package/src/tools/esbuild/compiler-plugin-options.js +3 -1
  50. package/src/tools/esbuild/i18n-inliner.js +4 -4
  51. package/src/tools/esbuild/javascript-transformer-worker.d.ts +1 -0
  52. package/src/tools/esbuild/javascript-transformer-worker.js +5 -1
  53. package/src/tools/esbuild/javascript-transformer.d.ts +2 -2
  54. package/src/tools/esbuild/javascript-transformer.js +7 -12
  55. package/src/tools/esbuild/utils.d.ts +9 -0
  56. package/src/tools/esbuild/utils.js +21 -3
  57. package/src/tools/sass/sass-service.js +11 -13
  58. package/src/tools/sass/worker.d.ts +13 -32
  59. package/src/tools/sass/worker.js +1 -0
  60. package/src/tools/vite/middlewares/assets-middleware.d.ts +1 -1
  61. package/src/tools/vite/middlewares/assets-middleware.js +43 -4
  62. package/src/tools/vite/middlewares/headers-middleware.d.ts +19 -0
  63. package/src/tools/vite/middlewares/headers-middleware.js +34 -0
  64. package/src/tools/vite/middlewares/html-fallback-middleware.d.ts +1 -1
  65. package/src/tools/vite/middlewares/html-fallback-middleware.js +23 -7
  66. package/src/tools/vite/middlewares/index-html-middleware.js +1 -2
  67. package/src/tools/vite/middlewares/index.d.ts +2 -1
  68. package/src/tools/vite/middlewares/index.js +5 -2
  69. package/src/tools/vite/middlewares/ssr-middleware.d.ts +2 -4
  70. package/src/tools/vite/middlewares/ssr-middleware.js +75 -43
  71. package/src/tools/vite/plugins/angular-memory-plugin.d.ts +16 -0
  72. package/src/tools/vite/{angular-memory-plugin.js → plugins/angular-memory-plugin.js} +19 -40
  73. package/src/tools/vite/{i18n-locale-plugin.d.ts → plugins/i18n-locale-plugin.d.ts} +0 -4
  74. package/src/tools/vite/{i18n-locale-plugin.js → plugins/i18n-locale-plugin.js} +2 -3
  75. package/src/tools/vite/plugins/index.d.ts +12 -0
  76. package/src/tools/vite/plugins/index.js +21 -0
  77. package/src/tools/vite/plugins/setup-middlewares-plugin.d.ts +41 -0
  78. package/src/tools/vite/plugins/setup-middlewares-plugin.js +62 -0
  79. package/src/{utils/server-rendering/main-bundle-exports.js → tools/vite/plugins/ssr-transform-plugin.d.ts} +2 -2
  80. package/src/tools/vite/plugins/ssr-transform-plugin.js +38 -0
  81. package/src/tools/vite/utils.d.ts +0 -3
  82. package/src/tools/vite/utils.js +0 -12
  83. package/src/typings.d.ts +26 -0
  84. package/src/utils/environment-options.d.ts +2 -0
  85. package/src/utils/environment-options.js +5 -1
  86. package/src/utils/index-file/index-html-generator.js +5 -0
  87. package/src/utils/index-file/inline-critical-css.js +43 -33
  88. package/src/utils/index-file/ngcm-attribute.d.ts +15 -0
  89. package/src/utils/index-file/ngcm-attribute.js +37 -0
  90. package/src/utils/index-file/valid-self-closing-tags.js +28 -0
  91. package/src/utils/normalize-cache.js +1 -1
  92. package/src/utils/server-rendering/fetch-patch.d.ts +1 -1
  93. package/src/utils/server-rendering/fetch-patch.js +5 -6
  94. package/src/utils/server-rendering/launch-server.d.ts +14 -0
  95. package/src/utils/server-rendering/launch-server.js +63 -0
  96. package/src/utils/server-rendering/load-esm-from-memory.d.ts +18 -2
  97. package/src/utils/server-rendering/manifest.d.ts +50 -0
  98. package/src/utils/server-rendering/manifest.js +126 -0
  99. package/src/utils/server-rendering/models.d.ts +27 -0
  100. package/src/utils/server-rendering/models.js +22 -0
  101. package/src/utils/server-rendering/prerender.d.ts +26 -10
  102. package/src/utils/server-rendering/prerender.js +126 -67
  103. package/src/utils/server-rendering/render-worker.d.ts +9 -8
  104. package/src/utils/server-rendering/render-worker.js +19 -14
  105. package/src/utils/server-rendering/routes-extractor-worker.d.ts +6 -10
  106. package/src/utils/server-rendering/routes-extractor-worker.js +16 -33
  107. package/src/utils/server-rendering/utils.d.ts +11 -0
  108. package/src/utils/server-rendering/utils.js +17 -0
  109. package/src/utils/worker-pool.d.ts +12 -0
  110. package/src/utils/worker-pool.js +43 -0
  111. package/src/tools/vite/angular-memory-plugin.d.ts +0 -21
  112. package/src/utils/server-rendering/main-bundle-exports.d.ts +0 -27
  113. package/src/utils/server-rendering/render-page.d.ts +0 -26
  114. package/src/utils/server-rendering/render-page.js +0 -114
  115. /package/src/tools/vite/{id-prefix-plugin.d.ts → plugins/id-prefix-plugin.d.ts} +0 -0
  116. /package/src/tools/vite/{id-prefix-plugin.js → plugins/id-prefix-plugin.js} +0 -0
@@ -39,10 +39,9 @@ const node_assert_1 = __importDefault(require("node:assert"));
39
39
  const promises_1 = require("node:fs/promises");
40
40
  const node_module_1 = require("node:module");
41
41
  const node_path_1 = require("node:path");
42
- const angular_memory_plugin_1 = require("../../tools/vite/angular-memory-plugin");
43
- const i18n_locale_plugin_1 = require("../../tools/vite/i18n-locale-plugin");
44
- const id_prefix_plugin_1 = require("../../tools/vite/id-prefix-plugin");
42
+ const plugins_1 = require("../../tools/vite/plugins");
45
43
  const utils_1 = require("../../utils");
44
+ const environment_options_1 = require("../../utils/environment-options");
46
45
  const load_esm_1 = require("../../utils/load-esm");
47
46
  const results_1 = require("../application/results");
48
47
  const internal_1 = require("./internal");
@@ -66,17 +65,17 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
66
65
  }
67
66
  // TODO: Adjust architect to not force a JsonObject derived return type
68
67
  const browserOptions = (await context.validateOptions(rawBrowserOptions, builderName));
69
- if (browserOptions.prerender || browserOptions.ssr) {
68
+ if (browserOptions.prerender || (browserOptions.outputMode && browserOptions.server)) {
70
69
  // Disable prerendering if enabled and force SSR.
71
70
  // This is so instead of prerendering all the routes for every change, the page is "prerendered" when it is requested.
72
71
  browserOptions.prerender = false;
73
- // Avoid bundling and processing the ssr entry-point as this is not used by the dev-server.
74
- browserOptions.ssr = true;
75
- // https://nodejs.org/api/process.html#processsetsourcemapsenabledval
76
- process.setSourceMapsEnabled(true);
72
+ browserOptions.ssr ||= true;
77
73
  }
78
74
  // Set all packages as external to support Vite's prebundle caching
79
75
  browserOptions.externalPackages = serverOptions.prebundle;
76
+ // Disable generating a full manifest with routes.
77
+ // This is done during runtime when using the dev-server.
78
+ browserOptions.partialSSRBuild = true;
80
79
  // The development server currently only supports a single locale when localizing.
81
80
  // This matches the behavior of the Webpack-based development server but could be expanded in the future.
82
81
  if (browserOptions.localize === true ||
@@ -88,7 +87,13 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
88
87
  // When localization is enabled with a single locale, force a flat path to maintain behavior with the existing Webpack-based dev server.
89
88
  browserOptions.forceI18nFlatOutput = true;
90
89
  }
91
- const { vendor: thirdPartySourcemaps } = (0, utils_1.normalizeSourceMaps)(browserOptions.sourceMap ?? false);
90
+ const { vendor: thirdPartySourcemaps, scripts: scriptsSourcemaps } = (0, utils_1.normalizeSourceMaps)(browserOptions.sourceMap ?? false);
91
+ if (scriptsSourcemaps && browserOptions.server) {
92
+ // https://nodejs.org/api/process.html#processsetsourcemapsenabledval
93
+ process.setSourceMapsEnabled(true);
94
+ }
95
+ // TODO: Enable by default once full support across CLI and FW is integrated
96
+ browserOptions.externalRuntimeStyles = environment_options_1.useComponentStyleHmr;
92
97
  // Setup the prebundling transformer that will be shared across Vite prebundling requests
93
98
  const prebundleTransformer = new internal_1.JavaScriptTransformer(
94
99
  // Always enable JIT linking to support applications built with and without AOT.
@@ -107,8 +112,10 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
107
112
  const externalMetadata = {
108
113
  implicitBrowser: [],
109
114
  implicitServer: [],
110
- explicit: [],
115
+ explicitBrowser: [],
116
+ explicitServer: [],
111
117
  };
118
+ const usedComponentStyles = new Map();
112
119
  // Add cleanup logic via a builder teardown.
113
120
  let deferred;
114
121
  context.addTeardown(async () => {
@@ -122,7 +129,7 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
122
129
  case results_1.ResultKind.Failure:
123
130
  if (result.errors.length && server) {
124
131
  hadError = true;
125
- server.hot.send({
132
+ server.ws.send({
126
133
  type: 'error',
127
134
  err: {
128
135
  message: result.errors[0].text,
@@ -169,7 +176,7 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
169
176
  if (hadError && server) {
170
177
  hadError = false;
171
178
  // Send an empty update to clear the error overlay
172
- server.hot.send({
179
+ server.ws.send({
173
180
  'type': 'update',
174
181
  updates: [],
175
182
  });
@@ -178,8 +185,8 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
178
185
  let requiresServerRestart = false;
179
186
  if (result.detail?.['externalMetadata']) {
180
187
  const { implicitBrowser, implicitServer, explicit } = result.detail['externalMetadata'];
181
- const implicitServerFiltered = implicitServer.filter((m) => removeNodeJsBuiltinModules(m) && removeAbsoluteUrls(m));
182
- const implicitBrowserFiltered = implicitBrowser.filter(removeAbsoluteUrls);
188
+ const implicitServerFiltered = implicitServer.filter((m) => !(0, node_module_1.isBuiltin)(m) && !isAbsoluteUrl(m));
189
+ const implicitBrowserFiltered = implicitBrowser.filter((m) => !isAbsoluteUrl(m));
183
190
  if (browserOptions.ssr && serverOptions.prebundle !== false) {
184
191
  const previousImplicitServer = new Set(externalMetadata.implicitServer);
185
192
  // Restart the server to force SSR dep re-optimization when a dependency has been added.
@@ -187,15 +194,18 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
187
194
  requiresServerRestart = implicitServerFiltered.some((dep) => !previousImplicitServer.has(dep));
188
195
  }
189
196
  // Empty Arrays to avoid growing unlimited with every re-build.
190
- externalMetadata.explicit.length = 0;
197
+ externalMetadata.explicitBrowser.length = 0;
198
+ externalMetadata.explicitServer.length = 0;
191
199
  externalMetadata.implicitServer.length = 0;
192
200
  externalMetadata.implicitBrowser.length = 0;
193
- externalMetadata.explicit.push(...explicit);
201
+ externalMetadata.explicitBrowser.push(...explicit);
202
+ externalMetadata.explicitServer.push(...explicit, ...node_module_1.builtinModules);
194
203
  externalMetadata.implicitServer.push(...implicitServerFiltered);
195
204
  externalMetadata.implicitBrowser.push(...implicitBrowserFiltered);
196
205
  // The below needs to be sorted as Vite uses these options are part of the hashing invalidation algorithm.
197
206
  // See: https://github.com/vitejs/vite/blob/0873bae0cfe0f0718ad2f5743dd34a17e4ab563d/packages/vite/src/node/optimizer/index.ts#L1203-L1239
198
- externalMetadata.explicit.sort();
207
+ externalMetadata.explicitBrowser.sort();
208
+ externalMetadata.explicitServer.sort();
199
209
  externalMetadata.implicitServer.sort();
200
210
  externalMetadata.implicitBrowser.sort();
201
211
  }
@@ -204,12 +214,14 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
204
214
  server.config.server.fs.allow = [
205
215
  ...new Set([...server.config.server.fs.allow, ...assetFiles.values()]),
206
216
  ];
207
- handleUpdate(normalizePath, generatedFiles, server, serverOptions, context.logger);
208
217
  if (requiresServerRestart) {
209
218
  // Restart the server to force SSR dep re-optimization when a dependency has been added.
210
219
  // This is a workaround for: https://github.com/vitejs/vite/issues/14896
211
220
  await server.restart();
212
221
  }
222
+ else {
223
+ await handleUpdate(normalizePath, generatedFiles, server, serverOptions, context.logger, usedComponentStyles);
224
+ }
213
225
  }
214
226
  else {
215
227
  const projectName = context.target?.project;
@@ -231,15 +243,25 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
231
243
  const polyfills = Array.isArray((browserOptions.polyfills ??= []))
232
244
  ? browserOptions.polyfills
233
245
  : [browserOptions.polyfills];
246
+ let ssrMode = plugins_1.ServerSsrMode.NoSsr;
247
+ if (browserOptions.outputMode &&
248
+ typeof browserOptions.ssr === 'object' &&
249
+ browserOptions.ssr.entry) {
250
+ ssrMode = plugins_1.ServerSsrMode.ExternalSsrMiddleware;
251
+ }
252
+ else if (browserOptions.ssr) {
253
+ ssrMode = plugins_1.ServerSsrMode.InternalSsrMiddleware;
254
+ }
255
+ if (browserOptions.progress !== false && ssrMode !== plugins_1.ServerSsrMode.NoSsr) {
256
+ // This is a workaround for https://github.com/angular/angular-cli/issues/28336, which is caused by the interaction between `zone.js` and `listr2`.
257
+ process.once('SIGINT', () => {
258
+ process.kill(process.pid);
259
+ });
260
+ }
234
261
  // Setup server and start listening
235
- const serverConfiguration = await setupServer(serverOptions, generatedFiles, assetFiles, browserOptions.preserveSymlinks, externalMetadata, !!browserOptions.ssr, prebundleTransformer, target, (0, internal_1.isZonelessApp)(polyfills), browserOptions.loader, extensions?.middleware, transformers?.indexHtml, thirdPartySourcemaps);
262
+ const serverConfiguration = await setupServer(serverOptions, generatedFiles, assetFiles, browserOptions.preserveSymlinks, externalMetadata, ssrMode, prebundleTransformer, target, (0, internal_1.isZonelessApp)(polyfills), usedComponentStyles, browserOptions.loader, extensions?.middleware, transformers?.indexHtml, thirdPartySourcemaps);
236
263
  server = await createServer(serverConfiguration);
237
264
  await server.listen();
238
- if (browserOptions.ssr && serverOptions.prebundle !== false) {
239
- // Warm up the SSR request and begin optimizing dependencies.
240
- // Without this, Vite will only start optimizing SSR modules when the first request is made.
241
- void server.warmupRequest('./main.server.mjs', { ssr: true });
242
- }
243
265
  const urls = server.resolvedUrls;
244
266
  if (urls && (urls.local.length || urls.network.length)) {
245
267
  serverUrl = new URL(urls.local[0] ?? urls.network[0]);
@@ -253,7 +275,7 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
253
275
  key: 'r',
254
276
  description: 'force reload browser',
255
277
  action(server) {
256
- server.hot.send({
278
+ server.ws.send({
257
279
  type: 'full-reload',
258
280
  path: '*',
259
281
  });
@@ -271,15 +293,24 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
271
293
  }
272
294
  await new Promise((resolve) => (deferred = resolve));
273
295
  }
274
- function handleUpdate(normalizePath, generatedFiles, server, serverOptions, logger) {
296
+ async function handleUpdate(normalizePath, generatedFiles, server, serverOptions, logger, usedComponentStyles) {
275
297
  const updatedFiles = [];
298
+ let destroyAngularServerAppCalled = false;
276
299
  // Invalidate any updated files
277
- for (const [file, record] of generatedFiles) {
278
- if (record.updated) {
279
- updatedFiles.push(file);
280
- const updatedModules = server.moduleGraph.getModulesByFile(normalizePath((0, node_path_1.join)(server.config.root, file)));
281
- updatedModules?.forEach((m) => server?.moduleGraph.invalidateModule(m));
300
+ for (const [file, { updated, type }] of generatedFiles) {
301
+ if (!updated) {
302
+ continue;
282
303
  }
304
+ if (type === internal_1.BuildOutputFileType.ServerApplication && !destroyAngularServerAppCalled) {
305
+ // Clear the server app cache
306
+ // This must be done before module invalidation.
307
+ const { ɵdestroyAngularServerApp } = (await server.ssrLoadModule('/main.server.mjs'));
308
+ ɵdestroyAngularServerApp();
309
+ destroyAngularServerAppCalled = true;
310
+ }
311
+ updatedFiles.push(file);
312
+ const updatedModules = server.moduleGraph.getModulesByFile(normalizePath((0, node_path_1.join)(server.config.root, file)));
313
+ updatedModules?.forEach((m) => server.moduleGraph.invalidateModule(m));
283
314
  }
284
315
  if (!updatedFiles.length) {
285
316
  return;
@@ -287,9 +318,23 @@ function handleUpdate(normalizePath, generatedFiles, server, serverOptions, logg
287
318
  if (serverOptions.liveReload || serverOptions.hmr) {
288
319
  if (updatedFiles.every((f) => f.endsWith('.css'))) {
289
320
  const timestamp = Date.now();
290
- server.hot.send({
321
+ server.ws.send({
291
322
  type: 'update',
292
- updates: updatedFiles.map((filePath) => {
323
+ updates: updatedFiles.flatMap((filePath) => {
324
+ // For component styles, an HMR update must be sent for each one with the corresponding
325
+ // component identifier search parameter (`ngcomp`). The Vite client code will not keep
326
+ // the existing search parameters when it performs an update and each one must be
327
+ // specified explicitly. Typically, there is only one each though as specific style files
328
+ // are not typically reused across components.
329
+ const componentIds = usedComponentStyles.get(filePath);
330
+ if (componentIds) {
331
+ return componentIds.map((id) => ({
332
+ type: 'css-update',
333
+ timestamp,
334
+ path: `${filePath}?ngcomp` + (id ? `=${id}` : ''),
335
+ acceptedPath: filePath,
336
+ }));
337
+ }
293
338
  return {
294
339
  type: 'css-update',
295
340
  timestamp,
@@ -304,7 +349,7 @@ function handleUpdate(normalizePath, generatedFiles, server, serverOptions, logg
304
349
  }
305
350
  // Send reload command to clients
306
351
  if (serverOptions.liveReload) {
307
- server.hot.send({
352
+ server.ws.send({
308
353
  type: 'full-reload',
309
354
  path: '*',
310
355
  });
@@ -334,6 +379,7 @@ function analyzeResultFiles(normalizePath, htmlIndexPath, resultFiles, generated
334
379
  contents: file.contents,
335
380
  servable,
336
381
  size: file.contents.byteLength,
382
+ type: file.type,
337
383
  updated: false,
338
384
  });
339
385
  continue;
@@ -352,6 +398,7 @@ function analyzeResultFiles(normalizePath, htmlIndexPath, resultFiles, generated
352
398
  size: file.contents.byteLength,
353
399
  hash: file.hash,
354
400
  updated: true,
401
+ type: file.type,
355
402
  servable,
356
403
  });
357
404
  }
@@ -362,13 +409,13 @@ function analyzeResultFiles(normalizePath, htmlIndexPath, resultFiles, generated
362
409
  }
363
410
  }
364
411
  }
365
- async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks, externalMetadata, ssr, prebundleTransformer, target, zoneless, prebundleLoaderExtensions, extensionMiddleware, indexHtmlTransformer, thirdPartySourcemaps = false) {
412
+ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks, externalMetadata, ssrMode, prebundleTransformer, target, zoneless, usedComponentStyles, prebundleLoaderExtensions, extensionMiddleware, indexHtmlTransformer, thirdPartySourcemaps = false) {
366
413
  const proxy = await (0, utils_1.loadProxyConfiguration)(serverOptions.workspaceRoot, serverOptions.proxyConfig);
367
414
  // dynamically import Vite for ESM compatibility
368
415
  const { normalizePath } = await (0, load_esm_1.loadEsmModule)('vite');
369
416
  // Path will not exist on disk and only used to provide separate path for Vite requests
370
417
  const virtualProjectRoot = normalizePath((0, node_path_1.join)(serverOptions.workspaceRoot, `.angular/vite-root`, serverOptions.buildTarget.project));
371
- const cacheDir = (0, node_path_1.join)(serverOptions.cacheOptions.path, 'vite');
418
+ const cacheDir = (0, node_path_1.join)(serverOptions.cacheOptions.path, serverOptions.buildTarget.project, 'vite');
372
419
  const configuration = {
373
420
  configFile: false,
374
421
  envFile: false,
@@ -397,6 +444,9 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
397
444
  preserveSymlinks,
398
445
  },
399
446
  server: {
447
+ warmup: {
448
+ ssrFiles: ['./main.server.mjs', './server.mjs'],
449
+ },
400
450
  port: serverOptions.port,
401
451
  strictPort: true,
402
452
  host: serverOptions.host,
@@ -422,18 +472,18 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
422
472
  },
423
473
  // This is needed when `externalDependencies` is used to prevent Vite load errors.
424
474
  // NOTE: If Vite adds direct support for externals, this can be removed.
425
- preTransformRequests: externalMetadata.explicit.length === 0,
475
+ preTransformRequests: externalMetadata.explicitBrowser.length === 0,
426
476
  },
427
477
  ssr: {
428
478
  // Note: `true` and `/.*/` have different sematics. When true, the `external` option is ignored.
429
479
  noExternal: /.*/,
430
480
  // Exclude any Node.js built in module and provided dependencies (currently build defined externals)
431
- external: externalMetadata.explicit,
481
+ external: externalMetadata.explicitServer,
432
482
  optimizeDeps: getDepOptimizationConfig({
433
483
  // Only enable with caching since it causes prebundle dependencies to be cached
434
484
  disabled: serverOptions.prebundle === false,
435
485
  // Exclude any explicitly defined dependencies (currently build defined externals and node.js built-ins)
436
- exclude: externalMetadata.explicit,
486
+ exclude: externalMetadata.explicitServer,
437
487
  // Include all implict dependencies from the external packages internal option
438
488
  include: externalMetadata.implicitServer,
439
489
  ssr: true,
@@ -445,26 +495,29 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
445
495
  }),
446
496
  },
447
497
  plugins: [
448
- (0, i18n_locale_plugin_1.createAngularLocaleDataPlugin)(),
449
- (0, angular_memory_plugin_1.createAngularMemoryPlugin)({
450
- workspaceRoot: serverOptions.workspaceRoot,
451
- virtualProjectRoot,
498
+ (0, plugins_1.createAngularLocaleDataPlugin)(),
499
+ (0, plugins_1.createAngularSetupMiddlewaresPlugin)({
452
500
  outputFiles,
453
501
  assets,
454
- ssr,
455
- external: externalMetadata.explicit,
456
502
  indexHtmlTransformer,
457
503
  extensionMiddleware,
458
- normalizePath,
504
+ usedComponentStyles,
505
+ ssrMode,
506
+ }),
507
+ (0, plugins_1.createRemoveIdPrefixPlugin)(externalMetadata.explicitBrowser),
508
+ await (0, plugins_1.createAngularSsrTransformPlugin)(serverOptions.workspaceRoot),
509
+ await (0, plugins_1.createAngularMemoryPlugin)({
510
+ virtualProjectRoot,
511
+ outputFiles,
512
+ external: externalMetadata.explicitBrowser,
459
513
  }),
460
- (0, id_prefix_plugin_1.createRemoveIdPrefixPlugin)(externalMetadata.explicit),
461
514
  ],
462
515
  // Browser only optimizeDeps. (This does not run for SSR dependencies).
463
516
  optimizeDeps: getDepOptimizationConfig({
464
517
  // Only enable with caching since it causes prebundle dependencies to be cached
465
518
  disabled: serverOptions.prebundle === false,
466
519
  // Exclude any explicitly defined dependencies (currently build defined externals)
467
- exclude: externalMetadata.explicit,
520
+ exclude: externalMetadata.explicitBrowser,
468
521
  // Include all implict dependencies from the external packages internal option
469
522
  include: externalMetadata.implicitBrowser,
470
523
  ssr: false,
@@ -525,12 +578,14 @@ function getDepOptimizationConfig({ disabled, exclude, include, target, zoneless
525
578
  },
526
579
  };
527
580
  }
528
- const nodeJsBuiltinModules = new Set(node_module_1.builtinModules);
529
- /** Remove any Node.js builtin modules to avoid Vite's prebundling from processing them as files. */
530
- function removeNodeJsBuiltinModules(value) {
531
- return !nodeJsBuiltinModules.has(value);
532
- }
533
- /** Remove any absolute URLs (http://, https://, //) to avoid Vite's prebundling from processing them as files. */
534
- function removeAbsoluteUrls(value) {
535
- return !/^(?:https?:)?\/\//.test(value);
581
+ /**
582
+ * Checks if the given value is an absolute URL.
583
+ *
584
+ * This function helps in avoiding Vite's prebundling from processing absolute URLs (http://, https://, //) as files.
585
+ *
586
+ * @param value - The URL or path to check.
587
+ * @returns `true` if the value is not an absolute URL; otherwise, `false`.
588
+ */
589
+ function isAbsoluteUrl(value) {
590
+ return /^(?:https?:)?\/\//.test(value);
536
591
  }
@@ -11,9 +11,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.extractMessages = extractMessages;
14
+ const node_fs_1 = require("node:fs");
14
15
  const node_path_1 = __importDefault(require("node:path"));
15
16
  const application_1 = require("../application");
16
17
  const results_1 = require("../application/results");
18
+ const schema_1 = require("../application/schema");
17
19
  async function extractMessages(options, builderName, context, extractorConstructor, extensions) {
18
20
  const messages = [];
19
21
  // Setup the build options for the application based on the buildTarget option
@@ -24,9 +26,8 @@ async function extractMessages(options, builderName, context, extractorConstruct
24
26
  buildOptions.budgets = undefined;
25
27
  buildOptions.index = false;
26
28
  buildOptions.serviceWorker = false;
27
- buildOptions.ssr = false;
28
- buildOptions.appShell = false;
29
- buildOptions.prerender = false;
29
+ buildOptions.outputMode = schema_1.OutputMode.Static;
30
+ buildOptions.server = undefined;
30
31
  // Build the application with the build options
31
32
  const builderResult = await first((0, application_1.buildApplicationInternal)(buildOptions, context, extensions));
32
33
  let success = false;
@@ -72,6 +73,9 @@ function setupLocalizeExtractor(extractorConstructor, files, context) {
72
73
  if (file?.origin === 'memory') {
73
74
  content = textDecoder.decode(file.contents);
74
75
  }
76
+ else if (file?.origin === 'disk') {
77
+ content = (0, node_fs_1.readFileSync)(file.inputPath, 'utf-8');
78
+ }
75
79
  if (content === undefined) {
76
80
  throw new Error('Unknown file requested: ' + requestedPath);
77
81
  }
@@ -13,7 +13,8 @@ export interface AngularHostOptions {
13
13
  fileReplacements?: Record<string, string>;
14
14
  sourceFileCache?: Map<string, ts.SourceFile>;
15
15
  modifiedFiles?: Set<string>;
16
- transformStylesheet(data: string, containingFile: string, stylesheetFile?: string): Promise<string | null>;
16
+ externalStylesheets?: Map<string, string>;
17
+ transformStylesheet(data: string, containingFile: string, stylesheetFile?: string, order?: number): Promise<string | null>;
17
18
  processWebWorker(workerFile: string, containingFile: string): string;
18
19
  }
19
20
  /**
@@ -12,6 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.ensureSourceFileVersions = ensureSourceFileVersions;
14
14
  exports.createAngularCompilerHost = createAngularCompilerHost;
15
+ const node_assert_1 = __importDefault(require("node:assert"));
15
16
  const node_crypto_1 = require("node:crypto");
16
17
  const node_path_1 = __importDefault(require("node:path"));
17
18
  /**
@@ -107,13 +108,31 @@ function createAngularCompilerHost(typescript, compilerOptions, hostOptions) {
107
108
  if (context.type !== 'style') {
108
109
  return null;
109
110
  }
111
+ (0, node_assert_1.default)(!context.resourceFile || !hostOptions.externalStylesheets?.has(context.resourceFile), 'External runtime stylesheets should not be transformed: ' + context.resourceFile);
110
112
  // No transformation required if the resource is empty
111
113
  if (data.trim().length === 0) {
112
114
  return { content: '' };
113
115
  }
114
- const result = await hostOptions.transformStylesheet(data, context.containingFile, context.resourceFile ?? undefined);
116
+ const result = await hostOptions.transformStylesheet(data, context.containingFile, context.resourceFile ?? undefined,
117
+ // TODO: Remove once available in compiler-cli types
118
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
119
+ context.order);
115
120
  return typeof result === 'string' ? { content: result } : null;
116
121
  };
122
+ host.resourceNameToFileName = function (resourceName, containingFile) {
123
+ const resolvedPath = node_path_1.default.join(node_path_1.default.dirname(containingFile), resourceName);
124
+ // All resource names that have HTML file extensions are assumed to be templates
125
+ if (resourceName.endsWith('.html') || !hostOptions.externalStylesheets) {
126
+ return resolvedPath;
127
+ }
128
+ // For external stylesheets, create a unique identifier and store the mapping
129
+ let externalId = hostOptions.externalStylesheets.get(resolvedPath);
130
+ if (externalId === undefined) {
131
+ externalId = (0, node_crypto_1.createHash)('sha256').update(resolvedPath).digest('hex');
132
+ hostOptions.externalStylesheets.set(resolvedPath, externalId);
133
+ }
134
+ return externalId + '.css';
135
+ };
117
136
  // Allow the AOT compiler to request the set of changed templates and styles
118
137
  host.getModifiedResourceFiles = function () {
119
138
  return hostOptions.modifiedFiles;
@@ -30,6 +30,7 @@ export declare abstract class AngularCompilation {
30
30
  affectedFiles: ReadonlySet<ts.SourceFile>;
31
31
  compilerOptions: ng.CompilerOptions;
32
32
  referencedFiles: readonly string[];
33
+ externalStylesheets?: ReadonlyMap<string, string>;
33
34
  }>;
34
35
  abstract emitAffectedFiles(): Iterable<EmitFileResult> | Promise<Iterable<EmitFileResult>>;
35
36
  protected abstract collectDiagnostics(modes: DiagnosticModes): Iterable<ts.Diagnostic> | Promise<Iterable<ts.Diagnostic>>;
@@ -15,6 +15,7 @@ export declare class AotCompilation extends AngularCompilation {
15
15
  affectedFiles: ReadonlySet<ts.SourceFile>;
16
16
  compilerOptions: ng.CompilerOptions;
17
17
  referencedFiles: readonly string[];
18
+ externalStylesheets?: ReadonlyMap<string, string>;
18
19
  }>;
19
20
  collectDiagnostics(modes: DiagnosticModes): Iterable<ts.Diagnostic>;
20
21
  emitAffectedFiles(): Iterable<EmitFileResult>;
@@ -47,6 +47,9 @@ class AotCompilation extends angular_compilation_1.AngularCompilation {
47
47
  // Load the compiler configuration and transform as needed
48
48
  const { options: originalCompilerOptions, rootNames, errors: configurationDiagnostics, } = await this.loadConfiguration(tsconfig);
49
49
  const compilerOptions = compilerOptionsTransformer?.(originalCompilerOptions) ?? originalCompilerOptions;
50
+ if (compilerOptions.externalRuntimeStyles) {
51
+ hostOptions.externalStylesheets ??= new Map();
52
+ }
50
53
  // Create Angular compiler host
51
54
  const host = (0, angular_host_1.createAngularCompilerHost)(typescript_1.default, compilerOptions, hostOptions);
52
55
  // Create the Angular specific program that contains the Angular compiler
@@ -82,7 +85,12 @@ class AotCompilation extends angular_compilation_1.AngularCompilation {
82
85
  return [sourceFile.fileName, ...resourceDependencies];
83
86
  });
84
87
  this.#state = new AngularCompilationState(angularProgram, host, typeScriptProgram, affectedFiles, affectedFiles.size === 1 ? OptimizeFor.SingleFile : OptimizeFor.WholeProgram, (0, web_worker_transformer_1.createWorkerTransformer)(hostOptions.processWebWorker.bind(hostOptions)), this.#state?.diagnosticCache);
85
- return { affectedFiles, compilerOptions, referencedFiles };
88
+ return {
89
+ affectedFiles,
90
+ compilerOptions,
91
+ referencedFiles,
92
+ externalStylesheets: hostOptions.externalStylesheets,
93
+ };
86
94
  }
87
95
  *collectDiagnostics(modes) {
88
96
  (0, node_assert_1.default)(this.#state, 'Angular compilation must be initialized prior to collecting diagnostics.');
@@ -13,6 +13,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.JitCompilation = void 0;
14
14
  const node_assert_1 = __importDefault(require("node:assert"));
15
15
  const typescript_1 = __importDefault(require("typescript"));
16
+ const load_esm_1 = require("../../../utils/load-esm");
16
17
  const profiling_1 = require("../../esbuild/profiling");
17
18
  const angular_host_1 = require("../angular-host");
18
19
  const jit_resource_transformer_1 = require("../transformers/jit-resource-transformer");
@@ -36,7 +37,7 @@ class JitCompilation extends angular_compilation_1.AngularCompilation {
36
37
  #state;
37
38
  async initialize(tsconfig, hostOptions, compilerOptionsTransformer) {
38
39
  // Dynamically load the Angular compiler CLI package
39
- const { constructorParametersDownlevelTransform } = await angular_compilation_1.AngularCompilation.loadCompilerCli();
40
+ const { constructorParametersDownlevelTransform } = await (0, load_esm_1.loadEsmModule)('@angular/compiler-cli/private/tooling');
40
41
  // Load the compiler configuration and transform as needed
41
42
  const { options: originalCompilerOptions, rootNames, errors: configurationDiagnostics, } = await this.loadConfiguration(tsconfig);
42
43
  const compilerOptions = compilerOptionsTransformer?.(originalCompilerOptions) ?? originalCompilerOptions;
@@ -22,10 +22,11 @@ export declare class ParallelCompilation extends AngularCompilation {
22
22
  #private;
23
23
  readonly jit: boolean;
24
24
  constructor(jit: boolean);
25
- initialize(tsconfig: string, hostOptions: AngularHostOptions, compilerOptionsTransformer?: ((compilerOptions: CompilerOptions) => CompilerOptions) | undefined): Promise<{
25
+ initialize(tsconfig: string, hostOptions: AngularHostOptions, compilerOptionsTransformer?: (compilerOptions: CompilerOptions) => CompilerOptions): Promise<{
26
26
  affectedFiles: ReadonlySet<SourceFile>;
27
27
  compilerOptions: CompilerOptions;
28
28
  referencedFiles: readonly string[];
29
+ externalStylesheets?: ReadonlyMap<string, string>;
29
30
  }>;
30
31
  /**
31
32
  * This is not needed with this compilation type since the worker will already send a response
@@ -6,14 +6,11 @@
6
6
  * Use of this source code is governed by an MIT-style license that can be
7
7
  * found in the LICENSE file at https://angular.dev/license
8
8
  */
9
- var __importDefault = (this && this.__importDefault) || function (mod) {
10
- return (mod && mod.__esModule) ? mod : { "default": mod };
11
- };
12
9
  Object.defineProperty(exports, "__esModule", { value: true });
13
10
  exports.ParallelCompilation = void 0;
14
11
  const node_module_1 = require("node:module");
15
12
  const node_worker_threads_1 = require("node:worker_threads");
16
- const piscina_1 = __importDefault(require("piscina"));
13
+ const worker_pool_1 = require("../../../utils/worker-pool");
17
14
  const angular_compilation_1 = require("./angular-compilation");
18
15
  /**
19
16
  * An Angular compilation which uses a Node.js Worker thread to load and execute
@@ -31,15 +28,10 @@ class ParallelCompilation extends angular_compilation_1.AngularCompilation {
31
28
  this.jit = jit;
32
29
  // TODO: Convert to import.meta usage during ESM transition
33
30
  const localRequire = (0, node_module_1.createRequire)(__filename);
34
- this.#worker = new piscina_1.default({
35
- minThreads: 1,
31
+ this.#worker = new worker_pool_1.WorkerPool({
36
32
  maxThreads: 1,
37
33
  idleTimeout: Infinity,
38
- // Web containers do not support transferable objects with receiveOnMessagePort which
39
- // is used when the Atomics based wait loop is enable.
40
- useAtomics: !process.versions.webcontainer,
41
34
  filename: localRequire.resolve('./parallel-worker'),
42
- recordTiming: false,
43
35
  });
44
36
  }
45
37
  initialize(tsconfig, hostOptions, compilerOptionsTransformer) {
@@ -19,6 +19,7 @@ export interface InitRequest {
19
19
  webWorkerSignal: Int32Array;
20
20
  }
21
21
  export declare function initialize(request: InitRequest): Promise<{
22
+ externalStylesheets: ReadonlyMap<string, string> | undefined;
22
23
  referencedFiles: readonly string[];
23
24
  compilerOptions: {
24
25
  allowJs: boolean | undefined;
@@ -33,7 +33,7 @@ async function initialize(request) {
33
33
  stylesheetRequests.get(requestId)?.[0](value);
34
34
  }
35
35
  });
36
- const { compilerOptions, referencedFiles } = await compilation.initialize(request.tsconfig, {
36
+ const { compilerOptions, referencedFiles, externalStylesheets } = await compilation.initialize(request.tsconfig, {
37
37
  fileReplacements: request.fileReplacements,
38
38
  sourceFileCache,
39
39
  modifiedFiles: sourceFileCache.modifiedFiles,
@@ -69,6 +69,7 @@ async function initialize(request) {
69
69
  return result?.transformedOptions ?? compilerOptions;
70
70
  });
71
71
  return {
72
+ externalStylesheets,
72
73
  referencedFiles,
73
74
  // TODO: Expand? `allowJs`, `isolatedModules`, `sourceMap`, `inlineSourceMap` are the only fields needed currently.
74
75
  compilerOptions: {
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.dev/license
7
+ */
8
+ import { PluginObj } from '@babel/core';
9
+ /**
10
+ * A babel plugin factory function for adding istanbul instrumentation.
11
+ *
12
+ * @returns A babel plugin object instance.
13
+ */
14
+ export default function (): PluginObj;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google LLC All Rights Reserved.
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://angular.dev/license
8
+ */
9
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.default = default_1;
14
+ const core_1 = require("@babel/core");
15
+ const istanbul_lib_instrument_1 = require("istanbul-lib-instrument");
16
+ const node_assert_1 = __importDefault(require("node:assert"));
17
+ /**
18
+ * A babel plugin factory function for adding istanbul instrumentation.
19
+ *
20
+ * @returns A babel plugin object instance.
21
+ */
22
+ function default_1() {
23
+ const visitors = new WeakMap();
24
+ return {
25
+ visitor: {
26
+ Program: {
27
+ enter(path, state) {
28
+ const visitor = (0, istanbul_lib_instrument_1.programVisitor)(core_1.types, state.filename, {
29
+ // Babel returns a Converter object from the `convert-source-map` package
30
+ inputSourceMap: state.file.inputMap?.toObject(),
31
+ });
32
+ visitors.set(path, visitor);
33
+ visitor.enter(path);
34
+ },
35
+ exit(path) {
36
+ const visitor = visitors.get(path);
37
+ (0, node_assert_1.default)(visitor, 'Instrumentation visitor should always be present for program path.');
38
+ visitor.exit(path);
39
+ visitors.delete(path);
40
+ },
41
+ },
42
+ },
43
+ };
44
+ }