@angular/build 19.1.0-next.0 → 19.1.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/package.json +9 -9
  2. package/src/builders/application/execute-build.js +2 -2
  3. package/src/builders/application/execute-post-bundle.d.ts +3 -1
  4. package/src/builders/application/execute-post-bundle.js +6 -4
  5. package/src/builders/application/i18n.d.ts +3 -1
  6. package/src/builders/application/i18n.js +15 -13
  7. package/src/builders/application/options.js +7 -5
  8. package/src/builders/dev-server/vite-server.d.ts +2 -2
  9. package/src/builders/dev-server/vite-server.js +7 -40
  10. package/src/builders/extract-i18n/options.js +1 -1
  11. package/src/tools/angular/angular-host.d.ts +1 -1
  12. package/src/tools/angular/angular-host.js +4 -4
  13. package/src/tools/angular/compilation/aot-compilation.d.ts +2 -0
  14. package/src/tools/angular/compilation/aot-compilation.js +30 -9
  15. package/src/tools/angular/compilation/factory.d.ts +2 -1
  16. package/src/tools/angular/compilation/factory.js +5 -4
  17. package/src/tools/angular/compilation/jit-compilation.d.ts +2 -0
  18. package/src/tools/angular/compilation/jit-compilation.js +12 -2
  19. package/src/tools/angular/compilation/parallel-compilation.d.ts +3 -2
  20. package/src/tools/angular/compilation/parallel-compilation.js +4 -1
  21. package/src/tools/angular/compilation/parallel-worker.d.ts +1 -0
  22. package/src/tools/angular/compilation/parallel-worker.js +3 -1
  23. package/src/tools/angular/transformers/lazy-routes-transformer.d.ts +39 -0
  24. package/src/tools/angular/transformers/lazy-routes-transformer.js +163 -0
  25. package/src/tools/esbuild/angular/compiler-plugin.d.ts +1 -0
  26. package/src/tools/esbuild/angular/compiler-plugin.js +1 -1
  27. package/src/tools/esbuild/application-code-bundle.js +24 -20
  28. package/src/tools/esbuild/compiler-plugin-options.js +1 -0
  29. package/src/tools/vite/plugins/angular-memory-plugin.d.ts +1 -0
  30. package/src/tools/vite/plugins/angular-memory-plugin.js +14 -2
  31. package/src/tools/vite/utils.d.ts +14 -0
  32. package/src/tools/vite/utils.js +37 -0
  33. package/src/utils/i18n-options.d.ts +4 -1
  34. package/src/utils/i18n-options.js +50 -7
  35. package/src/utils/index-file/auto-csp.js +5 -5
  36. package/src/utils/normalize-cache.js +1 -1
  37. package/src/utils/server-rendering/esm-in-memory-loader/loader-hooks.js +9 -1
  38. package/src/utils/server-rendering/manifest.d.ts +5 -1
  39. package/src/utils/server-rendering/manifest.js +60 -11
  40. package/src/utils/server-rendering/prerender.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/build",
3
- "version": "19.1.0-next.0",
3
+ "version": "19.1.0-next.1",
4
4
  "description": "Official build system for Angular",
