@angular/build 19.1.0-next.2 → 19.1.0

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 (58) hide show
  1. package/LICENSE +1 -1
  2. package/builders.json +5 -0
  3. package/index.d.ts +8 -0
  4. package/index.js +24 -0
  5. package/package.json +20 -16
  6. package/private/index.d.ts +8 -0
  7. package/private/index.js +24 -0
  8. package/src/builders/application/build-action.d.ts +1 -0
  9. package/src/builders/application/build-action.js +93 -11
  10. package/src/builders/application/execute-build.js +5 -2
  11. package/src/builders/application/index.d.ts +5 -12
  12. package/src/builders/application/index.js +35 -21
  13. package/src/builders/application/options.d.ts +6 -0
  14. package/src/builders/application/options.js +1 -0
  15. package/src/builders/application/results.d.ts +4 -1
  16. package/src/builders/application/setup-bundling.d.ts +2 -1
  17. package/src/builders/application/setup-bundling.js +2 -2
  18. package/src/builders/dev-server/index.d.ts +4 -2
  19. package/src/builders/dev-server/index.js +2 -1
  20. package/src/builders/dev-server/vite-server.d.ts +5 -1
  21. package/src/builders/dev-server/vite-server.js +101 -77
  22. package/src/builders/extract-i18n/index.d.ts +4 -2
  23. package/src/builders/extract-i18n/index.js +2 -1
  24. package/src/builders/ng-packagr/builder.d.ts +19 -0
  25. package/src/builders/ng-packagr/builder.js +103 -0
  26. package/src/builders/ng-packagr/index.d.ts +14 -0
  27. package/src/builders/ng-packagr/index.js +15 -0
  28. package/src/builders/ng-packagr/schema.d.ts +21 -0
  29. package/src/builders/ng-packagr/schema.js +4 -0
  30. package/src/builders/ng-packagr/schema.json +27 -0
  31. package/src/index.d.ts +2 -1
  32. package/src/index.js +3 -1
  33. package/src/private.d.ts +4 -7
  34. package/src/private.js +4 -1
  35. package/src/tools/babel/plugins/pure-toplevel-functions.js +14 -3
  36. package/src/tools/esbuild/angular/compiler-plugin.d.ts +2 -4
  37. package/src/tools/esbuild/angular/compiler-plugin.js +21 -10
  38. package/src/tools/esbuild/angular-localize-init-warning-plugin.d.ts +16 -0
  39. package/src/tools/esbuild/angular-localize-init-warning-plugin.js +49 -0
  40. package/src/tools/esbuild/application-code-bundle.d.ts +2 -1
  41. package/src/tools/esbuild/application-code-bundle.js +37 -26
  42. package/src/tools/esbuild/bundler-execution-result.d.ts +10 -3
  43. package/src/tools/esbuild/bundler-execution-result.js +13 -10
  44. package/src/tools/esbuild/compiler-plugin-options.js +0 -1
  45. package/src/tools/esbuild/javascript-transformer.js +8 -4
  46. package/src/tools/vite/middlewares/assets-middleware.d.ts +2 -2
  47. package/src/tools/vite/middlewares/assets-middleware.js +4 -4
  48. package/src/tools/vite/plugins/angular-memory-plugin.js +10 -5
  49. package/src/tools/vite/plugins/setup-middlewares-plugin.d.ts +2 -2
  50. package/src/tools/vite/utils.d.ts +5 -1
  51. package/src/tools/vite/utils.js +2 -1
  52. package/src/utils/bundle-calculator.d.ts +1 -0
  53. package/src/utils/bundle-calculator.js +5 -4
  54. package/src/utils/environment-options.js +1 -1
  55. package/src/utils/i18n-options.js +3 -3
  56. package/src/utils/normalize-cache.js +1 -1
  57. package/src/utils/server-rendering/fetch-patch.js +2 -2
  58. package/tsconfig-build.json +0 -6
@@ -6,6 +6,7 @@
6
6
  * found in the LICENSE file at https://angular.dev/license
7
7
  */
8
8
  import type { Plugin } from 'esbuild';
9
+ import { AngularCompilation } from '../../angular/compilation';
9
10
  import { LoadResultCache } from '../load-result-cache';
10
11
  import { ComponentStylesheetBundler } from './component-stylesheets';
11
12
  import { SourceFileCache } from './source-file-cache';
