@angular-devkit/build-angular 17.0.0-rc.1 → 17.0.0-rc.3

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 (47) hide show
  1. package/package.json +11 -10
  2. package/src/builders/app-shell/render-worker.d.ts +1 -1
  3. package/src/builders/app-shell/render-worker.js +16 -9
  4. package/src/builders/application/build-action.js +5 -2
  5. package/src/builders/application/execute-build.js +28 -18
  6. package/src/builders/browser-esbuild/index.js +9 -1
  7. package/src/builders/dev-server/vite-server.js +59 -20
  8. package/src/builders/extract-i18n/application-extraction.js +1 -0
  9. package/src/builders/prerender/routes-extractor-worker.js +1 -1
  10. package/src/tools/babel/plugins/elide-angular-metadata.js +14 -2
  11. package/src/tools/esbuild/angular/compiler-plugin.js +2 -1
  12. package/src/tools/esbuild/application-code-bundle.d.ts +3 -2
  13. package/src/tools/esbuild/application-code-bundle.js +8 -12
  14. package/src/tools/esbuild/bundler-context.d.ts +1 -1
  15. package/src/tools/esbuild/bundler-context.js +7 -2
  16. package/src/tools/esbuild/bundler-execution-result.d.ts +2 -0
  17. package/src/tools/esbuild/bundler-execution-result.js +14 -0
  18. package/src/tools/esbuild/commonjs-checker.js +3 -3
  19. package/src/tools/esbuild/global-scripts.d.ts +2 -3
  20. package/src/tools/esbuild/global-scripts.js +72 -69
  21. package/src/tools/esbuild/global-styles.d.ts +2 -3
  22. package/src/tools/esbuild/global-styles.js +35 -33
  23. package/src/tools/esbuild/javascript-transformer-worker.js +3 -2
  24. package/src/tools/esbuild/javascript-transformer.d.ts +1 -0
  25. package/src/tools/esbuild/javascript-transformer.js +25 -13
  26. package/src/tools/esbuild/utils.d.ts +1 -1
  27. package/src/tools/esbuild/utils.js +18 -4
  28. package/src/tools/esbuild/watcher.d.ts +1 -0
  29. package/src/tools/esbuild/watcher.js +3 -0
  30. package/src/utils/check-port.js +3 -1
  31. package/src/utils/environment-options.d.ts +1 -0
  32. package/src/utils/environment-options.js +3 -1
  33. package/src/utils/load-esm.d.ts +0 -2
  34. package/src/utils/routes-extractor/extractor.d.ts +1 -1
  35. package/src/utils/routes-extractor/extractor.js +2 -2
  36. package/src/utils/server-rendering/esm-in-memory-loader/loader-hooks.js +3 -2
  37. package/src/utils/server-rendering/fetch-patch.d.ts +8 -0
  38. package/src/utils/server-rendering/fetch-patch.js +66 -0
  39. package/src/utils/server-rendering/prerender.js +25 -30
  40. package/src/utils/server-rendering/render-worker.d.ts +4 -2
  41. package/src/utils/server-rendering/render-worker.js +8 -4
  42. package/src/utils/server-rendering/routes-extractor-worker.d.ts +5 -3
  43. package/src/utils/server-rendering/routes-extractor-worker.js +10 -4
  44. package/src/tools/esbuild/javascript-transfomer-plugin.d.ts +0 -19
  45. package/src/tools/esbuild/javascript-transfomer-plugin.js +0 -51
  46. package/src/utils/server-rendering/prerender-server.d.ts +0 -21
  47. package/src/utils/server-rendering/prerender-server.js +0 -102
@@ -60,6 +60,9 @@ class ExecutionResult {
60
60
  if (this.codeBundleCache?.referencedFiles) {
61
61
  files.push(...this.codeBundleCache.referencedFiles);
62
62
  }
63
+ if (this.codeBundleCache?.loadResultCache) {
64
+ files.push(...this.codeBundleCache.loadResultCache.watchFiles);
65
+ }
63
66
  return files;
64
67
  }
65
68
  createRebuildState(fileChanges) {
@@ -68,8 +71,19 @@ class ExecutionResult {
68
71
  rebuildContexts: this.rebuildContexts,
69
72
  codeBundleCache: this.codeBundleCache,
70
73
  fileChanges,
74
+ previousOutputHashes: new Map(this.outputFiles.map((file) => [file.path, file.hash])),
71
75
  };
72
76
  }
