@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
@@ -12,12 +12,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.createBrowserCodeBundleOptions = createBrowserCodeBundleOptions;
14
14
  exports.createBrowserPolyfillBundleOptions = createBrowserPolyfillBundleOptions;
15
- exports.createServerCodeBundleOptions = createServerCodeBundleOptions;
16
15
  exports.createServerPolyfillBundleOptions = createServerPolyfillBundleOptions;
16
+ exports.createServerMainCodeBundleOptions = createServerMainCodeBundleOptions;
17
+ exports.createSsrEntryCodeBundleOptions = createSsrEntryCodeBundleOptions;
17
18
  const node_assert_1 = __importDefault(require("node:assert"));
18
19
  const node_crypto_1 = require("node:crypto");
19
20
  const node_path_1 = require("node:path");
20
21
  const environment_options_1 = require("../../utils/environment-options");
22
+ const manifest_1 = require("../../utils/server-rendering/manifest");
21
23
  const compiler_plugin_1 = require("./angular/compiler-plugin");
22
24
  const compiler_plugin_options_1 = require("./compiler-plugin-options");
23
25
  const external_packages_plugin_1 = require("./external-packages-plugin");
@@ -110,29 +112,28 @@ function createBrowserPolyfillBundleOptions(options, target, sourceFileCache) {
110
112
  // cannot be used with fully incremental bundling yet.
111
113
  return hasTypeScriptEntries ? buildOptions : () => buildOptions;
112
114
  }