@@ -13,9 +14,6 @@ export interface CompilerPluginOptions {
13
14
  sourcemap: boolean | 'external';
14
15
  tsconfig: string;
15
16
  jit?: boolean;
16
- browserOnlyBuild?: boolean;
17
- /** Skip TypeScript compilation setup. This is useful to re-use the TypeScript compilation from another plugin. */
18
- noopTypeScriptCompilation?: boolean;
19
17
  advancedOptimizations?: boolean;
20
18
  thirdPartySourcemaps?: boolean;
21
19
  fileReplacements?: Record<string, string>;
@@ -26,4 +24,4 @@ export interface CompilerPluginOptions {
26
24
  instrumentForCoverage?: (request: string) => boolean;
27
25
  templateUpdates?: Map<string, string>;
28
26
  }
29
- export declare function createCompilerPlugin(pluginOptions: CompilerPluginOptions, stylesheetBundler: ComponentStylesheetBundler): Plugin;
27
+ export declare function createCompilerPlugin(pluginOptions: CompilerPluginOptions, compilationOrFactory: AngularCompilation | (() => Promise<AngularCompilation>), stylesheetBundler: ComponentStylesheetBundler): Plugin;
@@ -56,7 +56,7 @@ const compilation_state_1 = require("./compilation-state");
56
56
  const file_reference_tracker_1 = require("./file-reference-tracker");
57
57
  const jit_plugin_callbacks_1 = require("./jit-plugin-callbacks");
58
58
  // eslint-disable-next-line max-lines-per-function
59
- function createCompilerPlugin(pluginOptions, stylesheetBundler) {
59
+ function createCompilerPlugin(pluginOptions, compilationOrFactory, stylesheetBundler) {
60
60
  return {
61
61
  name: 'angular-compiler',
62
62
  // eslint-disable-next-line max-lines-per-function
@@ -94,16 +94,17 @@ function createCompilerPlugin(pluginOptions, stylesheetBundler) {
94
94
  // Setup defines based on the values used by the Angular compiler-cli
95
95
  build.initialOptions.define ??= {};
96
96
  build.initialOptions.define['ngI18nClosureMode'] ??= 'false';
97
+ // The factory is only relevant for compatibility purposes with the private API.
98
+ // TODO: Update private API in the next major to allow compilation function factory removal here.
99
+ const compilation = typeof compilationOrFactory === 'function'
100
+ ? await compilationOrFactory()
101
+ : compilationOrFactory;
97
102
  // The in-memory cache of TypeScript file outputs will be used during the build in `onLoad` callbacks for TS files.
98
103
  // A string value indicates direct TS/NG output and a Uint8Array indicates fully transformed code.
99
104
  const typeScriptFileCache = pluginOptions.sourceFileCache?.typeScriptFileCache ??
100
105
  new Map();
101
106
  // The resources from component stylesheets and web workers that will be added to the build results output files
102
107
  const additionalResults = new Map();
103
- // Create new reusable compilation for the appropriate mode based on the `jit` plugin option
104
- const compilation = pluginOptions.noopTypeScriptCompilation
105
- ? new compilation_1.NoopCompilation()
106
- : await (0, compilation_1.createAngularCompilation)(!!pluginOptions.jit, !!pluginOptions.browserOnlyBuild);
107
108
  // Compilation is initially assumed to have errors until emitted
108
109
  let hasCompilationErrors = true;
109
110
  // Determines if TypeScript should process JavaScript files based on tsconfig `allowJs` option
@@ -128,8 +129,8 @@ function createCompilerPlugin(pluginOptions, stylesheetBundler) {
128
129
  // Angular compiler which does not have direct knowledge of transitive resource
129
130
  // dependencies or web worker processing.
130
131
  let modifiedFiles;
131
- if (pluginOptions.sourceFileCache?.modifiedFiles.size &&
132
- !pluginOptions.noopTypeScriptCompilation) {
132
+ if (!(compilation instanceof compilation_1.NoopCompilation) &&
133
+ pluginOptions.sourceFileCache?.modifiedFiles.size) {
133
134
  // TODO: Differentiate between changed input files and stale output files
134
135
  modifiedFiles = referencedFileTracker.update(pluginOptions.sourceFileCache.modifiedFiles);
135
136
  pluginOptions.sourceFileCache.invalidate(modifiedFiles);
@@ -141,9 +142,7 @@ function createCompilerPlugin(pluginOptions, stylesheetBundler) {
141
142
  // Remove any stale additional results based on modified files
142
143
  modifiedFiles.forEach((file) => additionalResults.delete(file));
143
144
  }
144
- if (!pluginOptions.noopTypeScriptCompilation &&
145
- compilation.update &&
146
- pluginOptions.sourceFileCache?.modifiedFiles.size) {
145
+ if (compilation.update && pluginOptions.sourceFileCache?.modifiedFiles.size) {
147
146
  await compilation.update(modifiedFiles ?? pluginOptions.sourceFileCache.modifiedFiles);
148
147
  }
149
148
  // Create Angular compiler host options
@@ -523,6 +522,18 @@ function createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserve
523
522
  notes: [{ text: `The 'module' option will be set to 'ES2022' instead.` }],
524
523
  });
525
524
  }
525
+ if (compilerOptions.isolatedModules && compilerOptions.emitDecoratorMetadata) {
526
+ setupWarnings?.push({
527
+ text: `TypeScript compiler option 'isolatedModules' may prevent the 'emitDecoratorMetadata' option from emitting all metadata.`,
528
+ location: null,
529
+ notes: [
530
+ {
531
+ text: `The 'emitDecoratorMetadata' option is not required by Angular` +
532
+ 'and can be removed if not explictly required by the project.',
533
+ },
534
+ ],
535
+ });
536
+ }
526
537
  // Synchronize custom resolve conditions.
527
538
  // Set if using the supported bundler resolution mode (bundler is the default in new projects)
528
539
  if (compilerOptions.moduleResolution === 100 /* ModuleResolutionKind.Bundler */) {
@@ -0,0 +1,16 @@
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 type { Plugin } from 'esbuild';
9
+ /**
10
+ * This plugin addresses an issue where '@angular/localize/init' is directly imported,
11
+ * potentially resulting in undefined behavior. By detecting such imports, the plugin
12
+ * issues a warning and suggests including '@angular/localize/init' as a polyfill.
13
+ *
14
+ * @returns An esbuild plugin.
15
+ */
16
+ export declare function createAngularLocalizeInitWarningPlugin(): Plugin;
@@ -0,0 +1,49 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.createAngularLocalizeInitWarningPlugin = createAngularLocalizeInitWarningPlugin;
11
+ const NG_LOCALIZE_RESOLUTION = Symbol('NG_LOCALIZE_RESOLUTION');
12
+ /**
13
+ * This plugin addresses an issue where '@angular/localize/init' is directly imported,
14
+ * potentially resulting in undefined behavior. By detecting such imports, the plugin
15
+ * issues a warning and suggests including '@angular/localize/init' as a polyfill.
16
+ *
17
+ * @returns An esbuild plugin.
18
+ */
19
+ function createAngularLocalizeInitWarningPlugin() {
20
+ return {
21
+ name: 'angular-localize-init-warning',
22
+ setup(build) {
23
+ build.onResolve({ filter: /^@angular\/localize\/init/ }, async (args) => {
24
+ if (args.pluginData?.[NG_LOCALIZE_RESOLUTION]) {
25
+ return null;
26
+ }
27
+ const { importer, kind, resolveDir, namespace, pluginData = {} } = args;
28
+ pluginData[NG_LOCALIZE_RESOLUTION] = true;
29
+ const result = await build.resolve(args.path, {
30
+ importer,
31
+ kind,
32
+ namespace,
33
+ pluginData,
34
+ resolveDir,
35
+ });
36
+ return {
37
+ ...result,
38
+ warnings: [
39
+ ...result.warnings,
40
+ {
41
+ text: `Direct import of '@angular/localize/init' detected. This may lead to undefined behavior.`,
42
+ notes: [{ text: `Include '@angular/localize/init' as a polyfill instead.` }],
43
+ },
44
+ ],
45
+ };
46
+ });
47
+ },
48
+ };
49
+ }
@@ -7,11 +7,12 @@
7
7
  */
8
8
  import type { BuildOptions } from 'esbuild';
9
9
  import type { NormalizedApplicationBuildOptions } from '../../builders/application/options';
10
+ import { AngularCompilation } from '../angular/compilation';
10
11
  import { ComponentStylesheetBundler } from './angular/component-stylesheets';
11
12
  import { SourceFileCache } from './angular/source-file-cache';
12
13
  import { BundlerOptionsFactory } from './bundler-context';
13
14
  import type { LoadResultCache } from './load-result-cache';
14
- export declare function createBrowserCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache, stylesheetBundler: ComponentStylesheetBundler, templateUpdates: Map<string, string> | undefined): BundlerOptionsFactory;
15
+ export declare function createBrowserCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache, stylesheetBundler: ComponentStylesheetBundler, angularCompilation: AngularCompilation, templateUpdates: Map<string, string> | undefined): BundlerOptionsFactory;
15
16
  export declare function createBrowserPolyfillBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache, stylesheetBundler: ComponentStylesheetBundler): BuildOptions | BundlerOptionsFactory | undefined;
16
17
  export declare function createServerPolyfillBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], loadResultCache: LoadResultCache | undefined): BundlerOptionsFactory | undefined;
17
18
  export declare function createServerMainCodeBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], sourceFileCache: SourceFileCache, stylesheetBundler: ComponentStylesheetBundler): BundlerOptionsFactory;