77
+ findChangedFiles(previousOutputHashes) {
78
+ const changed = new Set();
79
+ for (const file of this.outputFiles) {
80
+ const previousHash = previousOutputHashes.get(file.path);
81
+ if (previousHash === undefined || previousHash !== file.hash) {
82
+ changed.add(file.path);
83
+ }
84
+ }
85
+ return changed;
86
+ }
73
87
  async dispose() {
74
88
  await Promise.allSettled(this.rebuildContexts.map((context) => context.dispose()));
75
89
  }
@@ -84,11 +84,11 @@ function checkCommonJSModules(metafile, allowedCommonJsDependencies) {
84
84
  }
85
85
  }
86
86
  if (notAllowed) {
87
- // Issue a diagnostic message and skip all descendants since they are also most
88
- // likely not ESM but solved by addressing this import.
87
+ // Issue a diagnostic message for CommonJS module
89
88
  messages.push(createCommonJSModuleError(request, currentFile));
90
- continue;
91
89
  }
90
+ // Skip all descendants since they are also most likely not ESM but solved by addressing this import
91
+ continue;
92
92
  }
93
93
  // Add the path so that its imports can be checked
94
94
  files.push(imported.path);
@@ -5,13 +5,12 @@
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.io/license
7
7
  */
8
- import type { BuildOptions } from 'esbuild';
9
8
  import type { NormalizedApplicationBuildOptions } from '../../builders/application/options';
10
- import { LoadResultCache } from './load-result-cache';
9
+ import { BundlerOptionsFactory } from './bundler-context';
11
10
  /**
12
11
  * Create an esbuild 'build' options object for all global scripts defined in the user provied
13
12
  * build options.
14
13
  * @param options The builder's user-provider normalized options.
15
14
  * @returns An esbuild BuildOptions object.
16
15
  */
17
- export declare function createGlobalScriptsBundleOptions(options: NormalizedApplicationBuildOptions, initial: boolean, loadCache?: LoadResultCache): BuildOptions | undefined;
16
+ export declare function createGlobalScriptsBundleOptions(options: NormalizedApplicationBuildOptions, initial: boolean): BundlerOptionsFactory | undefined;
@@ -48,7 +48,7 @@ const virtual_module_plugin_1 = require("./virtual-module-plugin");
48
48
  * @param options The builder's user-provider normalized options.
49
49
  * @returns An esbuild BuildOptions object.
50
50
  */