113
- /**
114
- * Create an esbuild 'build' options object for the server bundle.
115
- * @param options The builder's user-provider normalized options.
116
- * @returns An esbuild BuildOptions object.
117
- */
118
- function createServerCodeBundleOptions(options, target, sourceFileCache) {
119
- const { serverEntryPoint, workspaceRoot, ssrOptions, watch, externalPackages, prerenderOptions, polyfills, } = options;
120
- (0, node_assert_1.default)(serverEntryPoint, 'createServerCodeBundleOptions should not be called without a defined serverEntryPoint.');
121
- const { pluginOptions, styleOptions } = (0, compiler_plugin_options_1.createCompilerPluginOptions)(options, target, sourceFileCache);
122
- const mainServerNamespace = 'angular:server-render-utils';
123
- const entryPoints = {
124
- 'render-utils.server': mainServerNamespace,
125
- 'main.server': serverEntryPoint,
126
- };
127
- const ssrEntryPoint = ssrOptions?.entry;
128
- if (ssrEntryPoint) {
129
- entryPoints['server'] = ssrEntryPoint;
115
+ function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
116
+ const serverPolyfills = [];
117
+ const polyfillsFromConfig = new Set(options.polyfills);
118
+ if (!(0, utils_1.isZonelessApp)(options.polyfills)) {
119
+ serverPolyfills.push('zone.js/node');
120
+ }
121
+ if (polyfillsFromConfig.has('@angular/localize') ||
122
+ polyfillsFromConfig.has('@angular/localize/init')) {
123
+ serverPolyfills.push('@angular/localize/init');
124
+ }
125
+ serverPolyfills.push('@angular/platform-server/init');
126
+ const namespace = 'angular:polyfills-server';
127
+ const polyfillBundleOptions = getEsBuildCommonPolyfillsOptions({
128
+ ...options,
129
+ polyfills: serverPolyfills,
130
+ }, namespace, false, sourceFileCache);
131
+ if (!polyfillBundleOptions) {
132
+ return;
130
133
  }
131
- const zoneless = (0, utils_1.isZonelessApp)(polyfills);
132
134
  const buildOptions = {
133
- ...getEsBuildCommonOptions(options),
135
+ ...polyfillBundleOptions,
134
136
  platform: 'node',
135
- splitting: true,
136
137
  outExtension: { '.js': '.mjs' },
137
138
  // Note: `es2015` is needed for RxJS v6. If not specified, `module` would
138
139
  // match and the ES5 distribution would be bundled and ends up breaking at
@@ -140,14 +141,46 @@ function createServerCodeBundleOptions(options, target, sourceFileCache) {
140
141
  // More details: https://github.com/angular/angular-cli/issues/25405.
141
142
  mainFields: ['es2020', 'es2015', 'module', 'main'],
142
143
  entryNames: '[name]',
143
- target,
144
144
  banner: {
145
- js: `import './polyfills.server.mjs';`,
145
+ js: [
146
+ // Note: Needed as esbuild does not provide require shims / proxy from ESModules.
147
+ // See: https://github.com/evanw/esbuild/issues/1921.
148
+ `import { createRequire } from 'node:module';`,
149
+ `globalThis['require'] ??= createRequire(import.meta.url);`,
150
+ ].join('\n'),
146
151
  },
152
+ target,
153
+ entryPoints: {
154
+ 'polyfills.server': namespace,
155
+ },
156
+ };
157
+ return () => buildOptions;
158
+ }
159
+ function createServerMainCodeBundleOptions(options, target, sourceFileCache) {
160
+ const { serverEntryPoint: mainServerEntryPoint, workspaceRoot, outputMode, externalPackages, ssrOptions, polyfills, } = options;
161
+ (0, node_assert_1.default)(mainServerEntryPoint, 'createServerCodeBundleOptions should not be called without a defined serverEntryPoint.');
162
+ const { pluginOptions, styleOptions } = (0, compiler_plugin_options_1.createCompilerPluginOptions)(options, target, sourceFileCache);
163
+ const mainServerNamespace = 'angular:main-server';
164
+ const mainServerInjectPolyfillsNamespace = 'angular:main-server-inject-polyfills';
165
+ const mainServerInjectManifestNamespace = 'angular:main-server-inject-manifest';
166
+ const zoneless = (0, utils_1.isZonelessApp)(polyfills);
167
+ const entryPoints = {
168
+ 'main.server': mainServerNamespace,
169
+ };
170
+ const ssrEntryPoint = ssrOptions?.entry;
171
+ const isOldBehaviour = !outputMode;
172
+ if (ssrEntryPoint && isOldBehaviour) {
173
+ // Old behavior: 'server.ts' was bundled together with the SSR (Server-Side Rendering) code.
174
+ // This approach combined server-side logic and rendering into a single bundle.
175
+ entryPoints['server'] = ssrEntryPoint;
176
+ }
177
+ const buildOptions = {
178
+ ...getEsBuildServerCommonOptions(options),
179
+ target,
180
+ inject: [mainServerInjectPolyfillsNamespace, mainServerInjectManifestNamespace],
147
181
  entryPoints,
148
182
  supported: (0, utils_1.getFeatureSupport)(target, zoneless),
149
183
  plugins: [
150
- (0, loader_import_attribute_plugin_1.createLoaderImportAttributePlugin)(),
151
184
  (0, wasm_plugin_1.createWasmPlugin)({ allowAsync: zoneless, cache: sourceFileCache?.loadResultCache }),
152
185
  (0, sourcemap_ignorelist_plugin_1.createSourcemapIgnorelistPlugin)(),
153
186
  (0, compiler_plugin_1.createCompilerPlugin)(
@@ -164,20 +197,48 @@ function createServerCodeBundleOptions(options, target, sourceFileCache) {
164
197
  else {
165
198
  buildOptions.plugins.push((0, rxjs_esm_resolution_plugin_1.createRxjsEsmResolutionPlugin)());
166
199
  }
200
+ // Mark manifest and polyfills file as external as these are generated by a different bundle step.
201
+ (buildOptions.external ??= []).push(...utils_1.SERVER_GENERATED_EXTERNALS);
167
202
  buildOptions.plugins.push((0, virtual_module_plugin_1.createVirtualModulePlugin)({
203
+ namespace: mainServerInjectPolyfillsNamespace,
204
+ cache: sourceFileCache?.loadResultCache,
205
+ loadContent: () => ({
206
+ contents: `import './polyfills.server.mjs';`,
207
+ loader: 'js',
208
+ resolveDir: workspaceRoot,
209
+ }),
210
+ }), (0, virtual_module_plugin_1.createVirtualModulePlugin)({
211
+ namespace: mainServerInjectManifestNamespace,
212
+ cache: sourceFileCache?.loadResultCache,
213
+ loadContent: async () => {
214
+ const contents = [
215
+ // Configure `@angular/ssr` manifest.
216
+ `import manifest from './${manifest_1.SERVER_APP_MANIFEST_FILENAME}';`,
217
+ `import { ɵsetAngularAppManifest } from '@angular/ssr';`,
218
+ `ɵsetAngularAppManifest(manifest);`,
219
+ ];
220
+ return {
221
+ contents: contents.join('\n'),
222
+ loader: 'js',
223
+ resolveDir: workspaceRoot,
224
+ };
225
+ },
226
+ }), (0, virtual_module_plugin_1.createVirtualModulePlugin)({
168
227
  namespace: mainServerNamespace,
169
228
  cache: sourceFileCache?.loadResultCache,
170
229
  loadContent: async () => {
230
+ const mainServerEntryPointJsImport = entryFileToWorkspaceRelative(workspaceRoot, mainServerEntryPoint);
171
231
  const contents = [
172
- `export { ɵConsole } from '@angular/core';`,
173
- `export { renderApplication, renderModule, ɵSERVER_CONTEXT } from '@angular/platform-server';`,
232
+ // Re-export all symbols including default export from 'main.server.ts'
233
+ `export { default } from '${mainServerEntryPointJsImport}';`,
234
+ `export * from '${mainServerEntryPointJsImport}';`,
235
+ // Add @angular/ssr exports
236
+ `export {
237
+ ɵdestroyAngularServerApp,
238
+ ɵextractRoutesAndCreateRouteTree,
239
+ ɵgetOrCreateAngularServerApp,
240
+ } from '@angular/ssr';`,
174
241
  ];
175
- if (watch) {
176
- contents.push(`export { ɵresetCompiledComponents } from '@angular/core';`);
177
- }
178
- if (prerenderOptions?.discoverRoutes) {
179
- contents.push(`export { ɵgetRoutesFromAngularRouterConfig } from '@angular/ssr';`);
180
- }
181
242
  return {
182
243
  contents: contents.join('\n'),
183
244
  loader: 'js',
@@ -190,27 +251,114 @@ function createServerCodeBundleOptions(options, target, sourceFileCache) {
190
251
  }
191
252
  return buildOptions;
192
253
  }
193
- function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
194
- const serverPolyfills = [];
195
- const polyfillsFromConfig = new Set(options.polyfills);
196
- if (!(0, utils_1.isZonelessApp)(options.polyfills)) {
197
- serverPolyfills.push('zone.js/node');
254
+ function createSsrEntryCodeBundleOptions(options, target, sourceFileCache) {
255
+ const { workspaceRoot, ssrOptions, externalPackages } = options;
256
+ const serverEntryPoint = ssrOptions?.entry;
257
+ (0, node_assert_1.default)(serverEntryPoint, 'createSsrEntryCodeBundleOptions should not be called without a defined serverEntryPoint.');
258
+ const { pluginOptions, styleOptions } = (0, compiler_plugin_options_1.createCompilerPluginOptions)(options, target, sourceFileCache);
259
+ const ssrEntryNamespace = 'angular:ssr-entry';
260
+ const ssrInjectManifestNamespace = 'angular:ssr-entry-inject-manifest';
261
+ const ssrInjectRequireNamespace = 'angular:ssr-entry-inject-require';
262
+ const buildOptions = {
263
+ ...getEsBuildServerCommonOptions(options),
264
+ target,
265
+ entryPoints: {
266
+ // TODO: consider renaming to index
267
+ 'server': ssrEntryNamespace,
268
+ },
269
+ supported: (0, utils_1.getFeatureSupport)(target, true),
270
+ plugins: [
271
+ (0, sourcemap_ignorelist_plugin_1.createSourcemapIgnorelistPlugin)(),
272
+ (0, compiler_plugin_1.createCompilerPlugin)(
273
+ // JS/TS options
274
+ { ...pluginOptions, noopTypeScriptCompilation: true },
275
+ // Component stylesheet options
276
+ styleOptions),
277
+ ],
278
+ inject: [ssrInjectRequireNamespace, ssrInjectManifestNamespace],
279
+ };
280
+ buildOptions.plugins ??= [];
281
+ if (externalPackages) {
282
+ buildOptions.packages = 'external';
198
283
  }
199
- if (polyfillsFromConfig.has('@angular/localize') ||
200
- polyfillsFromConfig.has('@angular/localize/init')) {
201
- serverPolyfills.push('@angular/localize/init');
284
+ else {
285
+ buildOptions.plugins.push((0, rxjs_esm_resolution_plugin_1.createRxjsEsmResolutionPlugin)());
202
286
  }
203
- serverPolyfills.push('@angular/platform-server/init');
204
- const namespace = 'angular:polyfills-server';
205
- const polyfillBundleOptions = getEsBuildCommonPolyfillsOptions({
206
- ...options,
207
- polyfills: serverPolyfills,
208
- }, namespace, false, sourceFileCache);
209
- if (!polyfillBundleOptions) {
210
- return;
287
+ // Mark manifest file as external. As this will be generated later on.
288
+ (buildOptions.external ??= []).push('*/main.server.mjs', ...utils_1.SERVER_GENERATED_EXTERNALS);
289
+ buildOptions.plugins.push({
290
+ name: 'angular-ssr-metadata',
291
+ setup(build) {
292
+ build.onEnd((result) => {
293
+ if (result.metafile) {
294
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
295
+ result.metafile['ng-ssr-entry-bundle'] = true;
296
+ }
297
+ });
298
+ },
299
+ }, (0, virtual_module_plugin_1.createVirtualModulePlugin)({
300
+ namespace: ssrInjectRequireNamespace,
301
+ cache: sourceFileCache?.loadResultCache,
302
+ loadContent: () => {
303
+ const contents = [
304
+ // Note: Needed as esbuild does not provide require shims / proxy from ESModules.
305
+ // See: https://github.com/evanw/esbuild/issues/1921.
306
+ `import { createRequire } from 'node:module';`,
307
+ `globalThis['require'] ??= createRequire(import.meta.url);`,
308
+ ];
309
+ return {
310
+ contents: contents.join('\n'),
311
+ loader: 'js',
312
+ resolveDir: workspaceRoot,
313
+ };
314
+ },
315
+ }), (0, virtual_module_plugin_1.createVirtualModulePlugin)({
316
+ namespace: ssrInjectManifestNamespace,
317
+ cache: sourceFileCache?.loadResultCache,
318
+ loadContent: () => {
319
+ const contents = [
320
+ // Configure `@angular/ssr` app engine manifest.
321
+ `import manifest from './${manifest_1.SERVER_APP_ENGINE_MANIFEST_FILENAME}';`,
322
+ `import { ɵsetAngularAppEngineManifest } from '@angular/ssr';`,
323
+ `ɵsetAngularAppEngineManifest(manifest);`,
324
+ ];
325
+ return {
326
+ contents: contents.join('\n'),
327
+ loader: 'js',
328
+ resolveDir: workspaceRoot,
329
+ };
330
+ },
331
+ }), (0, virtual_module_plugin_1.createVirtualModulePlugin)({
332
+ namespace: ssrEntryNamespace,
333
+ cache: sourceFileCache?.loadResultCache,
334
+ loadContent: () => {
335
+ const serverEntryPointJsImport = entryFileToWorkspaceRelative(workspaceRoot, serverEntryPoint);
336
+ const contents = [
337
+ // Re-export all symbols including default export
338
+ `import * as server from '${serverEntryPointJsImport}';`,
339
+ `export * from '${serverEntryPointJsImport}';`,
340
+ // The below is needed to avoid
341
+ // `Import "default" will always be undefined because there is no matching export` warning when no default is present.
342
+ `const defaultExportName = 'default';`,
343
+ `export default server[defaultExportName]`,
344
+ // Add @angular/ssr exports
345
+ `export { AngularAppEngine } from '@angular/ssr';`,
346
+ ];
347
+ return {
348
+ contents: contents.join('\n'),
349
+ loader: 'js',
350
+ resolveDir: workspaceRoot,
351
+ };
352
+ },
353
+ }));
354
+ if (options.plugins) {
355
+ buildOptions.plugins.push(...options.plugins);
211
356
  }
212
- const buildOptions = {
213
- ...polyfillBundleOptions,
357
+ return buildOptions;
358
+ }
359
+ function getEsBuildServerCommonOptions(options) {
360
+ return {
361
+ ...getEsBuildCommonOptions(options),
214
362
  platform: 'node',
215
363
  outExtension: { '.js': '.mjs' },
216
364
  // Note: `es2015` is needed for RxJS v6. If not specified, `module` would
@@ -219,31 +367,18 @@ function createServerPolyfillBundleOptions(options, target, sourceFileCache) {
219
367
  // More details: https://github.com/angular/angular-cli/issues/25405.
220
368
  mainFields: ['es2020', 'es2015', 'module', 'main'],
221
369
  entryNames: '[name]',
222
- banner: {
223
- js: [
224
- // Note: Needed as esbuild does not provide require shims / proxy from ESModules.
225
- // See: https://github.com/evanw/esbuild/issues/1921.
226
- `import { createRequire } from 'node:module';`,
227
- `globalThis['require'] ??= createRequire(import.meta.url);`,
228
- ].join('\n'),
229
- },
230
- target,
231
- entryPoints: {
232
- 'polyfills.server': namespace,
233
- },
234
370
  };
235
- return () => buildOptions;
236
371
  }
237
372
  function getEsBuildCommonOptions(options) {
238
- const { workspaceRoot, outExtension, optimizationOptions, sourcemapOptions, tsconfig, externalDependencies, outputNames, preserveSymlinks, jit, loaderExtensions, jsonLogs, } = options;
373
+ const { workspaceRoot, outExtension, optimizationOptions, sourcemapOptions, tsconfig, externalDependencies, outputNames, preserveSymlinks, jit, loaderExtensions, jsonLogs, i18nOptions, } = options;
239
374
  // Ensure unique hashes for i18n translation changes when using post-process inlining.
240
375
  // This hash value is added as a footer to each file and ensures that the output file names (with hashes)
241
376
  // change when translation files have changed. If this is not done the post processed files may have
242
377
  // different content but would retain identical production file names which would lead to browser caching problems.
243
378
  let footer;
244
- if (options.i18nOptions.shouldInline) {
379
+ if (i18nOptions.shouldInline) {
245
380
  // Update file hashes to include translation file content
246
- const i18nHash = Object.values(options.i18nOptions.locales).reduce((data, locale) => data + locale.files.map((file) => file.integrity || '').join('|'), '');
381
+ const i18nHash = Object.values(i18nOptions.locales).reduce((data, locale) => data + locale.files.map((file) => file.integrity || '').join('|'), '');
247
382
  footer = { js: `/**i18n:${(0, node_crypto_1.createHash)('sha256').update(i18nHash).digest('hex')}*/` };
248
383
  }
249
384
  return {
@@ -267,7 +402,7 @@ function getEsBuildCommonOptions(options) {
267
402
  splitting: true,
268
403
  chunkNames: options.namedChunks ? '[name]-[hash]' : 'chunk-[hash]',
269
404
  tsconfig,
270
- external: externalDependencies,
405
+ external: externalDependencies ? [...externalDependencies] : undefined,
271
406
  write: false,
272
407
  preserveSymlinks,
273
408
  define: {
@@ -322,12 +457,10 @@ function getEsBuildCommonPolyfillsOptions(options, namespace, tryToResolvePolyfi
322
457
  namespace,
323
458
  cache: sourceFileCache?.loadResultCache,
324
459
  loadContent: async (_, build) => {
325
- let hasLocalizePolyfill = false;
326
460
  let polyfillPaths = polyfills;
327
461
  let warnings;
328
462
  if (tryToResolvePolyfillsAsRelative) {
329
463
  polyfillPaths = await Promise.all(polyfills.map(async (path) => {
330
- hasLocalizePolyfill ||= path.startsWith('@angular/localize');
331
464
  if (path.startsWith('zone.js') || !(0, node_path_1.extname)(path)) {
332
465
  return path;
333
466
  }
@@ -339,29 +472,6 @@ function getEsBuildCommonPolyfillsOptions(options, namespace, tryToResolvePolyfi
339
472
  return result.path ? potentialPathRelative : path;
340
473
  }));
341
474
  }
342
- else {
343
- hasLocalizePolyfill = polyfills.some((p) => p.startsWith('@angular/localize'));
344
- }
345
- // Add localize polyfill if needed.
346
- // TODO: remove in version 19 or later.
347
- if (!i18nOptions.shouldInline && !hasLocalizePolyfill) {
348
- const result = await build.resolve('@angular/localize', {
349
- kind: 'import-statement',
350
- resolveDir: workspaceRoot,
351
- });
352
- if (result.path) {
353
- polyfillPaths.push('@angular/localize/init');
354
- (warnings ??= []).push({
355
- text: 'Polyfill for "@angular/localize/init" was added automatically.',
356
- notes: [
357
- {
358
- text: 'In the future, this functionality will be removed. ' +
359
- 'Please add this polyfill in the "polyfills" section of your "angular.json" instead.',
360
- },
361
- ],
362
- });
363
- }
364
- }
365
475
  // Generate module contents with an import statement per defined polyfill
366
476
  let contents = polyfillPaths
367
477
  .map((file) => `import '${file.replace(/\\/g, '/')}';`)
@@ -385,3 +495,9 @@ function getEsBuildCommonPolyfillsOptions(options, namespace, tryToResolvePolyfi
385
495
  }));
386
496
  return buildOptions;
387
497
  }
498
+ function entryFileToWorkspaceRelative(workspaceRoot, entryFile) {
499
+ return ('./' +
500
+ (0, node_path_1.relative)(workspaceRoot, entryFile)
501
+ .replace(/.[mc]?ts$/, '')
502
+ .replace(/\\/g, '/'));
503
+ }
@@ -28,7 +28,7 @@ function generateBudgetStats(metafile, outputFiles, initialFiles) {
28
28
  continue;
29
29
  }
30
30
  // Exclude server bundles
31
- if (type === bundler_context_1.BuildOutputFileType.Server) {
31
+ if (type === bundler_context_1.BuildOutputFileType.ServerApplication || type === bundler_context_1.BuildOutputFileType.ServerRoot) {
32
32
  continue;
33
33
  }
34
34
  const initialRecord = initialFiles.get(file);
@@ -31,9 +31,10 @@ export interface InitialFileRecord {
31
31
  depth: number;
32
32
  }
33
33
  export declare enum BuildOutputFileType {
34
- Browser = 1,
35
- Media = 2,
36
- Server = 3,
34
+ Browser = 0,
35
+ Media = 1,
36
+ ServerApplication = 2,
37
+ ServerRoot = 3,
37
38
  Root = 4
38
39
  }
39
40
  export interface BuildOutputFile extends OutputFile {
@@ -18,9 +18,10 @@ const load_result_cache_1 = require("./load-result-cache");
18
18
  const utils_1 = require("./utils");
19
19
  var BuildOutputFileType;
20
20
  (function (BuildOutputFileType) {
21
- BuildOutputFileType[BuildOutputFileType["Browser"] = 1] = "Browser";
22
- BuildOutputFileType[BuildOutputFileType["Media"] = 2] = "Media";
23
- BuildOutputFileType[BuildOutputFileType["Server"] = 3] = "Server";
21
+ BuildOutputFileType[BuildOutputFileType["Browser"] = 0] = "Browser";
22
+ BuildOutputFileType[BuildOutputFileType["Media"] = 1] = "Media";
23
+ BuildOutputFileType[BuildOutputFileType["ServerApplication"] = 2] = "ServerApplication";
24
+ BuildOutputFileType[BuildOutputFileType["ServerRoot"] = 3] = "ServerRoot";
24
25
  BuildOutputFileType[BuildOutputFileType["Root"] = 4] = "Root";
25
26
  })(BuildOutputFileType || (exports.BuildOutputFileType = BuildOutputFileType = {}));
26
27
  /**
@@ -138,6 +139,7 @@ class BundlerContext {
138
139
  }
139
140
  return result;
140
141
  }
142
+ // eslint-disable-next-line max-lines-per-function
141
143
  async #performBundle() {
142
144
  // Create esbuild options if not present
143
145
  if (this.#esbuildOptions === undefined) {
@@ -165,12 +167,6 @@ class BundlerContext {
165
167
  // For non-incremental builds, perform a single build
166
168
  result = await (0, esbuild_1.build)(this.#esbuildOptions);
167
169
  }
168
- if (this.#platformIsServer) {
169
- for (const entry of Object.values(result.metafile.outputs)) {
170
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
171
- entry['ng-platform-server'] = true;
172
- }
173
- }
174
170
  }
175
171
  catch (failure) {
176
172
  // Build failures will throw an exception which contains errors/warnings
@@ -280,6 +276,7 @@ class BundlerContext {
280
276
  for (const { imports } of Object.values(result.metafile.outputs)) {
281
277
  for (const importData of imports) {
282
278
  if (!importData.external ||
279
+ utils_1.SERVER_GENERATED_EXTERNALS.has(importData.path) ||
283
280
  (importData.kind !== 'import-statement' &&
284
281
  importData.kind !== 'dynamic-import' &&
285
282
  importData.kind !== 'require-call')) {
@@ -295,13 +292,24 @@ class BundlerContext {
295
292
  if (!/\.([cm]?js|css|wasm)(\.map)?$/i.test(file.path)) {
296
293
  fileType = BuildOutputFileType.Media;
297
294
  }
295
+ else if (this.#platformIsServer) {
296
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
297
+ fileType = result.metafile['ng-ssr-entry-bundle']
298
+ ? BuildOutputFileType.ServerRoot
299
+ : BuildOutputFileType.ServerApplication;
300
+ }
298
301
  else {
299
- fileType = this.#platformIsServer
300
- ? BuildOutputFileType.Server
301
- : BuildOutputFileType.Browser;
302
+ fileType = BuildOutputFileType.Browser;
302
303
  }
303
304
  return (0, utils_1.convertOutputFile)(file, fileType);
304
305
  });
306
+ let externalConfiguration = this.#esbuildOptions.external;
307
+ if (this.#platformIsServer && externalConfiguration) {
308
+ externalConfiguration = externalConfiguration.filter((dep) => !utils_1.SERVER_GENERATED_EXTERNALS.has(dep));
309
+ if (!externalConfiguration.length) {
310
+ externalConfiguration = undefined;
311
+ }
312
+ }
305
313
  // Return the successful build results
306
314
  return {
307
315
  ...result,
@@ -310,7 +318,7 @@ class BundlerContext {
310
318
  externalImports: {
311
319
  [this.#platformIsServer ? 'server' : 'browser']: externalImports,
312
320
  },
313
- externalConfiguration: this.#esbuildOptions.external,
321
+ externalConfiguration,
314
322
  errors: undefined,
315
323
  };
316
324
  }
@@ -24,6 +24,9 @@ export interface ExternalResultMetadata {
24
24
  implicitServer: string[];
25
25
  explicit: string[];
26
26
  }
27
+ export type PrerenderedRoutesRecord = Record<string, {
28
+ headers?: Record<string, string>;
29
+ }>;
27
30
  /**
28
31
  * Represents the result of a single builder execute call.
29
32
  */
@@ -33,7 +36,7 @@ export declare class ExecutionResult {
33
36
  outputFiles: BuildOutputFile[];
34
37
  assetFiles: BuildOutputAsset[];
35
38
  errors: (Message | PartialMessage)[];
36
- prerenderedRoutes: string[];
39
+ prerenderedRoutes: PrerenderedRoutesRecord;
37
40
  warnings: (Message | PartialMessage)[];
38
41
  logs: string[];
39
42
  externalMetadata?: ExternalResultMetadata;
@@ -46,7 +49,7 @@ export declare class ExecutionResult {
46
49
  addLog(value: string): void;
47
50
  addError(error: PartialMessage | string): void;
48
51
  addErrors(errors: (PartialMessage | string)[]): void;
49
- addPrerenderedRoutes(routes: string[]): void;
52
+ addPrerenderedRoutes(routes: PrerenderedRoutesRecord): void;
50
53
  addWarning(error: PartialMessage | string): void;
51
54
  addWarnings(errors: (PartialMessage | string)[]): void;
52
55
  /**
@@ -19,7 +19,7 @@ class ExecutionResult {
19
19
  outputFiles = [];
20
20
  assetFiles = [];
21
21
  errors = [];
22
- prerenderedRoutes = [];
22
+ prerenderedRoutes = {};
23
23
  warnings = [];
24
24
  logs = [];
25
25
  externalMetadata;
@@ -53,9 +53,13 @@ class ExecutionResult {
53
53
  }
54
54
  }
55
55
  addPrerenderedRoutes(routes) {
56
- this.prerenderedRoutes.push(...routes);
56
+ Object.assign(this.prerenderedRoutes, routes);
57
57
  // Sort the prerendered routes.
58
- this.prerenderedRoutes.sort((a, b) => a.localeCompare(b));
58
+ const sortedObj = {};
59
+ for (const key of Object.keys(this.prerenderedRoutes).sort()) {
60
+ sortedObj[key] = this.prerenderedRoutes[key];
61
+ }
62
+ this.prerenderedRoutes = sortedObj;
59
63
  }
60
64
  addWarning(error) {
61
65
  if (typeof error === 'string') {
@@ -84,5 +84,10 @@ export declare class MemoryCache<V> extends Cache<V, Map<string, V>> {
84
84
  * Provides all the values currently present in the cache instance.
85
85
  * @returns An iterable of all values in the cache.
86
86
  */
87
- values(): IterableIterator<V>;
87
+ values(): MapIterator<V>;
88
+ /**
89
+ * Provides all the keys/values currently present in the cache instance.
90
+ * @returns An iterable of all key/value pairs in the cache.
91
+ */
92
+ entries(): MapIterator<[string, V]>;
88
93
  }
@@ -88,5 +88,12 @@ class MemoryCache extends Cache {
88
88
  values() {
89
89
  return this.store.values();
90
90
  }
91
+ /**
92
+ * Provides all the keys/values currently present in the cache instance.
93
+ * @returns An iterable of all key/value pairs in the cache.
94
+ */
95
+ entries() {
96
+ return this.store.entries();
97
+ }
91
98
  }
92
99
  exports.MemoryCache = MemoryCache;
@@ -9,7 +9,7 @@
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.createCompilerPluginOptions = createCompilerPluginOptions;
11
11
  function createCompilerPluginOptions(options, target, sourceFileCache) {
12
- const { workspaceRoot, optimizationOptions, sourcemapOptions, tsconfig, outputNames, fileReplacements, externalDependencies, preserveSymlinks, stylePreprocessorOptions, advancedOptimizations, inlineStyleLanguage, jit, cacheOptions, tailwindConfiguration, postcssConfiguration, publicPath, } = options;
12
+ const { workspaceRoot, optimizationOptions, sourcemapOptions, tsconfig, outputNames, fileReplacements, externalDependencies, preserveSymlinks, stylePreprocessorOptions, advancedOptimizations, inlineStyleLanguage, jit, cacheOptions, tailwindConfiguration, postcssConfiguration, publicPath, externalRuntimeStyles, instrumentForCoverage, } = options;
13
13
  return {
14
14
  // JS/TS options
15
15
  pluginOptions: {
@@ -22,6 +22,8 @@ function createCompilerPluginOptions(options, target, sourceFileCache) {
22
22
  sourceFileCache,
23
23
  loadResultCache: sourceFileCache?.loadResultCache,
24
24
  incremental: !!options.watch,
25
+ externalRuntimeStyles,
26
+ instrumentForCoverage,
25
27
  },
26
28
  // Component stylesheet options
27
29
  styleOptions: {
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.I18nInliner = void 0;
14
14
  const node_assert_1 = __importDefault(require("node:assert"));
15
- const piscina_1 = __importDefault(require("piscina"));
15
+ const worker_pool_1 = require("../../utils/worker-pool");
16
16
  const bundler_context_1 = require("./bundler-context");
17
17
  const utils_1 = require("./utils");
18
18
  /**
@@ -36,7 +36,8 @@ class I18nInliner {
36
36
  const files = new Map();
37
37
  const pendingMaps = [];
38
38
  for (const file of options.outputFiles) {
39
- if (file.type === bundler_context_1.BuildOutputFileType.Root) {
39
+ if (file.type === bundler_context_1.BuildOutputFileType.Root || file.type === bundler_context_1.BuildOutputFileType.ServerRoot) {
40
+ // Skip also the server entry-point.
40
41
  // Skip stats and similar files.
41
42
  continue;
42
43
  }
@@ -74,7 +75,7 @@ class I18nInliner {
74
75
  }
75
76
  }
76
77
  this.#localizeFiles = files;
77
- this.#workerPool = new piscina_1.default({
78
+ this.#workerPool = new worker_pool_1.WorkerPool({
78
79
  filename: require.resolve('./i18n-inliner-worker'),
79
80
  maxThreads,
80
81
  // Extract options to ensure only the named options are serialized and sent to the worker
@@ -83,7 +84,6 @@ class I18nInliner {
83
84
  shouldOptimize: options.shouldOptimize,
84
85
  files,
85
86
  },
86
- recordTiming: false,
87
87
  });
88
88
  }
89
89
  /**
@@ -14,6 +14,7 @@ interface JavaScriptTransformRequest {
14
14
  skipLinker?: boolean;
15
15
  sideEffects?: boolean;
16
16
  jit: boolean;
17
+ instrumentForCoverage?: boolean;
17
18
  }
18
19
  export default function transformJavaScript(request: JavaScriptTransformRequest): Promise<unknown>;
19
20
  export {};