@@ -21,7 +21,9 @@ const node_path_1 = require("node:path");
21
21
  const schema_1 = require("../../builders/application/schema");
22
22
  const environment_options_1 = require("../../utils/environment-options");
23
23
  const manifest_1 = require("../../utils/server-rendering/manifest");
24
+ const compilation_1 = require("../angular/compilation");
24
25
  const compiler_plugin_1 = require("./angular/compiler-plugin");
26
+ const angular_localize_init_warning_plugin_1 = require("./angular-localize-init-warning-plugin");
25
27
  const compiler_plugin_options_1 = require("./compiler-plugin-options");
26
28
  const external_packages_plugin_1 = require("./external-packages-plugin");
27
29
  const i18n_locale_plugin_1 = require("./i18n-locale-plugin");
@@ -32,7 +34,7 @@ const sourcemap_ignorelist_plugin_1 = require("./sourcemap-ignorelist-plugin");
32
34
  const utils_1 = require("./utils");
33
35
  const virtual_module_plugin_1 = require("./virtual-module-plugin");
34
36
  const wasm_plugin_1 = require("./wasm-plugin");
35
- function createBrowserCodeBundleOptions(options, target, sourceFileCache, stylesheetBundler, templateUpdates) {
37
+ function createBrowserCodeBundleOptions(options, target, sourceFileCache, stylesheetBundler, angularCompilation, templateUpdates) {
36
38
  return (loadCache) => {
37
39
  const { entryPoints, outputNames, polyfills } = options;
38
40
  const pluginOptions = (0, compiler_plugin_options_1.createCompilerPluginOptions)(options, sourceFileCache, loadCache, templateUpdates);
@@ -53,9 +55,10 @@ function createBrowserCodeBundleOptions(options, target, sourceFileCache, styles
53
55
  (0, loader_import_attribute_plugin_1.createLoaderImportAttributePlugin)(),
54
56
  (0, wasm_plugin_1.createWasmPlugin)({ allowAsync: zoneless, cache: loadCache }),
55
57
  (0, sourcemap_ignorelist_plugin_1.createSourcemapIgnorelistPlugin)(),
58
+ (0, angular_localize_init_warning_plugin_1.createAngularLocalizeInitWarningPlugin)(),
56
59
  (0, compiler_plugin_1.createCompilerPlugin)(
57
60
  // JS/TS options
58
- pluginOptions,
61
+ pluginOptions, angularCompilation,
59
62
  // Component stylesheet bundler
60
63
  stylesheetBundler),
61
64
  ],
@@ -63,19 +66,7 @@ function createBrowserCodeBundleOptions(options, target, sourceFileCache, styles
63
66
  if (options.plugins) {
64
67
  buildOptions.plugins?.push(...options.plugins);
65
68
  }
66
- if (options.externalPackages) {
67
- // Package files affected by a customized loader should not be implicitly marked as external
68
- if (options.loaderExtensions ||
69
- options.plugins ||
70
- typeof options.externalPackages === 'object') {
71
- // Plugin must be added after custom plugins to ensure any added loader options are considered
72
- buildOptions.plugins?.push((0, external_packages_plugin_1.createExternalPackagesPlugin)(options.externalPackages !== true ? options.externalPackages : undefined));
73
- }
74
- else {
75
- // Safe to use the packages external option directly
76
- buildOptions.packages = 'external';
77
- }
78
- }
69
+ appendOptionsForExternalPackages(options, buildOptions);
79
70
  return buildOptions;
80
71
  };
81
72
  }
@@ -107,7 +98,9 @@ function createBrowserPolyfillBundleOptions(options, target, sourceFileCache, st
107
98
  const pluginOptions = (0, compiler_plugin_options_1.createCompilerPluginOptions)(options, sourceFileCache);
108
99
  buildOptions.plugins.push((0, compiler_plugin_1.createCompilerPlugin)(
109
100
  // JS/TS options
110
- { ...pluginOptions, noopTypeScriptCompilation: true },
101
+ pluginOptions,
102
+ // Browser compilation handles the actual Angular code compilation
103
+ new compilation_1.NoopCompilation(),
111
104
  // Component stylesheet options are unused for polyfills but required by the plugin
112
105
  stylesheetBundler));
113
106
  }
@@ -196,18 +189,18 @@ function createServerMainCodeBundleOptions(options, target, sourceFileCache, sty
196
189
  plugins: [
197
190
  (0, wasm_plugin_1.createWasmPlugin)({ allowAsync: zoneless, cache: loadResultCache }),
198
191
  (0, sourcemap_ignorelist_plugin_1.createSourcemapIgnorelistPlugin)(),
192
+ (0, angular_localize_init_warning_plugin_1.createAngularLocalizeInitWarningPlugin)(),
199
193
  (0, compiler_plugin_1.createCompilerPlugin)(
200
194
  // JS/TS options
201
- { ...pluginOptions, noopTypeScriptCompilation: true },
195
+ pluginOptions,
196
+ // Browser compilation handles the actual Angular code compilation
197
+ new compilation_1.NoopCompilation(),
202
198
  // Component stylesheet bundler
203
199
  stylesheetBundler),
204
200
  ],
205
201
  };
206
202
  buildOptions.plugins ??= [];
207
- if (externalPackages) {
208
- buildOptions.packages = 'external';
209
- }
210
- else {
203
+ if (!externalPackages) {
211
204
  buildOptions.plugins.push((0, rxjs_esm_resolution_plugin_1.createRxjsEsmResolutionPlugin)());
212
205
  }
213
206
  // Mark manifest and polyfills file as external as these are generated by a different bundle step.
@@ -266,6 +259,7 @@ function createServerMainCodeBundleOptions(options, target, sourceFileCache, sty
266
259
  if (options.plugins) {
267
260
  buildOptions.plugins.push(...options.plugins);
268
261
  }
262
+ appendOptionsForExternalPackages(options, buildOptions);
269
263
  return buildOptions;
270
264
  };
271
265
  }
@@ -299,18 +293,18 @@ function createSsrEntryCodeBundleOptions(options, target, sourceFileCache, style
299
293
  supported: (0, utils_1.getFeatureSupport)(target, true),
300
294
  plugins: [
301
295
  (0, sourcemap_ignorelist_plugin_1.createSourcemapIgnorelistPlugin)(),
296
+ (0, angular_localize_init_warning_plugin_1.createAngularLocalizeInitWarningPlugin)(),
302
297
  (0, compiler_plugin_1.createCompilerPlugin)(
303
298
  // JS/TS options
304
- { ...pluginOptions, noopTypeScriptCompilation: true },
299
+ pluginOptions,
300
+ // Browser compilation handles the actual Angular code compilation
301
+ new compilation_1.NoopCompilation(),
305
302
  // Component stylesheet bundler
306
303
  stylesheetBundler),
307
304
  ],
308
305
  };
309
306
  buildOptions.plugins ??= [];
310
- if (externalPackages) {
311
- buildOptions.packages = 'external';
312
- }
313
- else {
307
+ if (!externalPackages) {
314
308
  buildOptions.plugins.push((0, rxjs_esm_resolution_plugin_1.createRxjsEsmResolutionPlugin)());
315
309
  }
316
310
  // Mark manifest file as external. As this will be generated later on.
@@ -366,6 +360,7 @@ function createSsrEntryCodeBundleOptions(options, target, sourceFileCache, style
366
360
  if (options.plugins) {
367
361
  buildOptions.plugins.push(...options.plugins);
368
362
  }
363
+ appendOptionsForExternalPackages(options, buildOptions);
369
364
  return buildOptions;
370
365
  };
371
366
  }
@@ -524,3 +519,19 @@ function entryFileToWorkspaceRelative(workspaceRoot, entryFile) {
524
519
  .replace(/.[mc]?ts$/, '')
525
520
  .replace(/\\/g, '/'));
526
521
  }
522
+ function appendOptionsForExternalPackages(options, buildOptions) {
523
+ if (!options.externalPackages) {
524
+ return;
525
+ }
526
+ buildOptions.plugins ??= [];
527
+ // Package files affected by a customized loader should not be implicitly marked as external
528
+ if (options.loaderExtensions || options.plugins || typeof options.externalPackages === 'object') {
529
+ // Plugin must be added after custom plugins to ensure any added loader options are considered
530
+ buildOptions.plugins.push((0, external_packages_plugin_1.createExternalPackagesPlugin)(options.externalPackages !== true ? options.externalPackages : undefined));
531
+ buildOptions.packages = undefined;
532
+ }
533
+ else {
534
+ // Safe to use the packages external option directly
535
+ buildOptions.packages = 'external';
536
+ }
537
+ }
@@ -22,7 +22,11 @@ export interface RebuildState {
22
22
  componentStyleBundler: ComponentStylesheetBundler;
23
23
  codeBundleCache?: SourceFileCache;
24
24
  fileChanges: ChangedFiles;
25
- previousOutputHashes: Map<string, string>;
25
+ previousOutputInfo: ReadonlyMap<string, {
26
+ hash: string;
27
+ type: BuildOutputFileType;
28
+ }>;
29
+ previousAssetsInfo: ReadonlyMap<string, string>;
26
30
  templateUpdates?: Map<string, string>;
27
31
  }
28
32
  export interface ExternalResultMetadata {
@@ -81,8 +85,11 @@ export declare class ExecutionResult {
81
85
  errors: (PartialMessage | Message)[];
82
86
  externalMetadata: ExternalResultMetadata | undefined;
83
87
  };
84
- get watchFiles(): string[];
88
+ get watchFiles(): Readonly<string[]>;
85
89
  createRebuildState(fileChanges: ChangedFiles): RebuildState;
86
- findChangedFiles(previousOutputHashes: Map<string, string>): Set<string>;
90
+ findChangedFiles(previousOutputHashes: ReadonlyMap<string, {
91
+ hash: string;
92
+ type: BuildOutputFileType;
93
+ }>): Set<string>;
87
94
  dispose(): Promise<void>;
88
95
  }
@@ -103,16 +103,18 @@ class ExecutionResult {
103
103
  };
104
104
  }