51
- function createGlobalScriptsBundleOptions(options, initial, loadCache) {
51
+ function createGlobalScriptsBundleOptions(options, initial) {
52
52
  const { globalScripts, optimizationOptions, outputNames, preserveSymlinks, sourcemapOptions, workspaceRoot, } = options;
53
53
  const namespace = 'angular:script/global';
54
54
  const entryPoints = {};
@@ -63,77 +63,80 @@ function createGlobalScriptsBundleOptions(options, initial, loadCache) {
63
63
  if (found === false) {
64
64
  return;
65
65
  }
66
- return {
67
- absWorkingDir: workspaceRoot,
68
- bundle: false,
69
- splitting: false,
70
- entryPoints,
71
- entryNames: initial ? outputNames.bundles : '[name]',
72
- assetNames: outputNames.media,
73
- mainFields: ['script', 'browser', 'main'],
74
- conditions: ['script'],
75
- resolveExtensions: ['.mjs', '.js'],
76
- logLevel: options.verbose ? 'debug' : 'silent',
77
- metafile: true,
78
- minify: optimizationOptions.scripts,
79
- outdir: workspaceRoot,
80
- sourcemap: sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
81
- write: false,
82
- platform: 'neutral',
83
- preserveSymlinks,
84
- plugins: [
85
- (0, sourcemap_ignorelist_plugin_1.createSourcemapIgnorelistPlugin)(),
86
- (0, virtual_module_plugin_1.createVirtualModulePlugin)({
87
- namespace,
88
- external: true,
89
- // Add the `js` extension here so that esbuild generates an output file with the extension
90
- transformPath: (path) => path.slice(namespace.length + 1) + '.js',
91
- loadContent: (args, build) => (0, load_result_cache_1.createCachedLoad)(loadCache, async (args) => {
92
- const files = globalScripts.find(({ name }) => name === args.path.slice(0, -3))?.files;
93
- (0, node_assert_1.default)(files, `Invalid operation: global scripts name not found [${args.path}]`);
94
- // Global scripts are concatenated using magic-string instead of bundled via esbuild.
95
- const bundleContent = new magic_string_1.Bundle();
96
- const watchFiles = [];
97
- for (const filename of files) {
98
- let fileContent;
99
- try {
100
- // Attempt to read as a relative path from the workspace root
101
- const fullPath = node_path_1.default.join(workspaceRoot, filename);
102
- fileContent = await (0, promises_1.readFile)(fullPath, 'utf-8');
103
- watchFiles.push(fullPath);
104
- }
105
- catch (e) {
106
- (0, error_1.assertIsError)(e);
107
- if (e.code !== 'ENOENT') {
108
- throw e;
66
+ return (loadCache) => {
67
+ return {
68
+ absWorkingDir: workspaceRoot,
69
+ bundle: false,
70
+ splitting: false,
71
+ entryPoints,
72
+ entryNames: initial ? outputNames.bundles : '[name]',
73
+ assetNames: outputNames.media,
74
+ mainFields: ['script', 'browser', 'main'],
75
+ conditions: ['script'],
76
+ resolveExtensions: ['.mjs', '.js'],
77
+ logLevel: options.verbose ? 'debug' : 'silent',
78
+ metafile: true,
79
+ minify: optimizationOptions.scripts,
80
+ outdir: workspaceRoot,
81
+ sourcemap: sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
82
+ write: false,
83
+ platform: 'neutral',
84
+ preserveSymlinks,
85
+ plugins: [
86
+ (0, sourcemap_ignorelist_plugin_1.createSourcemapIgnorelistPlugin)(),
87
+ (0, virtual_module_plugin_1.createVirtualModulePlugin)({
88
+ namespace,
89
+ external: true,
90
+ // Add the `js` extension here so that esbuild generates an output file with the extension
91
+ transformPath: (path) => path.slice(namespace.length + 1) + '.js',
92
+ loadContent: (args, build) => (0, load_result_cache_1.createCachedLoad)(loadCache, async (args) => {
93
+ const files = globalScripts.find(({ name }) => name === args.path.slice(0, -3))
94
+ ?.files;
95
+ (0, node_assert_1.default)(files, `Invalid operation: global scripts name not found [${args.path}]`);
96
+ // Global scripts are concatenated using magic-string instead of bundled via esbuild.
97
+ const bundleContent = new magic_string_1.Bundle();
98
+ const watchFiles = [];
99
+ for (const filename of files) {
100
+ let fileContent;
101
+ try {
102
+ // Attempt to read as a relative path from the workspace root
103
+ const fullPath = node_path_1.default.join(workspaceRoot, filename);
104
+ fileContent = await (0, promises_1.readFile)(fullPath, 'utf-8');
105
+ watchFiles.push(fullPath);
109
106
  }
110
- // If not found, attempt to resolve as a module specifier
111
- const resolveResult = await build.resolve(filename, {
112
- kind: 'entry-point',
113
- resolveDir: workspaceRoot,
114
- });
115
- if (resolveResult.errors.length) {
116
- // Remove resolution failure notes about marking as external since it doesn't apply
117
- // to global scripts.
118
- resolveResult.errors.forEach((error) => (error.notes = []));
119
- return {
120
- errors: resolveResult.errors,
121
- warnings: resolveResult.warnings,
122
- };
107
+ catch (e) {
108
+ (0, error_1.assertIsError)(e);
109
+ if (e.code !== 'ENOENT') {
110
+ throw e;
111
+ }
112
+ // If not found, attempt to resolve as a module specifier
113
+ const resolveResult = await build.resolve(filename, {
114
+ kind: 'entry-point',
115
+ resolveDir: workspaceRoot,
116
+ });
117
+ if (resolveResult.errors.length) {
118
+ // Remove resolution failure notes about marking as external since it doesn't apply
119
+ // to global scripts.
120
+ resolveResult.errors.forEach((error) => (error.notes = []));
121
+ return {
122
+ errors: resolveResult.errors,
123
+ warnings: resolveResult.warnings,
124
+ };
125
+ }
126
+ watchFiles.push(resolveResult.path);
127
+ fileContent = await (0, promises_1.readFile)(resolveResult.path, 'utf-8');
123
128
  }
124
- watchFiles.push(resolveResult.path);
125
- fileContent = await (0, promises_1.readFile)(resolveResult.path, 'utf-8');
129
+ bundleContent.addSource(new magic_string_1.default(fileContent, { filename }));
126
130
  }
127
- bundleContent.addSource(new magic_string_1.default(fileContent, { filename }));
128
- }
129
- return {
130
- contents: bundleContent.toString(),
131
- loader: 'js',
132
- watchFiles,
133
- };
134
- }).call(build, args),
135
- }),
136
- ],
131
+ return {
132
+ contents: bundleContent.toString(),
133
+ loader: 'js',
134
+ watchFiles,
135
+ };
136
+ }).call(build, args),
137
+ }),
138
+ ],
139
+ };
137
140
  };
138
141
  }
139
142
  exports.createGlobalScriptsBundleOptions = createGlobalScriptsBundleOptions;
@@ -5,7 +5,6 @@
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.io/license
7
7
  */
8
- import type { BuildOptions } from 'esbuild';
9
8
  import { NormalizedApplicationBuildOptions } from '../../builders/application/options';
10
- import { LoadResultCache } from './load-result-cache';
11
- export declare function createGlobalStylesBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], initial: boolean, cache?: LoadResultCache): BuildOptions | undefined;
9
+ import { BundlerOptionsFactory } from './bundler-context';
10
+ export declare function createGlobalStylesBundleOptions(options: NormalizedApplicationBuildOptions, target: string[], initial: boolean): BundlerOptionsFactory | undefined;
@@ -14,7 +14,7 @@ exports.createGlobalStylesBundleOptions = void 0;
14
14
  const node_assert_1 = __importDefault(require("node:assert"));
15
15
  const bundle_options_1 = require("./stylesheets/bundle-options");
16
16
  const virtual_module_plugin_1 = require("./virtual-module-plugin");
17
- function createGlobalStylesBundleOptions(options, target, initial, cache) {
17
+ function createGlobalStylesBundleOptions(options, target, initial) {
18
18
  const { workspaceRoot, optimizationOptions, sourcemapOptions, outputNames, globalStyles, preserveSymlinks, externalDependencies, stylePreprocessorOptions, tailwindConfiguration, } = options;
19
19
  const namespace = 'angular:styles/global';
20
20
  const entryPoints = {};
@@ -29,38 +29,40 @@ function createGlobalStylesBundleOptions(options, target, initial, cache) {
29
29
  if (found === false) {
30
30
  return;
31
31
  }
32
- const buildOptions = (0, bundle_options_1.createStylesheetBundleOptions)({
33
- workspaceRoot,
34
- optimization: !!optimizationOptions.styles.minify,
35
- sourcemap: !!sourcemapOptions.styles,
36
- preserveSymlinks,
37
- target,
38
- externalDependencies,
39
- outputNames: initial
40
- ? outputNames
41
- : {
42
- ...outputNames,
43
- bundles: '[name]',
32
+ return (loadCache) => {
33
+ const buildOptions = (0, bundle_options_1.createStylesheetBundleOptions)({
34
+ workspaceRoot,
35
+ optimization: !!optimizationOptions.styles.minify,
36
+ sourcemap: !!sourcemapOptions.styles,
37
+ preserveSymlinks,
38
+ target,
39
+ externalDependencies,
40
+ outputNames: initial
41
+ ? outputNames
42
+ : {
43
+ ...outputNames,
44
+ bundles: '[name]',
45
+ },
46
+ includePaths: stylePreprocessorOptions?.includePaths,
47
+ tailwindConfiguration,
48
+ publicPath: options.publicPath,
49
+ }, loadCache);
50
+ buildOptions.legalComments = options.extractLicenses ? 'none' : 'eof';
51
+ buildOptions.entryPoints = entryPoints;
52
+ buildOptions.plugins.unshift((0, virtual_module_plugin_1.createVirtualModulePlugin)({
53
+ namespace,
54
+ transformPath: (path) => path.split(';', 2)[1],
55
+ loadContent: (args) => {
56
+ const files = globalStyles.find(({ name }) => name === args.path)?.files;
57
+ (0, node_assert_1.default)(files, `global style name should always be found [${args.path}]`);
58
+ return {
59
+ contents: files.map((file) => `@import '${file.replace(/\\/g, '/')}';`).join('\n'),
60
+ loader: 'css',
61
+ resolveDir: workspaceRoot,
62
+ };
44
63
  },
45
- includePaths: stylePreprocessorOptions?.includePaths,
46
- tailwindConfiguration,
47
- publicPath: options.publicPath,
48
- }, cache);
49
- buildOptions.legalComments = options.extractLicenses ? 'none' : 'eof';
50
- buildOptions.entryPoints = entryPoints;
51
- buildOptions.plugins.unshift((0, virtual_module_plugin_1.createVirtualModulePlugin)({
52
- namespace,
53
- transformPath: (path) => path.split(';', 2)[1],
54
- loadContent: (args) => {
55
- const files = globalStyles.find(({ name }) => name === args.path)?.files;
56
- (0, node_assert_1.default)(files, `global style name should always be found [${args.path}]`);
57
- return {
58
- contents: files.map((file) => `@import '${file.replace(/\\/g, '/')}';`).join('\n'),
59
- loader: 'css',
60
- resolveDir: workspaceRoot,
61
- };
62
- },
63
- }));
64
- return buildOptions;
64
+ }));
65
+ return buildOptions;
66
+ };
65
67
  }
66
68
  exports.createGlobalStylesBundleOptions = createGlobalStylesBundleOptions;
@@ -50,9 +50,10 @@ async function transformWithBabel({ filename, data, ...options }) {
50
50
  // Strip sourcemaps if they should not be used
51
51
  return useInputSourcemap ? data : data.replace(/^\/\/# sourceMappingURL=[^\r\n]*/gm, '');
52
52
  }
53
- // @angular/platform-server/init entry-point has side-effects.
53
+ // `@angular/platform-server/init` and `@angular/common/locales/global` entry-points are side effectful.
54
54
  const safeAngularPackage = /[\\/]node_modules[\\/]@angular[\\/]/.test(filename) &&
55
- !/@angular[\\/]platform-server[\\/]f?esm2022[\\/]init/.test(filename);
55
+ !/@angular[\\/]platform-server[\\/]f?esm2022[\\/]init/.test(filename) &&
56
+ !/@angular[\\/]common[\\/]locales[\\/]global/.test(filename);
56
57
  // Lazy load the linker plugin only when linking is required
57
58
  if (shouldLink) {
58
59
  linkerPluginCreator ??= (await (0, load_esm_1.loadEsmModule)('@angular/compiler-cli/linker/babel')).createEs2015LinkerPlugin;
@@ -23,6 +23,7 @@ export interface JavaScriptTransformerOptions {
23
23
  */
24
24
  export declare class JavaScriptTransformer {
25
25
  #private;
26
+ readonly maxThreads: number;
26
27
  constructor(options: JavaScriptTransformerOptions, maxThreads: number);
27
28
  /**
28
29
  * Performs JavaScript transformations on a file from the filesystem.
@@ -20,16 +20,11 @@ const piscina_1 = __importDefault(require("piscina"));
20
20
  * and advanced optimizations.
21
21
  */
22
22
  class JavaScriptTransformer {
23
+ maxThreads;
23
24
  #workerPool;
24
25
  #commonOptions;
25
26
  constructor(options, maxThreads) {
26
- this.#workerPool = new piscina_1.default({
27
- filename: require.resolve('./javascript-transformer-worker'),
28
- minThreads: 1,
29
- maxThreads,
30
- // Shutdown idle threads after 1 second of inactivity
31
- idleTimeout: 1000,
32
- });
27
+ this.maxThreads = maxThreads;
33
28
  // Extract options to ensure only the named options are serialized and sent to the worker
34
29
  const { sourcemap, thirdPartySourcemaps = false, advancedOptimizations = false, jit = false, } = options;
35
30
  this.#commonOptions = {
@@ -39,6 +34,16 @@ class JavaScriptTransformer {
39
34
  jit,
40
35
  };
41
36
  }
37
+ #ensureWorkerPool() {
38
+ this.#workerPool ??= new piscina_1.default({
39
+ filename: require.resolve('./javascript-transformer-worker'),
40
+ minThreads: 1,
41
+ maxThreads: this.maxThreads,
42
+ // Shutdown idle threads after 1 second of inactivity
43
+ idleTimeout: 1000,
44
+ });
45
+ return this.#workerPool;
46
+ }
42
47
  /**
43
48
  * Performs JavaScript transformations on a file from the filesystem.
44
49
  * If no transformations are required, the data for the original file will be returned.
@@ -49,7 +54,7 @@ class JavaScriptTransformer {
49
54
  transformFile(filename, skipLinker) {
50
55
  // Always send the request to a worker. Files are almost always from node modules which means
51
56
  // they may need linking. The data is also not yet available to perform most transformation checks.
52
- return this.#workerPool.run({
57
+ return this.#ensureWorkerPool().run({
53
58
  filename,
54
59
  skipLinker,
55
60
  ...this.#commonOptions,
@@ -71,7 +76,7 @@ class JavaScriptTransformer {
71
76
  (!!this.#commonOptions.thirdPartySourcemaps || !/[\\/]node_modules[\\/]/.test(filename));
72
77
  return Buffer.from(keepSourcemap ? data : data.replace(/^\/\/# sourceMappingURL=[^\r\n]*/gm, ''), 'utf-8');
73
78
  }
74
- return this.#workerPool.run({
79
+ return this.#ensureWorkerPool().run({
75
80
  filename,
76
81
  data,
77
82
  skipLinker,
@@ -82,10 +87,17 @@ class JavaScriptTransformer {
82
87
  * Stops all active transformation tasks and shuts down all workers.
83
88
  * @returns A void promise that resolves when closing is complete.
84
89
  */
85
- close() {
86
- // Workaround piscina bug where a worker thread will be recreated after destroy to meet the minimum.
87
- this.#workerPool.options.minThreads = 0;
88
- return this.#workerPool.destroy();
90
+ async close() {
91
+ if (this.#workerPool) {
92
+ // Workaround piscina bug where a worker thread will be recreated after destroy to meet the minimum.
93
+ this.#workerPool.options.minThreads = 0;
94
+ try {
95
+ await this.#workerPool.destroy();
96
+ }
97
+ finally {
98
+ this.#workerPool = undefined;
99
+ }
100
+ }
89
101
  }
90
102
  }
91
103
  exports.JavaScriptTransformer = JavaScriptTransformer;
@@ -10,7 +10,7 @@ import { BuildOptions, Metafile, OutputFile, PartialMessage } from 'esbuild';
10
10
  import { BudgetCalculatorResult } from '../../utils/bundle-calculator';
11
11
  import { BuildOutputFile, BuildOutputFileType, InitialFileRecord } from './bundler-context';
12
12
  import { BuildOutputAsset } from './bundler-execution-result';
13
- export declare function logBuildStats(context: BuilderContext, metafile: Metafile, initial: Map<string, InitialFileRecord>, budgetFailures: BudgetCalculatorResult[] | undefined, estimatedTransferSizes?: Map<string, number>): void;
13
+ export declare function logBuildStats(context: BuilderContext, metafile: Metafile, initial: Map<string, InitialFileRecord>, budgetFailures: BudgetCalculatorResult[] | undefined, changedFiles?: Set<string>, estimatedTransferSizes?: Map<string, number>): void;
14
14
  export declare function calculateEstimatedTransferSizes(outputFiles: OutputFile[]): Promise<Map<string, number>>;
15
15
  export declare function withSpinner<T>(text: string, action: () => T | Promise<T>): Promise<T>;
16
16
  export declare function withNoProgress<T>(text: string, action: () => T | Promise<T>): Promise<T>;
@@ -46,8 +46,9 @@ const spinner_1 = require("../../utils/spinner");
46
46
  const stats_1 = require("../webpack/utils/stats");
47
47
  const bundler_context_1 = require("./bundler-context");
48
48
  const compressAsync = (0, node_util_1.promisify)(node_zlib_1.brotliCompress);
49
- function logBuildStats(context, metafile, initial, budgetFailures, estimatedTransferSizes) {
49
+ function logBuildStats(context, metafile, initial, budgetFailures, changedFiles, estimatedTransferSizes) {
50
50
  const stats = [];
51
+ let unchangedCount = 0;
51
52
  for (const [file, output] of Object.entries(metafile.outputs)) {
52
53
  // Only display JavaScript and CSS files
53
54
  if (!file.endsWith('.js') && !file.endsWith('.css')) {
@@ -58,6 +59,11 @@ function logBuildStats(context, metafile, initial, budgetFailures, estimatedTran
58
59
  if (output['ng-component']) {
59
60
  continue;
60
61
  }
62
+ // Show only changed files if a changed list is provided
63
+ if (changedFiles && !changedFiles.has(file)) {
64
+ ++unchangedCount;
65
+ continue;
66
+ }
61
67
  let name = initial.get(file)?.name;
62
68
  if (name === undefined && output.entryPoint) {
63
69
  name = node_path_1.default
@@ -70,8 +76,16 @@ function logBuildStats(context, metafile, initial, budgetFailures, estimatedTran
70
76
  stats: [file, name ?? '-', output.bytes, estimatedTransferSizes?.get(file) ?? '-'],
71
77
  });
72
78
  }
73
- const tableText = (0, stats_1.generateBuildStatsTable)(stats, true, true, !!estimatedTransferSizes, budgetFailures);
74
- context.logger.info('\n' + tableText + '\n');
79
+ if (stats.length > 0) {
80
+ const tableText = (0, stats_1.generateBuildStatsTable)(stats, true, unchangedCount === 0, !!estimatedTransferSizes, budgetFailures);
81
+ context.logger.info('\n' + tableText + '\n');
82
+ }
83
+ else if (changedFiles !== undefined) {
84
+ context.logger.info('\nNo output file changes.\n');
85
+ }
86
+ if (unchangedCount > 0) {
87
+ context.logger.info(`Unchanged output files: ${unchangedCount}`);
88
+ }
75
89
  }
76
90
  exports.logBuildStats = logBuildStats;
77
91
  async function calculateEstimatedTransferSizes(outputFiles) {
@@ -327,7 +341,7 @@ function transformSupportedBrowsersToTargets(supportedBrowsers) {
327
341
  return transformed;
328
342
  }
329
343
  exports.transformSupportedBrowsersToTargets = transformSupportedBrowsersToTargets;
330
- const SUPPORTED_NODE_VERSIONS = '>=18.13.0';
344
+ const SUPPORTED_NODE_VERSIONS = '^18.13.0 || >=20.9.0';
331
345
  /**
332
346
  * Transform supported Node.js versions to esbuild target.
333
347
  * @see https://esbuild.github.io/api/#target
@@ -9,6 +9,7 @@ export declare class ChangedFiles {
9
9
  readonly added: Set<string>;
10
10
  readonly modified: Set<string>;
11
11
  readonly removed: Set<string>;
12
+ get all(): string[];
12
13
  toDebugString(): string;
13
14
  }
14
15
  export interface BuildWatcher extends AsyncIterableIterator<ChangedFiles> {
@@ -13,6 +13,9 @@ class ChangedFiles {
13
13
  added = new Set();
14
14
  modified = new Set();
15
15
  removed = new Set();
16
+ get all() {
17
+ return [...this.added, ...this.modified, ...this.removed];
18
+ }
16
19
  toDebugString() {
17
20
  const content = {
18
21
  added: Array.from(this.added),
@@ -32,6 +32,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
32
32
  Object.defineProperty(exports, "__esModule", { value: true });
33
33
  exports.checkPort = void 0;
34
34
  const net = __importStar(require("net"));
35
+ const load_esm_1 = require("./load-esm");
35
36
  const tty_1 = require("./tty");
36
37
  function createInUseError(port) {
37
38
  return new Error(`Port ${port} is already in use. Use '--port' to specify a different port.`);
@@ -52,7 +53,8 @@ async function checkPort(port, host) {
52
53
  reject(createInUseError(port));
53
54
  return;
54
55
  }
55
- Promise.resolve().then(() => __importStar(require('inquirer'))).then(({ prompt }) => prompt({
56
+ (0, load_esm_1.loadEsmModule)('inquirer')
57
+ .then(({ default: { prompt } }) => prompt({
56
58
  type: 'confirm',
57
59
  name: 'useDifferent',
58
60
  message: `Port ${port} is already in use.\nWould you like to use a different port?`,
@@ -12,3 +12,4 @@ export declare const maxWorkers: number;
12
12
  export declare const useParallelTs: boolean;
13
13
  export declare const useLegacySass: boolean;
14
14
  export declare const debugPerformance: boolean;
15
+ export declare const shouldWatchRoot: boolean;
@@ -7,7 +7,7 @@
7
7
  * found in the LICENSE file at https://angular.io/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.debugPerformance = exports.useLegacySass = exports.useParallelTs = exports.maxWorkers = exports.allowMinify = exports.shouldBeautify = exports.allowMangle = void 0;
10
+ exports.shouldWatchRoot = exports.debugPerformance = exports.useLegacySass = exports.useParallelTs = exports.maxWorkers = exports.allowMinify = exports.shouldBeautify = exports.allowMangle = void 0;
11
11
  const color_1 = require("./color");
12
12
  function isDisabled(variable) {
13
13
  return variable === '0' || variable.toLowerCase() === 'false';
@@ -81,3 +81,5 @@ exports.useLegacySass = (() => {
81
81
  })();
82
82
  const debugPerfVariable = process.env['NG_BUILD_DEBUG_PERF'];
83
83
  exports.debugPerformance = isPresent(debugPerfVariable) && isEnabled(debugPerfVariable);
84
+ const watchRootVariable = process.env['NG_BUILD_WATCH_ROOT'];
85
+ exports.shouldWatchRoot = isPresent(watchRootVariable) && isEnabled(watchRootVariable);
@@ -5,8 +5,6 @@
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.io/license
7
7
  */
8
- /// <reference types="node" />
9
- import { URL } from 'url';
10
8
  /**
11
9
  * This uses a dynamic import to load a module which may be ESM.
12
10
  * CommonJS code can load ESM code via a dynamic import. Unfortunately, TypeScript
@@ -11,5 +11,5 @@ interface RouterResult {
11
11
  success: boolean;
12
12
  redirect: boolean;
13
13
  }
14
- export declare function extractRoutes(bootstrapAppFnOrModule: (() => Promise<ApplicationRef>) | Type<unknown>, document: string, url: string): AsyncIterableIterator<RouterResult>;
14
+ export declare function extractRoutes(bootstrapAppFnOrModule: (() => Promise<ApplicationRef>) | Type<unknown>, document: string): AsyncIterableIterator<RouterResult>;
15
15
  export {};
@@ -38,11 +38,11 @@ async function* getRoutesFromRouterConfig(routes, compiler, parentInjector, pare
38
38
  }
39
39
  }
40
40
  }
41
- export async function* extractRoutes(bootstrapAppFnOrModule, document, url) {
41
+ export async function* extractRoutes(bootstrapAppFnOrModule, document) {
42
42
  const platformRef = createPlatformFactory(platformCore, 'server', [
43
43
  {
44
44
  provide: INITIAL_CONFIG,
45
- useValue: { document, url },
45
+ useValue: { document, url: '' },
46
46
  },
47
47
  {
48
48
  provide: ɵConsole,
@@ -47,7 +47,9 @@ function resolve(specifier, context, nextResolve) {
47
47
  }
48
48
  exports.resolve = resolve;
49
49
  async function load(url, context, nextLoad) {
50
- if (isFileProtocol(url)) {
50
+ const { format } = context;
51
+ // CommonJs modules require no transformations and are not in memory.
52
+ if (format !== 'commonjs' && isFileProtocol(url)) {
51
53
  const filePath = (0, url_1.fileURLToPath)(url);
52
54
  // Remove '/' or drive letter for Windows that was added in the above 'resolve'.
53
55
  let source = outputFiles[(0, node_path_1.relative)('/', filePath)] ?? TRANSFORMED_FILES[filePath];
@@ -55,7 +57,6 @@ async function load(url, context, nextLoad) {
55
57
  source = TRANSFORMED_FILES[filePath] = Buffer.from(await javascriptTransformer.transformFile(filePath)).toString('utf-8');
56
58
  }
57
59
  if (source !== undefined) {
58
- const { format } = context;
59
60
  return {
60
61
  format,
61
62
  shortCircuit: true,
@@ -0,0 +1,8 @@
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.io/license
7
+ */
8
+ export declare function patchFetchToLoadInMemoryAssets(): void;