5
5
  "keywords": [
6
6
  "Angular CLI",
@@ -23,29 +23,29 @@
23
23
  "builders": "builders.json",
24
24
  "dependencies": {
25
25
  "@ampproject/remapping": "2.3.0",
26
- "@angular-devkit/architect": "0.1901.0-next.0",
26
+ "@angular-devkit/architect": "0.1901.0-next.1",
27
27
  "@babel/core": "7.26.0",
28
28
  "@babel/helper-annotate-as-pure": "7.25.9",
29
29
  "@babel/helper-split-export-declaration": "7.24.7",
30
30
  "@babel/plugin-syntax-import-attributes": "7.26.0",
31
- "@inquirer/confirm": "5.0.2",
31
+ "@inquirer/confirm": "5.1.0",
32
32
  "@vitejs/plugin-basic-ssl": "1.2.0",
33
- "beasties": "0.1.0",
33
+ "beasties": "0.2.0",
34
34
  "browserslist": "^4.23.0",
35
35
  "esbuild": "0.24.0",
36
36
  "fast-glob": "3.3.2",
37
- "https-proxy-agent": "7.0.5",
37
+ "https-proxy-agent": "7.0.6",
38
38
  "istanbul-lib-instrument": "6.0.3",
39
39
  "listr2": "8.2.5",
40
- "magic-string": "0.30.14",
40
+ "magic-string": "0.30.15",
41
41
  "mrmime": "2.0.0",
42
42
  "parse5-html-rewriting-stream": "7.0.0",
43
43
  "picomatch": "4.0.2",
44
44
  "piscina": "4.8.0",
45
- "rollup": "4.28.0",
45
+ "rollup": "4.28.1",
46
46
  "sass": "1.82.0",
47
47
  "semver": "7.6.3",
48
- "vite": "6.0.2",
48
+ "vite": "6.0.3",
49
49
  "watchpack": "2.4.2"
50
50
  },
51
51
  "optionalDependencies": {
@@ -57,7 +57,7 @@
57
57
  "@angular/localize": "^19.0.0 || ^19.1.0-next.0",
58
58
  "@angular/platform-server": "^19.0.0 || ^19.1.0-next.0",
59
59
  "@angular/service-worker": "^19.0.0 || ^19.1.0-next.0",
60
- "@angular/ssr": "^19.1.0-next.0",
60
+ "@angular/ssr": "^19.1.0-next.1",
61
61
  "less": "^4.2.0",
62
62
  "postcss": "^8.4.0",
63
63
  "tailwindcss": "^2.0.0 || ^3.0.0",
@@ -161,13 +161,13 @@ async function executeBuild(options, context, rebuildState) {
161
161
  }
162
162
  // Perform i18n translation inlining if enabled
163
163
  if (i18nOptions.shouldInline) {
164
- const result = await (0, i18n_1.inlineI18n)(options, executionResult, initialFiles);
164
+ const result = await (0, i18n_1.inlineI18n)(metafile, options, executionResult, initialFiles);
165
165
  executionResult.addErrors(result.errors);
166
166
  executionResult.addWarnings(result.warnings);
167
167
  executionResult.addPrerenderedRoutes(result.prerenderedRoutes);
168
168
  }
169
169
  else {
170
- const result = await (0, execute_post_bundle_1.executePostBundleSteps)(options, executionResult.outputFiles, executionResult.assetFiles, initialFiles,
170
+ const result = await (0, execute_post_bundle_1.executePostBundleSteps)(metafile, options, executionResult.outputFiles, executionResult.assetFiles, initialFiles,
171
171
  // Set lang attribute to the defined source locale if present
172
172
  i18nOptions.hasDefinedSourceLocale ? i18nOptions.sourceLocale : undefined);
173
173
  executionResult.addErrors(result.errors);
@@ -5,18 +5,20 @@
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://angular.dev/license
7
7
  */
8
+ import type { Metafile } from 'esbuild';
8
9
  import { BuildOutputFile, InitialFileRecord } from '../../tools/esbuild/bundler-context';
9
10
  import { BuildOutputAsset, PrerenderedRoutesRecord } from '../../tools/esbuild/bundler-execution-result';
10
11
  import { NormalizedApplicationBuildOptions } from './options';
11
12
  /**
12
13
  * Run additional builds steps including SSG, AppShell, Index HTML file and Service worker generation.
14
+ * @param metafile An esbuild metafile object.
13
15
  * @param options The normalized application builder options used to create the build.
14
16
  * @param outputFiles The output files of an executed build.
15
17
  * @param assetFiles The assets of an executed build.
16
18
  * @param initialFiles A map containing initial file information for the executed build.
17
19
  * @param locale A language locale to insert in the index.html.
18
20
  */
19
- export declare function executePostBundleSteps(options: NormalizedApplicationBuildOptions, outputFiles: BuildOutputFile[], assetFiles: BuildOutputAsset[], initialFiles: Map<string, InitialFileRecord>, locale: string | undefined): Promise<{
21
+ export declare function executePostBundleSteps(metafile: Metafile, options: NormalizedApplicationBuildOptions, outputFiles: BuildOutputFile[], assetFiles: BuildOutputAsset[], initialFiles: Map<string, InitialFileRecord>, locale: string | undefined): Promise<{
20
22
  errors: string[];
21
23
  warnings: string[];
22
24
  additionalOutputFiles: BuildOutputFile[];
@@ -24,6 +24,7 @@ const options_1 = require("./options");
24
24
  const schema_1 = require("./schema");
25
25
  /**
26
26
  * Run additional builds steps including SSG, AppShell, Index HTML file and Service worker generation.
27
+ * @param metafile An esbuild metafile object.
27
28
  * @param options The normalized application builder options used to create the build.
28
29
  * @param outputFiles The output files of an executed build.
29
30
  * @param assetFiles The assets of an executed build.
@@ -31,13 +32,13 @@ const schema_1 = require("./schema");
31
32
  * @param locale A language locale to insert in the index.html.
32
33
  */
33
34
  // eslint-disable-next-line max-lines-per-function
34
- async function executePostBundleSteps(options, outputFiles, assetFiles, initialFiles, locale) {
35
+ async function executePostBundleSteps(metafile, options, outputFiles, assetFiles, initialFiles, locale) {
35
36
  const additionalAssets = [];
36
37
  const additionalOutputFiles = [];
37
38
  const allErrors = [];
38
39
  const allWarnings = [];
39
40
  const prerenderedRoutes = {};
40
- const { baseHref = '/', serviceWorker, i18nOptions, indexHtmlOptions, optimizationOptions, sourcemapOptions, outputMode, serverEntryPoint, prerenderOptions, appShellOptions, workspaceRoot, partialSSRBuild, } = options;
41
+ const { baseHref = '/', serviceWorker, i18nOptions, indexHtmlOptions, optimizationOptions, sourcemapOptions, outputMode, serverEntryPoint, prerenderOptions, appShellOptions, publicPath, workspaceRoot, partialSSRBuild, } = options;
41
42
  // Index HTML content without CSS inlining to be used for server rendering (AppShell, SSG and SSR).
42
43
  // NOTE: Critical CSS inlining is deliberately omitted here, as it will be handled during server rendering.
43
44
  // Additionally, when using prerendering or AppShell, the index HTML file may be regenerated.
@@ -55,8 +56,9 @@ async function executePostBundleSteps(options, outputFiles, assetFiles, initialF
55
56
  }
56
57
  }
57
58
  // Create server manifest
59
+ const initialFilesPaths = new Set(initialFiles.keys());
58
60
  if (serverEntryPoint) {
59
- const { manifestContent, serverAssetsChunks } = (0, manifest_1.generateAngularServerAppManifest)(additionalHtmlOutputFiles, outputFiles, optimizationOptions.styles.inlineCritical ?? false, undefined, locale, baseHref);
61
+ const { manifestContent, serverAssetsChunks } = (0, manifest_1.generateAngularServerAppManifest)(additionalHtmlOutputFiles, outputFiles, optimizationOptions.styles.inlineCritical ?? false, undefined, locale, baseHref, initialFilesPaths, metafile, publicPath);
60
62
  additionalOutputFiles.push(...serverAssetsChunks, (0, utils_1.createOutputFile)(manifest_1.SERVER_APP_MANIFEST_FILENAME, manifestContent, bundler_context_1.BuildOutputFileType.ServerApplication));
61
63
  }
62
64
  // Pre-render (SSG) and App-shell
@@ -95,7 +97,7 @@ async function executePostBundleSteps(options, outputFiles, assetFiles, initialF
95
97
  // Regenerate the manifest to append route tree. This is only needed if SSR is enabled.
96
98
  const manifest = additionalOutputFiles.find((f) => f.path === manifest_1.SERVER_APP_MANIFEST_FILENAME);
97
99
  (0, node_assert_1.default)(manifest, `${manifest_1.SERVER_APP_MANIFEST_FILENAME} was not found in output files.`);
98
- const { manifestContent, serverAssetsChunks } = (0, manifest_1.generateAngularServerAppManifest)(additionalHtmlOutputFiles, outputFiles, optimizationOptions.styles.inlineCritical ?? false, serializableRouteTreeNodeForManifest, locale, baseHref);
100
+ const { manifestContent, serverAssetsChunks } = (0, manifest_1.generateAngularServerAppManifest)(additionalHtmlOutputFiles, outputFiles, optimizationOptions.styles.inlineCritical ?? false, serializableRouteTreeNodeForManifest, locale, baseHref, initialFilesPaths, metafile, publicPath);
99
101
  for (const chunk of serverAssetsChunks) {
100
102
  const idx = additionalOutputFiles.findIndex(({ path }) => path === chunk.path);
101
103
  if (idx === -1) {
@@ -6,17 +6,19 @@
6
6
  * found in the LICENSE file at https://angular.dev/license
7
7
  */
8
8
  import { BuilderContext } from '@angular-devkit/architect';
9
+ import type { Metafile } from 'esbuild';
9
10
  import { InitialFileRecord } from '../../tools/esbuild/bundler-context';
10
11
  import { ExecutionResult, PrerenderedRoutesRecord } from '../../tools/esbuild/bundler-execution-result';
11
12
  import { NormalizedApplicationBuildOptions } from './options';
12
13
  /**
13
14
  * Inlines all active locales as specified by the application build options into all
14
15
  * application JavaScript files created during the build.
16
+ * @param metafile An esbuild metafile object.
15
17
  * @param options The normalized application builder options used to create the build.
16
18
  * @param executionResult The result of an executed build.
17
19
  * @param initialFiles A map containing initial file information for the executed build.
18
20
  */
19
- export declare function inlineI18n(options: NormalizedApplicationBuildOptions, executionResult: ExecutionResult, initialFiles: Map<string, InitialFileRecord>): Promise<{
21
+ export declare function inlineI18n(metafile: Metafile, options: NormalizedApplicationBuildOptions, executionResult: ExecutionResult, initialFiles: Map<string, InitialFileRecord>): Promise<{
20
22
  errors: string[];
21
23
  warnings: string[];
22
24
  prerenderedRoutes: PrerenderedRoutesRecord;
@@ -20,16 +20,18 @@ const options_1 = require("./options");
20
20
  /**
21
21
  * Inlines all active locales as specified by the application build options into all
22
22
  * application JavaScript files created during the build.
23
+ * @param metafile An esbuild metafile object.
23
24
  * @param options The normalized application builder options used to create the build.
24
25
  * @param executionResult The result of an executed build.
25
26
  * @param initialFiles A map containing initial file information for the executed build.
26
27
  */
27
- async function inlineI18n(options, executionResult, initialFiles) {
28
+ async function inlineI18n(metafile, options, executionResult, initialFiles) {
29
+ const { i18nOptions, optimizationOptions, baseHref } = options;
28
30
  // Create the multi-threaded inliner with common options and the files generated from the build.
29
31
  const inliner = new i18n_inliner_1.I18nInliner({
30
- missingTranslation: options.i18nOptions.missingTranslationBehavior ?? 'warning',
32
+ missingTranslation: i18nOptions.missingTranslationBehavior ?? 'warning',
31
33
  outputFiles: executionResult.outputFiles,
32
- shouldOptimize: options.optimizationOptions.scripts,
34
+ shouldOptimize: optimizationOptions.scripts,
33
35
  }, environment_options_1.maxWorkers);
34
36
  const inlineResult = {
35
37
  errors: [],
@@ -40,29 +42,29 @@ async function inlineI18n(options, executionResult, initialFiles) {
40
42
  const updatedOutputFiles = [];
41
43
  const updatedAssetFiles = [];
42
44
  try {
43
- for (const locale of options.i18nOptions.inlineLocales) {
45
+ for (const locale of i18nOptions.inlineLocales) {
44
46
  // A locale specific set of files is returned from the inliner.
45
- const localeInlineResult = await inliner.inlineForLocale(locale, options.i18nOptions.locales[locale].translation);
47
+ const localeInlineResult = await inliner.inlineForLocale(locale, i18nOptions.locales[locale].translation);
46
48
  const localeOutputFiles = localeInlineResult.outputFiles;
47
49
  inlineResult.errors.push(...localeInlineResult.errors);
48
50
  inlineResult.warnings.push(...localeInlineResult.warnings);
49
- const baseHref = (0, options_1.getLocaleBaseHref)(options.baseHref, options.i18nOptions, locale) ?? options.baseHref;
50
- const { errors, warnings, additionalAssets, additionalOutputFiles, prerenderedRoutes: generatedRoutes, } = await (0, execute_post_bundle_1.executePostBundleSteps)({
51
+ const { errors, warnings, additionalAssets, additionalOutputFiles, prerenderedRoutes: generatedRoutes, } = await (0, execute_post_bundle_1.executePostBundleSteps)(metafile, {
51
52
  ...options,
52
- baseHref,
53
+ baseHref: (0, options_1.getLocaleBaseHref)(baseHref, i18nOptions, locale) ?? baseHref,
53
54
  }, localeOutputFiles, executionResult.assetFiles, initialFiles, locale);
54
55
  localeOutputFiles.push(...additionalOutputFiles);
55
56
  inlineResult.errors.push(...errors);
56
57
  inlineResult.warnings.push(...warnings);
57
- // Update directory with locale base
58
- if (options.i18nOptions.flatOutput !== true) {
58
+ // Update directory with locale base or subPath
59
+ const subPath = i18nOptions.locales[locale].subPath;
60
+ if (i18nOptions.flatOutput !== true) {
59
61
  localeOutputFiles.forEach((file) => {
60
- file.path = (0, node_path_1.join)(locale, file.path);
62
+ file.path = (0, node_path_1.join)(subPath, file.path);
61
63
  });
62
64
  for (const assetFile of [...executionResult.assetFiles, ...additionalAssets]) {
63
65
  updatedAssetFiles.push({
64
66
  source: assetFile.source,
65
- destination: (0, node_path_1.join)(locale, assetFile.destination),
67
+ destination: (0, node_path_1.join)(subPath, assetFile.destination),
66
68
  });
67
69
  }
68
70
  }
@@ -84,7 +86,7 @@ async function inlineI18n(options, executionResult, initialFiles) {
84
86
  ...updatedOutputFiles,
85
87
  ];
86
88
  // Assets are only changed if not using the flat output option
87
- if (options.i18nOptions.flatOutput !== true) {
89
+ if (!i18nOptions.flatOutput) {
88
90
  executionResult.assetFiles = updatedAssetFiles;
89
91
  }
90
92
  return inlineResult;
@@ -63,7 +63,7 @@ async function normalizeOptions(context, projectName, options, extensions) {
63
63
  // Gather persistent caching option and provide a project specific cache location
64
64
  const cacheOptions = (0, normalize_cache_1.normalizeCacheOptions)(projectMetadata, workspaceRoot);
65
65
  cacheOptions.path = node_path_1.default.join(cacheOptions.path, projectName);
66
- const i18nOptions = (0, i18n_options_1.createI18nOptions)(projectMetadata, options.localize);
66
+ const i18nOptions = (0, i18n_options_1.createI18nOptions)(projectMetadata, options.localize, context.logger);
67
67
  i18nOptions.duplicateTranslationBehavior = options.i18nDuplicateTranslation;
68
68
  i18nOptions.missingTranslationBehavior = options.i18nMissingTranslation;
69
69
  if (options.forceI18nFlatOutput) {
@@ -427,12 +427,14 @@ function normalizeGlobalEntries(rawEntries, defaultName) {
427
427
  }
428
428
  return [...bundles.values()];
429
429
  }
430
- function getLocaleBaseHref(baseHref, i18n, locale) {
430
+ function getLocaleBaseHref(baseHref = '', i18n, locale) {
431
431
  if (i18n.flatOutput) {
432
432
  return undefined;
433
433
  }
434
- if (i18n.locales[locale] && i18n.locales[locale].baseHref !== '') {
435
- return (0, url_1.urlJoin)(baseHref || '', i18n.locales[locale].baseHref ?? `/${locale}/`);
434
+ const localeData = i18n.locales[locale];
435
+ if (!localeData) {
436
+ return undefined;
436
437
  }
437
- return undefined;
438
+ const baseHrefSuffix = localeData.baseHref ?? localeData.subPath + '/';
439
+ return baseHrefSuffix !== '' ? (0, url_1.urlJoin)(baseHref, baseHrefSuffix) : undefined;
438
440
  }
@@ -7,9 +7,10 @@
7
7
  */
8
8
  import type { BuilderContext } from '@angular-devkit/architect';
9
9
  import type { Plugin } from 'esbuild';
10
- import type { Connect, DepOptimizationConfig, InlineConfig } from 'vite';
10
+ import type { Connect, InlineConfig } from 'vite';
11
11
  import type { ComponentStyleRecord } from '../../tools/vite/middlewares';
12
12
  import { ServerSsrMode } from '../../tools/vite/plugins';
13
+ import { EsbuildLoaderOption } from '../../tools/vite/utils';
13
14
  import { Result } from '../application/results';
14
15
  import { type ApplicationBuilderInternalOptions, BuildOutputFileType, type ExternalResultMetadata, JavaScriptTransformer } from './internal';
15
16
  import type { NormalizedDevServerOptions } from './options';
@@ -34,5 +35,4 @@ export declare function serveWithVite(serverOptions: NormalizedDevServerOptions,
34
35
  buildPlugins?: Plugin[];
35
36
  }): AsyncIterableIterator<DevServerBuilderOutput>;
36
37
  export declare function setupServer(serverOptions: NormalizedDevServerOptions, outputFiles: Map<string, OutputFileRecord>, assets: Map<string, string>, preserveSymlinks: boolean | undefined, externalMetadata: DevServerExternalResultMetadata, ssrMode: ServerSsrMode, prebundleTransformer: JavaScriptTransformer, target: string[], zoneless: boolean, componentStyles: Map<string, ComponentStyleRecord>, templateUpdates: Map<string, string>, prebundleLoaderExtensions: EsbuildLoaderOption | undefined, extensionMiddleware?: Connect.NextHandleFunction[], indexHtmlTransformer?: (content: string) => Promise<string>, thirdPartySourcemaps?: boolean): Promise<InlineConfig>;
37
- type EsbuildLoaderOption = Exclude<DepOptimizationConfig['esbuildOptions'], undefined>['loader'];
38
38
  export {};
@@ -50,7 +50,8 @@ const promises_1 = require("node:fs/promises");
50
50
  const node_module_1 = require("node:module");
51
51
  const node_path_1 = require("node:path");
52
52
  const plugins_1 = require("../../tools/vite/plugins");
53
- const utils_1 = require("../../utils");
53
+ const utils_1 = require("../../tools/vite/utils");
54
+ const utils_2 = require("../../utils");
54
55
  const environment_options_1 = require("../../utils/environment-options");
55
56
  const load_esm_1 = require("../../utils/load-esm");
56
57
  const results_1 = require("../application/results");
@@ -97,7 +98,7 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
97
98
  // When localization is enabled with a single locale, force a flat path to maintain behavior with the existing Webpack-based dev server.
98
99
  browserOptions.forceI18nFlatOutput = true;
99
100
  }
100
- const { vendor: thirdPartySourcemaps, scripts: scriptsSourcemaps } = (0, utils_1.normalizeSourceMaps)(browserOptions.sourceMap ?? false);
101
+ const { vendor: thirdPartySourcemaps, scripts: scriptsSourcemaps } = (0, utils_2.normalizeSourceMaps)(browserOptions.sourceMap ?? false);
101
102
  if (scriptsSourcemaps && browserOptions.server) {
102
103
  // https://nodejs.org/api/process.html#processsetsourcemapsenabledval
103
104
  process.setSourceMapsEnabled(true);
@@ -459,7 +460,7 @@ function analyzeResultFiles(normalizePath, htmlIndexPath, resultFiles, generated
459
460
  }
460
461
  }
461
462
  async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks, externalMetadata, ssrMode, prebundleTransformer, target, zoneless, componentStyles, templateUpdates, prebundleLoaderExtensions, extensionMiddleware, indexHtmlTransformer, thirdPartySourcemaps = false) {
462
- const proxy = await (0, utils_1.loadProxyConfiguration)(serverOptions.workspaceRoot, serverOptions.proxyConfig);
463
+ const proxy = await (0, utils_2.loadProxyConfiguration)(serverOptions.workspaceRoot, serverOptions.proxyConfig);
463
464
  // dynamically import Vite for ESM compatibility
464
465
  const { normalizePath } = await (0, load_esm_1.loadEsmModule)('vite');
465
466
  // Path will not exist on disk and only used to provide separate path for Vite requests
@@ -526,7 +527,7 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
526
527
  noExternal: /.*/,
527
528
  // Exclude any Node.js built in module and provided dependencies (currently build defined externals)
528
529
  external: externalMetadata.explicitServer,
529
- optimizeDeps: getDepOptimizationConfig({
530
+ optimizeDeps: (0, utils_1.getDepOptimizationConfig)({
530
531
  // Only enable with caching since it causes prebundle dependencies to be cached
531
532
  disabled: serverOptions.prebundle === false,
532
533
  // Exclude any explicitly defined dependencies (currently build defined externals and node.js built-ins)
@@ -557,12 +558,13 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
557
558
  await (0, plugins_1.createAngularMemoryPlugin)({
558
559
  virtualProjectRoot,
559
560
  outputFiles,
561
+ templateUpdates,
560
562
  external: externalMetadata.explicitBrowser,
561
563
  skipViteClient: serverOptions.liveReload === false && serverOptions.hmr === false,
562
564
  }),
563
565
  ],
564
566
  // Browser only optimizeDeps. (This does not run for SSR dependencies).
565
- optimizeDeps: getDepOptimizationConfig({
567
+ optimizeDeps: (0, utils_1.getDepOptimizationConfig)({
566
568
  // Only enable with caching since it causes prebundle dependencies to be cached
567
569
  disabled: serverOptions.prebundle === false,
568
570
  // Exclude any explicitly defined dependencies (currently build defined externals)
@@ -595,41 +597,6 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
595
597
  }
596
598
  return configuration;
597
599
  }
598
- function getDepOptimizationConfig({ disabled, exclude, include, target, zoneless, prebundleTransformer, ssr, loader, thirdPartySourcemaps, }) {
599
- const plugins = [
600
- {
601
- name: `angular-vite-optimize-deps${ssr ? '-ssr' : ''}${thirdPartySourcemaps ? '-vendor-sourcemap' : ''}`,
602
- setup(build) {
603
- build.onLoad({ filter: /\.[cm]?js$/ }, async (args) => {
604
- return {
605
- contents: await prebundleTransformer.transformFile(args.path),
606
- loader: 'js',
607
- };
608
- });
609
- },
610
- },
611
- ];
612
- return {
613
- // Exclude any explicitly defined dependencies (currently build defined externals)
614
- exclude,
615
- // NB: to disable the deps optimizer, set optimizeDeps.noDiscovery to true and optimizeDeps.include as undefined.
616
- // Include all implict dependencies from the external packages internal option
617
- include: disabled ? undefined : include,
618
- noDiscovery: disabled,
619
- // Add an esbuild plugin to run the Angular linker on dependencies
620
- esbuildOptions: {
621
- // Set esbuild supported targets.
622
- target,
623
- supported: (0, internal_1.getFeatureSupport)(target, zoneless),
624
- plugins,
625
- loader,
626
- define: {
627
- 'ngServerMode': `${ssr}`,
628
- },
629
- resolveExtensions: ['.mjs', '.js', '.cjs'],
630
- },
631
- };
632
- }
633
600
  /**
634
601
  * Checks if the given value is an absolute URL.
635
602
  *
@@ -33,7 +33,7 @@ async function normalizeOptions(context, projectName, options) {
33
33
  // Target specifier defaults to the current project's build target with no specified configuration
34
34
  const buildTargetSpecifier = options.buildTarget ?? ':';
35
35
  const buildTarget = (0, architect_1.targetFromTargetString)(buildTargetSpecifier, projectName, 'build');
36
- const i18nOptions = (0, i18n_options_1.createI18nOptions)(projectMetadata);
36
+ const i18nOptions = (0, i18n_options_1.createI18nOptions)(projectMetadata, /** inline */ false, context.logger);
37
37
  // Normalize xliff format extensions
38
38
  let format = options.format;
39
39
  switch (format) {
@@ -24,4 +24,4 @@ export interface AngularHostOptions {
24
24
  * @param program The TypeScript Program instance to patch.
25
25
  */
26
26
  export declare function ensureSourceFileVersions(program: ts.Program): void;
27
- export declare function createAngularCompilerHost(typescript: typeof ts, compilerOptions: AngularCompilerOptions, hostOptions: AngularHostOptions): AngularCompilerHost;
27
+ export declare function createAngularCompilerHost(typescript: typeof ts, compilerOptions: AngularCompilerOptions, hostOptions: AngularHostOptions, packageJsonCache: ts.PackageJsonInfoCache | undefined): AngularCompilerHost;
@@ -91,7 +91,7 @@ function augmentHostWithReplacements(typescript, host, replacements, moduleResol
91
91
  };
92
92
  augmentResolveModuleNames(typescript, host, tryReplace, moduleResolutionCache);
93
93
  }
94
- function createAngularCompilerHost(typescript, compilerOptions, hostOptions) {
94
+ function createAngularCompilerHost(typescript, compilerOptions, hostOptions, packageJsonCache) {
95
95
  // Create TypeScript compiler host
96
96
  const host = typescript.createIncrementalCompilerHost(compilerOptions);
97
97
  // Set the parsing mode to the same as TS 5.3+ default for tsc. This provides a parse
@@ -135,11 +135,11 @@ function createAngularCompilerHost(typescript, compilerOptions, hostOptions) {
135
135
  host.getModifiedResourceFiles = function () {
136
136
  return hostOptions.modifiedFiles;
137
137
  };
138
+ // Provide a resolution cache to ensure package.json lookups are cached
139
+ const resolutionCache = typescript.createModuleResolutionCache(host.getCurrentDirectory(), host.getCanonicalFileName.bind(host), compilerOptions, packageJsonCache);
140
+ host.getModuleResolutionCache = () => resolutionCache;
138
141
  // Augment TypeScript Host for file replacements option
139
142
  if (hostOptions.fileReplacements) {
140
- // Provide a resolution cache since overriding resolution prevents automatic creation
141
- const resolutionCache = typescript.createModuleResolutionCache(host.getCurrentDirectory(), host.getCanonicalFileName.bind(host), compilerOptions);
142
- host.getModuleResolutionCache = () => resolutionCache;
143
143
  augmentHostWithReplacements(typescript, host, hostOptions.fileReplacements, resolutionCache);
144
144
  }
145
145
  // Augment TypeScript Host with source file caching if provided
@@ -11,6 +11,8 @@ import { AngularHostOptions } from '../angular-host';
11
11
  import { AngularCompilation, DiagnosticModes, EmitFileResult } from './angular-compilation';
12
12
  export declare class AotCompilation extends AngularCompilation {
13
13
  #private;
14
+ private readonly browserOnlyBuild;
15
+ constructor(browserOnlyBuild: boolean);
14
16
  initialize(tsconfig: string, hostOptions: AngularHostOptions, compilerOptionsTransformer?: (compilerOptions: ng.CompilerOptions) => ng.CompilerOptions): Promise<{
15
17
  affectedFiles: ReadonlySet<ts.SourceFile>;
16
18
  compilerOptions: ng.CompilerOptions;
@@ -17,6 +17,7 @@ const typescript_1 = __importDefault(require("typescript"));
17
17
  const profiling_1 = require("../../esbuild/profiling");
18
18
  const angular_host_1 = require("../angular-host");
19
19
  const jit_bootstrap_transformer_1 = require("../transformers/jit-bootstrap-transformer");
20
+ const lazy_routes_transformer_1 = require("../transformers/lazy-routes-transformer");
20
21
  const web_worker_transformer_1 = require("../transformers/web-worker-transformer");
21
22
  const angular_compilation_1 = require("./angular-compilation");
22
23
  const hmr_candidates_1 = require("./hmr-candidates");
@@ -48,7 +49,12 @@ class AngularCompilationState {
48
49
  }
49
50
  }
50
51
  class AotCompilation extends angular_compilation_1.AngularCompilation {
52
+ browserOnlyBuild;
51
53
  #state;
54
+ constructor(browserOnlyBuild) {
55
+ super();
56
+ this.browserOnlyBuild = browserOnlyBuild;
57
+ }
52
58
  async initialize(tsconfig, hostOptions, compilerOptionsTransformer) {
53
59
  // Dynamically load the Angular compiler CLI package
54
60
  const { NgtscProgram, OptimizeFor } = await angular_compilation_1.AngularCompilation.loadCompilerCli();
@@ -58,22 +64,34 @@ class AotCompilation extends angular_compilation_1.AngularCompilation {
58
64
  if (compilerOptions.externalRuntimeStyles) {
59
65
  hostOptions.externalStylesheets ??= new Map();
60
66
  }
67
+ // Reuse the package.json cache from the previous compilation
68
+ const packageJsonCache = this.#state?.compilerHost
69
+ .getModuleResolutionCache?.()
70
+ ?.getPackageJsonInfoCache();
61
71
  const useHmr = compilerOptions['_enableHmr'] &&
62
72
  hostOptions.modifiedFiles &&
63
73
  hostOptions.modifiedFiles.size <= HMR_MODIFIED_FILE_LIMIT;
64
- // Collect stale source files for HMR analysis of inline component resources
65
74
  let staleSourceFiles;
66
- if (useHmr && hostOptions.modifiedFiles && this.#state) {
75
+ let clearPackageJsonCache = false;
76
+ if (hostOptions.modifiedFiles && this.#state) {
67
77
  for (const modifiedFile of hostOptions.modifiedFiles) {
68
- const sourceFile = this.#state.typeScriptProgram.getSourceFile(modifiedFile);
69
- if (sourceFile) {
70
- staleSourceFiles ??= new Map();
71
- staleSourceFiles.set(modifiedFile, sourceFile);
78
+ // Clear package.json cache if a node modules file was modified
79
+ if (!clearPackageJsonCache && modifiedFile.includes('node_modules')) {
80
+ clearPackageJsonCache = true;
81
+ packageJsonCache?.clear();
82
+ }
83
+ // Collect stale source files for HMR analysis of inline component resources
84
+ if (useHmr) {
85
+ const sourceFile = this.#state.typeScriptProgram.getSourceFile(modifiedFile);
86
+ if (sourceFile) {
87
+ staleSourceFiles ??= new Map();
88
+ staleSourceFiles.set(modifiedFile, sourceFile);
89
+ }
72
90
  }
73
91
  }
74
92
  }
75
93
  // Create Angular compiler host
76
- const host = (0, angular_host_1.createAngularCompilerHost)(typescript_1.default, compilerOptions, hostOptions);
94
+ const host = (0, angular_host_1.createAngularCompilerHost)(typescript_1.default, compilerOptions, hostOptions, packageJsonCache);
77
95
  // Create the Angular specific program that contains the Angular compiler
78
96
  const angularProgram = (0, profiling_1.profileSync)('NG_CREATE_PROGRAM', () => new NgtscProgram(rootNames, compilerOptions, host, this.#state?.angularProgram));
79
97
  const angularCompiler = angularProgram.compiler;
@@ -99,6 +117,7 @@ class AotCompilation extends angular_compilation_1.AngularCompilation {
99
117
  if (relativePath.startsWith('..')) {
100
118
  relativePath = componentFilename;
101
119
  }
120
+ relativePath = relativePath.replaceAll('\\', '/');
102
121
  const updateId = encodeURIComponent(`${host.getCanonicalFileName(relativePath)}@${node.name?.text}`);
103
122
  const updateText = angularCompiler.emitHmrUpdateModule(node);
104
123
  if (updateText === null) {
@@ -210,8 +229,10 @@ class AotCompilation extends angular_compilation_1.AngularCompilation {
210
229
  };
211
230
  const transformers = angularCompiler.prepareEmit().transformers;
212
231
  transformers.before ??= [];
213
- transformers.before.push((0, jit_bootstrap_transformer_1.replaceBootstrap)(() => typeScriptProgram.getProgram().getTypeChecker()));
214
- transformers.before.push(webWorkerTransform);
232
+ transformers.before.push((0, jit_bootstrap_transformer_1.replaceBootstrap)(() => typeScriptProgram.getProgram().getTypeChecker()), webWorkerTransform);
233
+ if (!this.browserOnlyBuild) {
234
+ transformers.before.push((0, lazy_routes_transformer_1.lazyRoutesTransformer)(compilerOptions, compilerHost));
235
+ }
215
236
  // Emit is handled in write file callback when using TypeScript
216
237
  if (useTypeScriptTranspilation) {
217
238
  // TypeScript will loop until there are no more affected files in the program
@@ -11,6 +11,7 @@ import type { AngularCompilation } from './angular-compilation';
11
11
  * compilation either for AOT or JIT mode. By default a parallel compilation is created
12
12
  * that uses a Node.js worker thread.
13
13
  * @param jit True, for Angular JIT compilation; False, for Angular AOT compilation.
14
+ * @param browserOnlyBuild True, for browser only builds; False, for browser and server builds.
14
15
  * @returns An instance of an Angular compilation object.
15
16
  */
16
- export declare function createAngularCompilation(jit: boolean): Promise<AngularCompilation>;
17
+ export declare function createAngularCompilation(jit: boolean, browserOnlyBuild: boolean): Promise<AngularCompilation>;
@@ -47,19 +47,20 @@ const environment_options_1 = require("../../../utils/environment-options");
47
47
  * compilation either for AOT or JIT mode. By default a parallel compilation is created
48
48
  * that uses a Node.js worker thread.
49
49
  * @param jit True, for Angular JIT compilation; False, for Angular AOT compilation.
50
+ * @param browserOnlyBuild True, for browser only builds; False, for browser and server builds.
50
51
  * @returns An instance of an Angular compilation object.
51
52
  */
52
- async function createAngularCompilation(jit) {
53
+ async function createAngularCompilation(jit, browserOnlyBuild) {
53
54
  if (environment_options_1.useParallelTs) {
54
55
  const { ParallelCompilation } = await Promise.resolve().then(() => __importStar(require('./parallel-compilation')));
55
- return new ParallelCompilation(jit);
56
+ return new ParallelCompilation(jit, browserOnlyBuild);
56
57
  }
57
58
  if (jit) {
58
59
  const { JitCompilation } = await Promise.resolve().then(() => __importStar(require('./jit-compilation')));
59
- return new JitCompilation();
60
+ return new JitCompilation(browserOnlyBuild);
60
61
  }
61
62
  else {
62
63
  const { AotCompilation } = await Promise.resolve().then(() => __importStar(require('./aot-compilation')));
63
- return new AotCompilation();
64
+ return new AotCompilation(browserOnlyBuild);
64
65
  }
65
66
  }
@@ -11,6 +11,8 @@ import { AngularHostOptions } from '../angular-host';
11
11
  import { AngularCompilation, DiagnosticModes, EmitFileResult } from './angular-compilation';
12
12
  export declare class JitCompilation extends AngularCompilation {
13
13
  #private;
14
+ private readonly browserOnlyBuild;
15
+ constructor(browserOnlyBuild: boolean);
14
16
  initialize(tsconfig: string, hostOptions: AngularHostOptions, compilerOptionsTransformer?: (compilerOptions: ng.CompilerOptions) => ng.CompilerOptions): Promise<{
15
17
  affectedFiles: ReadonlySet<ts.SourceFile>;
16
18
  compilerOptions: ng.CompilerOptions;
@@ -17,6 +17,7 @@ const load_esm_1 = require("../../../utils/load-esm");
17
17
  const profiling_1 = require("../../esbuild/profiling");
18
18
  const angular_host_1 = require("../angular-host");
19
19
  const jit_resource_transformer_1 = require("../transformers/jit-resource-transformer");
20
+ const lazy_routes_transformer_1 = require("../transformers/lazy-routes-transformer");
20
21
  const web_worker_transformer_1 = require("../transformers/web-worker-transformer");
21
22
  const angular_compilation_1 = require("./angular-compilation");
22
23
  class JitCompilationState {
@@ -34,7 +35,12 @@ class JitCompilationState {
34
35
  }
35
36
  }
36
37
  class JitCompilation extends angular_compilation_1.AngularCompilation {
38
+ browserOnlyBuild;
37
39
  #state;
40
+ constructor(browserOnlyBuild) {
41
+ super();
42
+ this.browserOnlyBuild = browserOnlyBuild;
43
+ }
38
44
  async initialize(tsconfig, hostOptions, compilerOptionsTransformer) {
39
45
  // Dynamically load the Angular compiler CLI package
40
46
  const { constructorParametersDownlevelTransform } = await (0, load_esm_1.loadEsmModule)('@angular/compiler-cli/private/tooling');
@@ -42,7 +48,7 @@ class JitCompilation extends angular_compilation_1.AngularCompilation {
42
48
  const { options: originalCompilerOptions, rootNames, errors: configurationDiagnostics, } = await this.loadConfiguration(tsconfig);
43
49
  const compilerOptions = compilerOptionsTransformer?.(originalCompilerOptions) ?? originalCompilerOptions;
44
50
  // Create Angular compiler host
45
- const host = (0, angular_host_1.createAngularCompilerHost)(typescript_1.default, compilerOptions, hostOptions);
51
+ const host = (0, angular_host_1.createAngularCompilerHost)(typescript_1.default, compilerOptions, hostOptions, undefined);
46
52
  // Create the TypeScript Program
47
53
  const typeScriptProgram = (0, profiling_1.profileSync)('TS_CREATE_PROGRAM', () => typescript_1.default.createEmitAndSemanticDiagnosticsBuilderProgram(rootNames, compilerOptions, host, this.#state?.typeScriptProgram ?? typescript_1.default.readBuilderProgram(compilerOptions, host), configurationDiagnostics));
48
54
  const affectedFiles = (0, profiling_1.profileSync)('TS_FIND_AFFECTED', () => findAffectedFiles(typeScriptProgram));
@@ -71,7 +77,8 @@ class JitCompilation extends angular_compilation_1.AngularCompilation {
71
77
  emitAffectedFiles() {
72
78
  (0, node_assert_1.default)(this.#state, 'Compilation must be initialized prior to emitting files.');
73
79
  const { compilerHost, typeScriptProgram, constructorParametersDownlevelTransform, replaceResourcesTransform, webWorkerTransform, } = this.#state;
74
- const buildInfoFilename = typeScriptProgram.getCompilerOptions().tsBuildInfoFile ?? '.tsbuildinfo';
80
+ const compilerOptions = typeScriptProgram.getCompilerOptions();
81
+ const buildInfoFilename = compilerOptions.tsBuildInfoFile ?? '.tsbuildinfo';
75
82
  const emittedFiles = [];
76
83
  const writeFileCallback = (filename, contents, _a, _b, sourceFiles) => {
77
84
  if (!sourceFiles?.length && filename.endsWith(buildInfoFilename)) {
@@ -89,6 +96,9 @@ class JitCompilation extends angular_compilation_1.AngularCompilation {
89
96
  webWorkerTransform,
90
97
  ],
91
98
  };
99
+ if (!this.browserOnlyBuild) {
100
+ transformers.before.push((0, lazy_routes_transformer_1.lazyRoutesTransformer)(compilerOptions, compilerHost));
101
+ }
92
102
  // TypeScript will loop until there are no more affected files in the program
93
103
  while (typeScriptProgram.emitNextAffectedFile(writeFileCallback, undefined, undefined, transformers)) {
94
104
  /* empty */
@@ -20,8 +20,9 @@ import { AngularCompilation, DiagnosticModes, EmitFileResult } from './angular-c
20
20
  */
21
21
  export declare class ParallelCompilation extends AngularCompilation {
22
22
  #private;
23
- readonly jit: boolean;
24
- constructor(jit: boolean);
23
+ private readonly jit;
24
+ private readonly browserOnlyBuild;
25
+ constructor(jit: boolean, browserOnlyBuild: boolean);
25
26
  initialize(tsconfig: string, hostOptions: AngularHostOptions, compilerOptionsTransformer?: (compilerOptions: CompilerOptions) => CompilerOptions): Promise<{
26
27
  affectedFiles: ReadonlySet<SourceFile>;
27
28
  compilerOptions: CompilerOptions;