105
105
  get watchFiles() {
106
- // Bundler contexts internally normalize file dependencies
107
- const files = this.rebuildContexts.typescriptContexts
108
- .flatMap((context) => [...context.watchFiles])
109
- .concat(this.rebuildContexts.otherContexts.flatMap((context) => [...context.watchFiles]));
110
- if (this.codeBundleCache?.referencedFiles) {
106
+ const { typescriptContexts, otherContexts } = this.rebuildContexts;
107
+ return [
108
+ // Bundler contexts internally normalize file dependencies.
109
+ ...typescriptContexts.flatMap((context) => [...context.watchFiles]),
110
+ ...otherContexts.flatMap((context) => [...context.watchFiles]),
111
111
  // These files originate from TS/NG and can have POSIX path separators even on Windows.
112
112
  // To ensure path comparisons are valid, all these paths must be normalized.
113
- files.push(...this.codeBundleCache.referencedFiles.map(node_path_1.normalize));
114
- }
115
- return files.concat(this.extraWatchFiles);
113
+ ...(this.codeBundleCache?.referencedFiles?.map(node_path_1.normalize) ?? []),
114
+ // The assets source files.
115
+ ...this.assetFiles.map(({ source }) => source),
116
+ ...this.extraWatchFiles,
117
+ ];
116
118
  }
117
119
  createRebuildState(fileChanges) {
118
120
  return {
@@ -120,14 +122,15 @@ class ExecutionResult {
120
122
  codeBundleCache: this.codeBundleCache,
121
123
  componentStyleBundler: this.componentStyleBundler,
122
124
  fileChanges,
123
- previousOutputHashes: new Map(this.outputFiles.map((file) => [file.path, file.hash])),
125
+ previousOutputInfo: new Map(this.outputFiles.map(({ path, hash, type }) => [path, { hash, type }])),
126
+ previousAssetsInfo: new Map(this.assetFiles.map(({ source, destination }) => [source, destination])),
124
127
  templateUpdates: this.templateUpdates,
125
128
  };
126
129
  }
127
130
  findChangedFiles(previousOutputHashes) {
128
131
  const changed = new Set();
129
132
  for (const file of this.outputFiles) {
130
- const previousHash = previousOutputHashes.get(file.path);
133
+ const previousHash = previousOutputHashes.get(file.path)?.hash;
131
134
  if (previousHash === undefined || previousHash !== file.hash) {
132
135
  changed.add(file.path);
133
136
  }
@@ -12,7 +12,6 @@ function createCompilerPluginOptions(options, sourceFileCache, loadResultCache,
12
12
  const { sourcemapOptions, tsconfig, fileReplacements, advancedOptimizations, jit, externalRuntimeStyles, instrumentForCoverage, } = options;
13
13
  const incremental = !!options.watch;
14
14
  return {
15
- browserOnlyBuild: !options.serverEntryPoint,
16
15
  sourcemap: !!sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
17
16
  thirdPartySourcemaps: sourcemapOptions.vendor,
18
17
  tsconfig,
@@ -39,12 +39,16 @@ class JavaScriptTransformer {
39
39
  this.#fileCacheKeyBase = Buffer.from(JSON.stringify(this.#commonOptions), 'utf-8');
40
40
  }
41
41
  #ensureWorkerPool() {
42
- this.#workerPool ??= new worker_pool_1.WorkerPool({
42
+ const workerPoolOptions = {
43
43
  filename: require.resolve('./javascript-transformer-worker'),
44
44
  maxThreads: this.maxThreads,
45
- // Prevent passing `--import` (loader-hooks) from parent to child worker.
46
- execArgv: process.execArgv.filter((v) => v !== utils_1.IMPORT_EXEC_ARGV),
47
- });
45
+ };
46
+ // Prevent passing SSR `--import` (loader-hooks) from parent to child worker.
47
+ const filteredExecArgv = process.execArgv.filter((v) => v !== utils_1.IMPORT_EXEC_ARGV);
48
+ if (process.execArgv.length !== filteredExecArgv.length) {
49
+ workerPoolOptions.execArgv = filteredExecArgv;
50
+ }
51
+ this.#workerPool ??= new worker_pool_1.WorkerPool(workerPoolOptions);
48
52
  return this.#workerPool;
49
53
  }
50
54
  /**
@@ -6,10 +6,10 @@
6
6
  * found in the LICENSE file at https://angular.dev/license
7
7
  */
8
8
  import type { Connect, ViteDevServer } from 'vite';
9
- import { AngularMemoryOutputFiles } from '../utils';
9
+ import { AngularMemoryOutputFiles, AngularOutputAssets } from '../utils';
10
10
  export interface ComponentStyleRecord {
11
11
  rawContent: Uint8Array;
12
12
  used?: Set<string>;
13
13
  reload?: boolean;
14
14
  }
15
- export declare function createAngularAssetsMiddleware(server: ViteDevServer, assets: Map<string, string>, outputFiles: AngularMemoryOutputFiles, componentStyles: Map<string, ComponentStyleRecord>, encapsulateStyle: (style: Uint8Array, componentId: string) => string): Connect.NextHandleFunction;
15
+ export declare function createAngularAssetsMiddleware(server: ViteDevServer, assets: AngularOutputAssets, outputFiles: AngularMemoryOutputFiles, componentStyles: Map<string, ComponentStyleRecord>, encapsulateStyle: (style: Uint8Array, componentId: string) => string): Connect.NextHandleFunction;
@@ -22,15 +22,15 @@ function createAngularAssetsMiddleware(server, assets, outputFiles, componentSty
22
22
  const extension = (0, node_path_1.extname)(pathname);
23
23
  const pathnameHasTrailingSlash = pathname[pathname.length - 1] === '/';
24
24
  // Rewrite all build assets to a vite raw fs URL
25
- const assetSourcePath = assets.get(pathname);
26
- if (assetSourcePath !== undefined) {
25
+ const asset = assets.get(pathname);
26
+ if (asset) {
27
27
  // Workaround to disable Vite transformer middleware.
28
28
  // See: https://github.com/vitejs/vite/blob/746a1daab0395f98f0afbdee8f364cb6cf2f3b3f/packages/vite/src/node/server/middlewares/transform.ts#L201 and
29
29
  // https://github.com/vitejs/vite/blob/746a1daab0395f98f0afbdee8f364cb6cf2f3b3f/packages/vite/src/node/server/transformRequest.ts#L204-L206
30
30
  req.headers.accept = 'text/html';
31
31
  // The encoding needs to match what happens in the vite static middleware.
32
32
  // ref: https://github.com/vitejs/vite/blob/d4f13bd81468961c8c926438e815ab6b1c82735e/packages/vite/src/node/server/middlewares/static.ts#L163
33
- req.url = `${server.config.base}@fs/${encodeURI(assetSourcePath)}`;
33
+ req.url = `${server.config.base}@fs/${encodeURI(asset.source)}`;
34
34
  next();
35
35
  return;
36
36
  }
@@ -43,7 +43,7 @@ function createAngularAssetsMiddleware(server, assets, outputFiles, componentSty
43
43
  : // Non-trailing slash check for fallback `.html`
44
44
  assets.get(pathname + '.html');
45
45
  if (htmlAssetSourcePath) {
46
- req.url = `${server.config.base}@fs/${encodeURI(htmlAssetSourcePath)}`;
46
+ req.url = `${server.config.base}@fs/${encodeURI(htmlAssetSourcePath.source)}`;
47
47
  next();
48
48
  return;
49
49
  }
@@ -16,6 +16,7 @@ const promises_1 = require("node:fs/promises");
16
16
  const node_path_1 = require("node:path");
17
17
  const load_esm_1 = require("../../../utils/load-esm");
18
18
  const ANGULAR_PREFIX = '/@ng/';
19
+ const VITE_FS_PREFIX = '/@fs/';
19
20
  async function createAngularMemoryPlugin(options) {
20
21
  const { virtualProjectRoot, outputFiles, external } = options;
21
22
  const { normalizePath } = await (0, load_esm_1.loadEsmModule)('vite');
@@ -24,6 +25,9 @@ async function createAngularMemoryPlugin(options) {
24
25
  // Ensures plugin hooks run before built-in Vite hooks
25
26
  enforce: 'pre',
26
27
  async resolveId(source, importer, { ssr }) {
28
+ if (source.startsWith(VITE_FS_PREFIX)) {
29
+ return;
30
+ }
27
31
  // For SSR with component HMR, pass through as a virtual module
28
32
  if (ssr && source.startsWith(ANGULAR_PREFIX)) {
29
33
  return '\0' + source;
@@ -35,25 +39,26 @@ async function createAngularMemoryPlugin(options) {
35
39
  return source;
36
40
  }
37
41
  if (importer) {
38
- if (source[0] === '.' && normalizePath(importer).startsWith(virtualProjectRoot)) {
42
+ const normalizedImporter = normalizePath(importer);
43
+ if (source[0] === '.' && normalizedImporter.startsWith(virtualProjectRoot)) {
39
44
  // Remove query if present
40
- const [importerFile] = importer.split('?', 1);
45
+ const [importerFile] = normalizedImporter.split('?', 1);
41
46
  source = '/' + (0, node_path_1.join)((0, node_path_1.dirname)((0, node_path_1.relative)(virtualProjectRoot, importerFile)), source);
42
47
  }
43
48
  else if (!ssr &&
44
49
  source[0] === '/' &&
45
50
  importer.endsWith('index.html') &&
46
- normalizePath(importer).startsWith(virtualProjectRoot)) {
51
+ normalizedImporter.startsWith(virtualProjectRoot)) {
47
52
  // This is only needed when using SSR and `angularSsrMiddleware` (old style) to correctly resolve
48
53
  // .js files when using lazy-loading.
49
54
  // Remove query if present
50
- const [importerFile] = importer.split('?', 1);
55
+ const [importerFile] = normalizedImporter.split('?', 1);
51
56
  source =
52
57
  '/' + (0, node_path_1.join)((0, node_path_1.dirname)((0, node_path_1.relative)(virtualProjectRoot, importerFile)), (0, node_path_1.basename)(source));
53
58
  }
54
59
  }
55
60
  const [file] = source.split('?', 1);
56
- if (outputFiles.has(file)) {
61
+ if (outputFiles.has(normalizePath(file))) {
57
62
  return (0, node_path_1.join)(virtualProjectRoot, source);
58
63
  }
59
64
  },
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import type { Connect, Plugin } from 'vite';
9
9
  import { ComponentStyleRecord } from '../middlewares';
10
- import { AngularMemoryOutputFiles } from '../utils';
10
+ import { AngularMemoryOutputFiles, AngularOutputAssets } from '../utils';
11
11
  export declare enum ServerSsrMode {
12
12
  /**
13
13
  * No SSR
@@ -32,7 +32,7 @@ export declare enum ServerSsrMode {
32
32
  }
33
33
  interface AngularSetupMiddlewaresPluginOptions {
34
34
  outputFiles: AngularMemoryOutputFiles;
35
- assets: Map<string, string>;
35
+ assets: AngularOutputAssets;
36
36
  extensionMiddleware?: Connect.NextHandleFunction[];
37
37
  indexHtmlTransformer?: (content: string) => Promise<string>;
38
38
  componentStyles: Map<string, ComponentStyleRecord>;
@@ -12,10 +12,13 @@ export type AngularMemoryOutputFiles = Map<string, {
12
12
  hash: string;
13
13
  servable: boolean;
14
14
  }>;
15
+ export type AngularOutputAssets = Map<string, {
16
+ source: string;
17
+ }>;
15
18
  export declare function pathnameWithoutBasePath(url: string, basePath: string): string;
16
19
  export declare function lookupMimeTypeFromRequest(url: string): string | undefined;
17
20
  export type EsbuildLoaderOption = Exclude<DepOptimizationConfig['esbuildOptions'], undefined>['loader'];
18
- export declare function getDepOptimizationConfig({ disabled, exclude, include, target, zoneless, prebundleTransformer, ssr, loader, thirdPartySourcemaps, }: {
21
+ export declare function getDepOptimizationConfig({ disabled, exclude, include, target, zoneless, prebundleTransformer, ssr, loader, thirdPartySourcemaps, define, }: {
19
22
  disabled: boolean;
20
23
  exclude: string[];
21
24
  include: string[];
@@ -25,4 +28,5 @@ export declare function getDepOptimizationConfig({ disabled, exclude, include, t
25
28
  zoneless: boolean;
26
29
  loader?: EsbuildLoaderOption;
27
30
  thirdPartySourcemaps: boolean;
31
+ define: Record<string, string> | undefined;
28
32
  }): DepOptimizationConfig;
@@ -28,7 +28,7 @@ function lookupMimeTypeFromRequest(url) {
28
28
  }
29
29
  return extension && (0, mrmime_1.lookup)(extension);
30
30
  }
31
- function getDepOptimizationConfig({ disabled, exclude, include, target, zoneless, prebundleTransformer, ssr, loader, thirdPartySourcemaps, }) {
31
+ function getDepOptimizationConfig({ disabled, exclude, include, target, zoneless, prebundleTransformer, ssr, loader, thirdPartySourcemaps, define = {}, }) {
32
32
  const plugins = [
33
33
  {
34
34
  name: `angular-vite-optimize-deps${ssr ? '-ssr' : ''}${thirdPartySourcemaps ? '-vendor-sourcemap' : ''}`,
@@ -57,6 +57,7 @@ function getDepOptimizationConfig({ disabled, exclude, include, target, zoneless
57
57
  plugins,
58
58
  loader,
59
59
  define: {
60
+ ...define,
60
61
  'ngServerMode': `${ssr}`,
61
62
  },
62
63
  resolveExtensions: ['.mjs', '.js', '.cjs'],
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import { Budget as BudgetEntry, Type as BudgetType } from '../builders/application/schema';
9
9
  export { type BudgetEntry, BudgetType };
10
+ export declare const BYTES_IN_KILOBYTE = 1000;
10
11
  export interface Threshold {
11
12
  limit: number;
12
13
  type: ThresholdType;
@@ -7,13 +7,14 @@
7
7
  * found in the LICENSE file at https://angular.dev/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.ThresholdSeverity = exports.BudgetType = void 0;
10
+ exports.ThresholdSeverity = exports.BYTES_IN_KILOBYTE = exports.BudgetType = void 0;
11
11
  exports.calculateThresholds = calculateThresholds;
12
12
  exports.checkBudgets = checkBudgets;
13
13
  exports.checkThresholds = checkThresholds;
14
14
  const schema_1 = require("../builders/application/schema");
15
15
  Object.defineProperty(exports, "BudgetType", { enumerable: true, get: function () { return schema_1.Type; } });
16
16
  const format_bytes_1 = require("./format-bytes");
17
+ exports.BYTES_IN_KILOBYTE = 1000;
17
18
  var ThresholdType;
18
19
  (function (ThresholdType) {
19
20
  ThresholdType["Max"] = "maximum";
@@ -242,13 +243,13 @@ function calculateBytes(input, baseline, factor = 1) {
242
243
  value = (baselineBytes * value) / 100;
243
244
  break;
244
245
  case 'kb':
245
- value *= 1024;
246
+ value *= exports.BYTES_IN_KILOBYTE;
246
247
  break;
247
248
  case 'mb':
248
- value *= 1024 * 1024;
249
+ value *= exports.BYTES_IN_KILOBYTE * exports.BYTES_IN_KILOBYTE;
249
250
  break;
250
251
  case 'gb':
251
- value *= 1024 * 1024 * 1024;
252
+ value *= exports.BYTES_IN_KILOBYTE * exports.BYTES_IN_KILOBYTE * exports.BYTES_IN_KILOBYTE;
252
253
  break;
253
254
  }
254
255
  if (baselineBytes === 0) {
@@ -83,7 +83,7 @@ exports.useJSONBuildLogs = isPresent(buildLogsJsonVariable) && isEnabled(buildLo
83
83
  const optimizeChunksVariable = process.env['NG_BUILD_OPTIMIZE_CHUNKS'];
84
84
  exports.shouldOptimizeChunks = isPresent(optimizeChunksVariable) && isEnabled(optimizeChunksVariable);
85
85
  const hmrComponentStylesVariable = process.env['NG_HMR_CSTYLES'];
86
- exports.useComponentStyleHmr = !isPresent(hmrComponentStylesVariable) || !isDisabled(hmrComponentStylesVariable);
86
+ exports.useComponentStyleHmr = isPresent(hmrComponentStylesVariable) && isEnabled(hmrComponentStylesVariable);
87
87
  const hmrComponentTemplateVariable = process.env['NG_HMR_TEMPLATES'];
88
88
  exports.useComponentTemplateHmr = !isPresent(hmrComponentTemplateVariable) || !isDisabled(hmrComponentTemplateVariable);
89
89
  const partialSsrBuildVariable = process.env['NG_BUILD_PARTIAL_SSR'];