@angular/build 18.1.0-rc.0 → 18.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 (40) hide show
  1. package/package.json +11 -9
  2. package/src/builders/application/chunk-optimizer.d.ts +9 -0
  3. package/src/builders/application/chunk-optimizer.js +169 -0
  4. package/src/builders/application/execute-build.js +9 -3
  5. package/src/builders/application/execute-post-bundle.js +4 -4
  6. package/src/builders/dev-server/vite-server.js +0 -1
  7. package/src/tools/angular/compilation/aot-compilation.js +3 -1
  8. package/src/tools/angular/compilation/parallel-worker.d.ts +1 -0
  9. package/src/tools/angular/compilation/parallel-worker.js +2 -1
  10. package/src/tools/esbuild/angular/compiler-plugin.js +3 -1
  11. package/src/tools/esbuild/application-code-bundle.js +7 -2
  12. package/src/tools/esbuild/budget-stats.d.ts +2 -2
  13. package/src/tools/esbuild/budget-stats.js +19 -14
  14. package/src/tools/esbuild/bundler-context.d.ts +1 -0
  15. package/src/tools/esbuild/bundler-execution-result.d.ts +1 -1
  16. package/src/tools/esbuild/bundler-execution-result.js +1 -1
  17. package/src/tools/esbuild/i18n-inliner.js +2 -2
  18. package/src/tools/esbuild/javascript-transformer-worker.js +3 -1
  19. package/src/tools/esbuild/utils.d.ts +4 -3
  20. package/src/tools/esbuild/utils.js +97 -56
  21. package/src/tools/esbuild/wasm-plugin.d.ts +28 -0
  22. package/src/tools/esbuild/wasm-plugin.js +210 -0
  23. package/src/tools/esbuild/wasm.d.ts +25 -0
  24. package/src/tools/vite/angular-memory-plugin.d.ts +2 -5
  25. package/src/tools/vite/angular-memory-plugin.js +7 -161
  26. package/src/tools/vite/middlewares/assets-middleware.d.ts +10 -0
  27. package/src/tools/vite/middlewares/assets-middleware.js +94 -0
  28. package/src/tools/vite/middlewares/html-fallback-middleware.d.ts +10 -0
  29. package/src/tools/vite/middlewares/html-fallback-middleware.js +24 -0
  30. package/src/tools/vite/middlewares/index-html-middleware.d.ts +10 -0
  31. package/src/tools/vite/middlewares/index-html-middleware.js +43 -0
  32. package/src/tools/vite/middlewares/index.d.ts +11 -0
  33. package/src/tools/vite/middlewares/index.js +18 -0
  34. package/src/tools/vite/middlewares/ssr-middleware.d.ts +12 -0
  35. package/src/tools/vite/middlewares/ssr-middleware.js +57 -0
  36. package/src/tools/vite/utils.d.ts +16 -0
  37. package/src/tools/vite/utils.js +40 -0
  38. package/src/utils/environment-options.d.ts +1 -0
  39. package/src/utils/environment-options.js +4 -2
  40. package/src/utils/normalize-cache.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/build",
3
- "version": "18.1.0-rc.0",
3
+ "version": "18.1.0",
4
4
  "description": "Official build system for Angular",
5
5
  "keywords": [
6
6
  "Angular CLI",
@@ -23,18 +23,19 @@
23
23
  "builders": "builders.json",
24
24
  "dependencies": {
25
25
  "@ampproject/remapping": "2.3.0",
26
- "@angular-devkit/architect": "0.1801.0-rc.0",
26
+ "@angular-devkit/architect": "0.1801.0",
27
27
  "@babel/core": "7.24.7",
28
28
  "@babel/helper-annotate-as-pure": "7.24.7",
29
29
  "@babel/helper-split-export-declaration": "7.24.7",
30
- "@inquirer/confirm": "3.1.10",
30
+ "@babel/plugin-syntax-import-attributes": "7.24.7",
31
+ "@inquirer/confirm": "3.1.11",
31
32
  "@vitejs/plugin-basic-ssl": "1.1.0",
32
33
  "ansi-colors": "4.1.3",
33
34
  "browserslist": "^4.23.0",
34
35
  "critters": "0.0.24",
35
36
  "esbuild": "0.21.5",
36
37
  "fast-glob": "3.3.2",
37
- "https-proxy-agent": "7.0.4",
38
+ "https-proxy-agent": "7.0.5",
38
39
  "lmdb": "3.0.12",
39
40
  "magic-string": "0.30.10",
40
41
  "mrmime": "2.0.0",
@@ -42,17 +43,18 @@
42
43
  "parse5-html-rewriting-stream": "7.0.0",
43
44
  "picomatch": "4.0.2",
44
45
  "piscina": "4.6.1",
46
+ "rollup": "4.18.0",
45
47
  "sass": "1.77.6",
46
48
  "semver": "7.6.2",
47
49
  "undici": "6.19.2",
48
- "vite": "5.3.1",
50
+ "vite": "5.3.2",
49
51
  "watchpack": "2.4.1"
50
52
  },
51
53
  "peerDependencies": {
52
- "@angular/compiler-cli": "^18.0.0 || ^18.1.0-next.0",
53
- "@angular/localize": "^18.0.0 || ^18.1.0-next.0",
54
- "@angular/platform-server": "^18.0.0 || ^18.1.0-next.0",
55
- "@angular/service-worker": "^18.0.0 || ^18.1.0-next.0",
54
+ "@angular/compiler-cli": "^18.0.0",
55
+ "@angular/localize": "^18.0.0",
56
+ "@angular/platform-server": "^18.0.0",
57
+ "@angular/service-worker": "^18.0.0",
56
58
  "less": "^4.2.0",
57
59
  "postcss": "^8.4.0",
58
60
  "tailwindcss": "^2.0.0 || ^3.0.0",
@@ -0,0 +1,9 @@
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 { BundleContextResult } from '../../tools/esbuild/bundler-context';
9
+ export declare function optimizeChunks(original: BundleContextResult, sourcemap: boolean | 'hidden'): Promise<BundleContextResult>;
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google LLC All Rights Reserved.
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://angular.dev/license
8
+ */
9
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.optimizeChunks = optimizeChunks;
14
+ const node_assert_1 = __importDefault(require("node:assert"));
15
+ const rollup_1 = require("rollup");
16
+ const bundler_context_1 = require("../../tools/esbuild/bundler-context");
17
+ const utils_1 = require("../../tools/esbuild/utils");
18
+ const error_1 = require("../../utils/error");
19
+ async function optimizeChunks(original, sourcemap) {
20
+ // Failed builds cannot be optimized
21
+ if (original.errors) {
22
+ return original;
23
+ }
24
+ // Find the main browser entrypoint
25
+ let mainFile;
26
+ for (const [file, record] of original.initialFiles) {
27
+ if (record.name === 'main' &&
28
+ record.entrypoint &&
29
+ !record.serverFile &&
30
+ record.type === 'script') {
31
+ mainFile = file;
32
+ break;
33
+ }
34
+ }
35
+ // No action required if no browser main entrypoint
36
+ if (!mainFile) {
37
+ return original;
38
+ }
39
+ const chunks = {};
40
+ const maps = {};
41
+ for (const originalFile of original.outputFiles) {
42
+ if (originalFile.type !== bundler_context_1.BuildOutputFileType.Browser) {
43
+ continue;
44
+ }
45
+ if (originalFile.path.endsWith('.js')) {
46
+ chunks[originalFile.path] = originalFile;
47
+ }
48
+ else if (originalFile.path.endsWith('.js.map')) {
49
+ // Create mapping of JS file to sourcemap content
50
+ maps[originalFile.path.slice(0, -4)] = originalFile;
51
+ }
52
+ }
53
+ const usedChunks = new Set();
54
+ let bundle;
55
+ let optimizedOutput;
56
+ try {
57
+ bundle = await (0, rollup_1.rollup)({
58
+ input: mainFile,
59
+ plugins: [
60
+ {
61
+ name: 'angular-bundle',
62
+ resolveId(source) {
63
+ // Remove leading `./` if present
64
+ const file = source[0] === '.' && source[1] === '/' ? source.slice(2) : source;
65
+ if (chunks[file]) {
66
+ return file;
67
+ }
68
+ // All other identifiers are considered external to maintain behavior
69
+ return { id: source, external: true };
70
+ },
71
+ load(id) {
72
+ (0, node_assert_1.default)(chunks[id], `Angular chunk content should always be present in chunk optimizer [${id}].`);
73
+ usedChunks.add(id);
74
+ const result = {
75
+ code: chunks[id].text,
76
+ map: maps[id]?.text,
77
+ };
78
+ return result;
79
+ },
80
+ },
81
+ ],
82
+ });
83
+ const result = await bundle.generate({
84
+ compact: true,
85
+ sourcemap,
86
+ chunkFileNames(chunkInfo) {
87
+ // Do not add hash to file name if already present
88
+ return /-[a-zA-Z0-9]{8}$/.test(chunkInfo.name) ? '[name].js' : '[name]-[hash].js';
89
+ },
90
+ });
91
+ optimizedOutput = result.output;
92
+ }
93
+ catch (e) {
94
+ (0, error_1.assertIsError)(e);
95
+ return {
96
+ errors: [
97
+ // Most of these fields are not actually needed for printing the error
98
+ {
99
+ id: '',
100
+ text: 'Chunk optimization failed',
101
+ detail: undefined,
102
+ pluginName: '',
103
+ location: null,
104
+ notes: [
105
+ {
106
+ text: e.message,
107
+ location: null,
108
+ },
109
+ ],
110
+ },
111
+ ],
112
+ warnings: original.warnings,
113
+ };
114
+ }
115
+ finally {
116
+ await bundle?.close();
117
+ }
118
+ // Remove used chunks and associated sourcemaps from the original result
119
+ original.outputFiles = original.outputFiles.filter((file) => !usedChunks.has(file.path) &&
120
+ !(file.path.endsWith('.map') && usedChunks.has(file.path.slice(0, -4))));
121
+ // Add new optimized chunks
122
+ const importsPerFile = {};
123
+ for (const optimizedFile of optimizedOutput) {
124
+ if (optimizedFile.type !== 'chunk') {
125
+ continue;
126
+ }
127
+ importsPerFile[optimizedFile.fileName] = optimizedFile.imports;
128
+ original.outputFiles.push((0, utils_1.createOutputFile)(optimizedFile.fileName, optimizedFile.code, bundler_context_1.BuildOutputFileType.Browser));
129
+ if (optimizedFile.map && optimizedFile.sourcemapFileName) {
130
+ original.outputFiles.push((0, utils_1.createOutputFile)(optimizedFile.sourcemapFileName, optimizedFile.map.toString(), bundler_context_1.BuildOutputFileType.Browser));
131
+ }
132
+ }
133
+ // Update initial files to reflect optimized chunks
134
+ const entriesToAnalyze = [];
135
+ for (const usedFile of usedChunks) {
136
+ // Leave the main file since its information did not change
137
+ if (usedFile === mainFile) {
138
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
139
+ entriesToAnalyze.push([mainFile, original.initialFiles.get(mainFile)]);
140
+ continue;
141
+ }
142
+ // Remove all other used chunks
143
+ original.initialFiles.delete(usedFile);
144
+ }
145
+ // Analyze for transitive initial files
146
+ let currentEntry;
147
+ while ((currentEntry = entriesToAnalyze.pop())) {
148
+ const [entryPath, entryRecord] = currentEntry;
149
+ for (const importPath of importsPerFile[entryPath]) {
150
+ const existingRecord = original.initialFiles.get(importPath);
151
+ if (existingRecord) {
152
+ // Store the smallest value depth
153
+ if (existingRecord.depth > entryRecord.depth + 1) {
154
+ existingRecord.depth = entryRecord.depth + 1;
155
+ }
156
+ continue;
157
+ }
158
+ const record = {
159
+ type: 'script',
160
+ entrypoint: false,
161
+ external: false,
162
+ serverFile: false,
163
+ depth: entryRecord.depth + 1,
164
+ };
165
+ entriesToAnalyze.push([importPath, record]);
166
+ }
167
+ }
168
+ return original;
169
+ }
@@ -14,10 +14,13 @@ const bundler_context_1 = require("../../tools/esbuild/bundler-context");
14
14
  const bundler_execution_result_1 = require("../../tools/esbuild/bundler-execution-result");
15
15
  const commonjs_checker_1 = require("../../tools/esbuild/commonjs-checker");
16
16
  const license_extractor_1 = require("../../tools/esbuild/license-extractor");
17
+ const profiling_1 = require("../../tools/esbuild/profiling");
17
18
  const utils_1 = require("../../tools/esbuild/utils");
18
19
  const bundle_calculator_1 = require("../../utils/bundle-calculator");
20
+ const environment_options_1 = require("../../utils/environment-options");
19
21
  const resolve_assets_1 = require("../../utils/resolve-assets");
20
22
  const supported_browsers_1 = require("../../utils/supported-browsers");
23
+ const chunk_optimizer_1 = require("./chunk-optimizer");
21
24
  const execute_post_bundle_1 = require("./execute-post-bundle");
22
25
  const i18n_1 = require("./i18n");
23
26
  const setup_bundling_1 = require("./setup-bundling");
@@ -37,7 +40,10 @@ async function executeBuild(options, context, rebuildState) {
37
40
  if (bundlerContexts === undefined) {
38
41
  bundlerContexts = (0, setup_bundling_1.setupBundlerContexts)(options, browsers, codeBundleCache);
39
42
  }
40
- const bundlingResult = await bundler_context_1.BundlerContext.bundleAll(bundlerContexts, rebuildState?.fileChanges.all);
43
+ let bundlingResult = await bundler_context_1.BundlerContext.bundleAll(bundlerContexts, rebuildState?.fileChanges.all);
44
+ if (options.optimizationOptions.scripts && environment_options_1.shouldOptimizeChunks) {
45
+ bundlingResult = await (0, profiling_1.profileAsync)('OPTIMIZE_CHUNKS', () => (0, chunk_optimizer_1.optimizeChunks)(bundlingResult, options.sourcemapOptions.scripts ? !options.sourcemapOptions.hidden || 'hidden' : false));
46
+ }
41
47
  const executionResult = new bundler_execution_result_1.ExecutionResult(bundlerContexts, codeBundleCache);
42
48
  executionResult.addWarnings(bundlingResult.warnings);
43
49
  // Return if the bundling has errors
@@ -63,7 +69,7 @@ async function executeBuild(options, context, rebuildState) {
63
69
  // Analyze files for bundle budget failures if present
64
70
  let budgetFailures;
65
71
  if (options.budgets) {
66
- const compatStats = (0, budget_stats_1.generateBudgetStats)(metafile, initialFiles);
72
+ const compatStats = (0, budget_stats_1.generateBudgetStats)(metafile, outputFiles, initialFiles);
67
73
  budgetFailures = [...(0, bundle_calculator_1.checkBudgets)(options.budgets, compatStats, true)];
68
74
  for (const { message, severity } of budgetFailures) {
69
75
  if (severity === 'error') {
@@ -122,7 +128,7 @@ async function executeBuild(options, context, rebuildState) {
122
128
  executionResult.addOutputFile('stats.json', JSON.stringify(metafile, null, 2), bundler_context_1.BuildOutputFileType.Root);
123
129
  }
124
130
  if (!jsonLogs) {
125
- executionResult.addLog((0, utils_1.logBuildStats)(metafile, initialFiles, budgetFailures, colors, changedFiles, estimatedTransferSizes, !!ssrOptions, verbose));
131
+ executionResult.addLog((0, utils_1.logBuildStats)(metafile, outputFiles, initialFiles, budgetFailures, colors, changedFiles, estimatedTransferSizes, !!ssrOptions, verbose));
126
132
  }
127
133
  return executionResult;
128
134
  }
@@ -48,10 +48,10 @@ async function executePostBundleSteps(options, outputFiles, assetFiles, initialF
48
48
  const { csrContent, ssrContent, errors, warnings } = await (0, index_html_generator_1.generateIndexHtml)(initialFiles, outputFiles, options, locale);
49
49
  allErrors.push(...errors);
50
50
  allWarnings.push(...warnings);
51
- additionalHtmlOutputFiles.set(indexHtmlOptions.output, (0, utils_1.createOutputFileFromText)(indexHtmlOptions.output, csrContent, bundler_context_1.BuildOutputFileType.Browser));
51
+ additionalHtmlOutputFiles.set(indexHtmlOptions.output, (0, utils_1.createOutputFile)(indexHtmlOptions.output, csrContent, bundler_context_1.BuildOutputFileType.Browser));
52
52
  if (ssrContent) {
53
53
  const serverIndexHtmlFilename = 'index.server.html';
54
- additionalHtmlOutputFiles.set(serverIndexHtmlFilename, (0, utils_1.createOutputFileFromText)(serverIndexHtmlFilename, ssrContent, bundler_context_1.BuildOutputFileType.Server));
54
+ additionalHtmlOutputFiles.set(serverIndexHtmlFilename, (0, utils_1.createOutputFile)(serverIndexHtmlFilename, ssrContent, bundler_context_1.BuildOutputFileType.Server));
55
55
  ssrIndexContent = ssrContent;
56
56
  }
57
57
  }
@@ -64,7 +64,7 @@ async function executePostBundleSteps(options, outputFiles, assetFiles, initialF
64
64
  allWarnings.push(...warnings);
65
65
  prerenderedRoutes.push(...Array.from(generatedRoutes));
66
66
  for (const [path, content] of Object.entries(output)) {
67
- additionalHtmlOutputFiles.set(path, (0, utils_1.createOutputFileFromText)(path, content, bundler_context_1.BuildOutputFileType.Browser));
67
+ additionalHtmlOutputFiles.set(path, (0, utils_1.createOutputFile)(path, content, bundler_context_1.BuildOutputFileType.Browser));
68
68
  }
69
69
  }
70
70
  additionalOutputFiles.push(...additionalHtmlOutputFiles.values());
@@ -75,7 +75,7 @@ async function executePostBundleSteps(options, outputFiles, assetFiles, initialF
75
75
  const serviceWorkerResult = await (0, service_worker_1.augmentAppWithServiceWorkerEsbuild)(workspaceRoot, serviceWorker, options.baseHref || '/', options.indexHtmlOptions?.output,
76
76
  // Ensure additional files recently added are used
77
77
  [...outputFiles, ...additionalOutputFiles], assetFiles);
78
- additionalOutputFiles.push((0, utils_1.createOutputFileFromText)('ngsw.json', serviceWorkerResult.manifest, bundler_context_1.BuildOutputFileType.Browser));
78
+ additionalOutputFiles.push((0, utils_1.createOutputFile)('ngsw.json', serviceWorkerResult.manifest, bundler_context_1.BuildOutputFileType.Browser));
79
79
  additionalAssets.push(...serviceWorkerResult.assetFiles);
80
80
  }
81
81
  catch (error) {
@@ -436,7 +436,6 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
436
436
  outputFiles,
437
437
  assets,
438
438
  ssr,
439
- extraHeaders: serverOptions.headers,
440
439
  external: externalMetadata.explicit,
441
440
  indexHtmlTransformer,
442
441
  extensionMiddleware,
@@ -136,7 +136,9 @@ class AotCompilation extends angular_compilation_1.AngularCompilation {
136
136
  const { affectedFiles, angularCompiler, compilerHost, typeScriptProgram, webWorkerTransform } = this.#state;
137
137
  const compilerOptions = typeScriptProgram.getCompilerOptions();
138
138
  const buildInfoFilename = compilerOptions.tsBuildInfoFile ?? '.tsbuildinfo';
139
- const useTypeScriptTranspilation = !compilerOptions.isolatedModules || !!compilerOptions.sourceMap;
139
+ const useTypeScriptTranspilation = !compilerOptions.isolatedModules ||
140
+ !!compilerOptions.sourceMap ||
141
+ !!compilerOptions.inlineSourceMap;
140
142
  const emittedFiles = new Map();
141
143
  const writeFileCallback = (filename, contents, _a, _b, sourceFiles) => {
142
144
  if (!sourceFiles?.length && filename.endsWith(buildInfoFilename)) {
@@ -24,6 +24,7 @@ export declare function initialize(request: InitRequest): Promise<{
24
24
  allowJs: boolean | undefined;
25
25
  isolatedModules: boolean | undefined;
26
26
  sourceMap: boolean | undefined;
27
+ inlineSourceMap: boolean | undefined;
27
28
  };
28
29
  }>;
29
30
  export declare function diagnose(modes: DiagnosticModes): Promise<{
@@ -70,11 +70,12 @@ async function initialize(request) {
70
70
  });
71
71
  return {
72
72
  referencedFiles,
73
- // TODO: Expand? `allowJs`, `isolatedModules`, `sourceMap` are the only fields needed currently.
73
+ // TODO: Expand? `allowJs`, `isolatedModules`, `sourceMap`, `inlineSourceMap` are the only fields needed currently.
74
74
  compilerOptions: {
75
75
  allowJs: compilerOptions.allowJs,
76
76
  isolatedModules: compilerOptions.isolatedModules,
77
77
  sourceMap: compilerOptions.sourceMap,
78
+ inlineSourceMap: compilerOptions.inlineSourceMap,
78
79
  },
79
80
  };
80
81
  }
@@ -206,7 +206,8 @@ function createCompilerPlugin(pluginOptions, styleOptions) {
206
206
  // Typescript printing support for sourcemaps is not yet integrated.
207
207
  useTypeScriptTranspilation =
208
208
  !initializationResult.compilerOptions.isolatedModules ||
209
- !!initializationResult.compilerOptions.sourceMap;
209
+ !!initializationResult.compilerOptions.sourceMap ||
210
+ !!initializationResult.compilerOptions.inlineSourceMap;
210
211
  referencedFiles = initializationResult.referencedFiles;
211
212
  }
212
213
  catch (error) {
@@ -425,6 +426,7 @@ function createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserve
425
426
  noEmitOnError: false,
426
427
  inlineSources: !!pluginOptions.sourcemap,
427
428
  inlineSourceMap: !!pluginOptions.sourcemap,
429
+ sourceMap: undefined,
428
430
  mapRoot: undefined,
429
431
  sourceRoot: undefined,
430
432
  preserveSymlinks,
@@ -27,9 +27,11 @@ const rxjs_esm_resolution_plugin_1 = require("./rxjs-esm-resolution-plugin");
27
27
  const sourcemap_ignorelist_plugin_1 = require("./sourcemap-ignorelist-plugin");
28
28
  const utils_1 = require("./utils");
29
29
  const virtual_module_plugin_1 = require("./virtual-module-plugin");
30
+ const wasm_plugin_1 = require("./wasm-plugin");
30
31
  function createBrowserCodeBundleOptions(options, target, sourceFileCache) {
31
32
  const { entryPoints, outputNames, polyfills } = options;
32
33
  const { pluginOptions, styleOptions } = (0, compiler_plugin_options_1.createCompilerPluginOptions)(options, target, sourceFileCache);
34
+ const zoneless = (0, utils_1.isZonelessApp)(polyfills);
33
35
  const buildOptions = {
34
36
  ...getEsBuildCommonOptions(options),
35
37
  platform: 'browser',
@@ -41,8 +43,9 @@ function createBrowserCodeBundleOptions(options, target, sourceFileCache) {
41
43
  entryNames: outputNames.bundles,
42
44
  entryPoints,
43
45
  target,
44
- supported: (0, utils_1.getFeatureSupport)(target, (0, utils_1.isZonelessApp)(polyfills)),
46
+ supported: (0, utils_1.getFeatureSupport)(target, zoneless),
45
47
  plugins: [
48
+ (0, wasm_plugin_1.createWasmPlugin)({ allowAsync: zoneless, cache: sourceFileCache?.loadResultCache }),
46
49
  (0, sourcemap_ignorelist_plugin_1.createSourcemapIgnorelistPlugin)(),
47
50
  (0, compiler_plugin_1.createCompilerPlugin)(
48
51
  // JS/TS options
@@ -124,6 +127,7 @@ function createServerCodeBundleOptions(options, target, sourceFileCache) {
124
127
  if (ssrEntryPoint) {
125
128
  entryPoints['server'] = ssrEntryPoint;
126
129
  }
130
+ const zoneless = (0, utils_1.isZonelessApp)(polyfills);
127
131
  const buildOptions = {
128
132
  ...getEsBuildCommonOptions(options),
129
133
  platform: 'node',
@@ -140,8 +144,9 @@ function createServerCodeBundleOptions(options, target, sourceFileCache) {
140
144
  js: `import './polyfills.server.mjs';`,
141
145
  },
142
146
  entryPoints,
143
- supported: (0, utils_1.getFeatureSupport)(target, (0, utils_1.isZonelessApp)(polyfills)),
147
+ supported: (0, utils_1.getFeatureSupport)(target, zoneless),
144
148
  plugins: [
149
+ (0, wasm_plugin_1.createWasmPlugin)({ allowAsync: zoneless, cache: sourceFileCache?.loadResultCache }),
145
150
  (0, sourcemap_ignorelist_plugin_1.createSourcemapIgnorelistPlugin)(),
146
151
  (0, compiler_plugin_1.createCompilerPlugin)(
147
152
  // JS/TS options
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import type { Metafile } from 'esbuild';
9
9
  import type { BudgetStats } from '../../utils/bundle-calculator';
10
- import type { InitialFileRecord } from './bundler-context';
10
+ import { type BuildOutputFile, type InitialFileRecord } from './bundler-context';
11
11
  /**
12
12
  * Generates a bundle budget calculator compatible stats object that provides
13
13
  * the necessary information for the Webpack-based bundle budget code to
@@ -16,4 +16,4 @@ import type { InitialFileRecord } from './bundler-context';
16
16
  * @param initialFiles The records of all initial files of a build.
17
17
  * @returns A bundle budget compatible stats object.
18
18
  */
19
- export declare function generateBudgetStats(metafile: Metafile, initialFiles: Map<string, InitialFileRecord>): BudgetStats;
19
+ export declare function generateBudgetStats(metafile: Metafile, outputFiles: BuildOutputFile[], initialFiles: Map<string, InitialFileRecord>): BudgetStats;
@@ -8,7 +8,8 @@
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.generateBudgetStats = generateBudgetStats;
11
- const node_path_1 = require("node:path");
11
+ const bundler_context_1 = require("./bundler-context");
12
+ const utils_1 = require("./utils");
12
13
  /**
13
14
  * Generates a bundle budget calculator compatible stats object that provides
14
15
  * the necessary information for the Webpack-based bundle budget code to
@@ -17,39 +18,43 @@ const node_path_1 = require("node:path");
17
18
  * @param initialFiles The records of all initial files of a build.
18
19
  * @returns A bundle budget compatible stats object.
19
20
  */
20
- function generateBudgetStats(metafile, initialFiles) {
21
+ function generateBudgetStats(metafile, outputFiles, initialFiles) {
21
22
  const stats = {
22
23
  chunks: [],
23
24
  assets: [],
24
25
  };
25
- for (const [file, entry] of Object.entries(metafile.outputs)) {
26
+ for (const { path: file, size, type } of outputFiles) {
26
27
  if (!file.endsWith('.js') && !file.endsWith('.css')) {
27
28
  continue;
28
29
  }
29
30
  // Exclude server bundles
30
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
- if (entry['ng-platform-server']) {
31
+ if (type === bundler_context_1.BuildOutputFileType.Server) {
32
32
  continue;
33
33
  }
34
34
  const initialRecord = initialFiles.get(file);
35
- let name = initialRecord?.name;
36
- if (name === undefined && entry.entryPoint) {
37
- // For non-initial lazy modules, convert the entry point file into a Webpack compatible name
38
- name = (0, node_path_1.basename)(entry.entryPoint)
39
- .replace(/\.[cm]?[jt]s$/, '')
40
- .replace(/[\\/.]/g, '-');
41
- }
35
+ const name = initialRecord?.name ?? (0, utils_1.getChunkNameFromMetafile)(metafile, file);
42
36
  stats.chunks.push({
43
37
  files: [file],
44
38
  initial: !!initialRecord,
45
39
  names: name ? [name] : undefined,
46
40
  });
41
+ stats.assets.push({
42
+ name: file,
43
+ size,
44
+ });
45
+ }
46
+ // Add component styles from metafile
47
+ // TODO: Provide this information directly from the AOT compiler
48
+ for (const entry of Object.values(metafile.outputs)) {
47
49
  // 'ng-component' is set by the angular plugin's component stylesheet bundler
48
50
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
51
  const componentStyle = entry['ng-component'];
52
+ if (!componentStyle) {
53
+ continue;
54
+ }
50
55
  stats.assets.push({
51
- // Component styles use the input file while all other outputs use the result file
52
- name: (componentStyle && Object.keys(entry.inputs)[0]) || file,
56
+ // Component styles use the input file
57
+ name: Object.keys(entry.inputs)[0],
53
58
  size: entry.bytes,
54
59
  componentStyle,
55
60
  });
@@ -38,6 +38,7 @@ export declare enum BuildOutputFileType {
38
38
  }
39
39
  export interface BuildOutputFile extends OutputFile {
40
40
  type: BuildOutputFileType;
41
+ readonly size: number;
41
42
  clone: () => BuildOutputFile;
42
43
  }
43
44
  export type BundlerOptionsFactory<T extends BuildOptions = BuildOptions> = (loadCache: LoadResultCache | undefined) => T;
@@ -39,7 +39,7 @@ export declare class ExecutionResult {
39
39
  externalMetadata?: ExternalResultMetadata;
40
40
  extraWatchFiles: string[];
41
41
  constructor(rebuildContexts: BundlerContext[], codeBundleCache?: SourceFileCache | undefined);
42
- addOutputFile(path: string, content: string, type: BuildOutputFileType): void;
42
+ addOutputFile(path: string, content: string | Uint8Array, type: BuildOutputFileType): void;
43
43
  addAssets(assets: BuildOutputAsset[]): void;
44
44
  addLog(value: string): void;
45
45
  addError(error: PartialMessage | string): void;
@@ -29,7 +29,7 @@ class ExecutionResult {
29
29
  this.codeBundleCache = codeBundleCache;
30
30
  }
31
31
  addOutputFile(path, content, type) {
32
- this.outputFiles.push((0, utils_1.createOutputFileFromText)(path, content, type));
32
+ this.outputFiles.push((0, utils_1.createOutputFile)(path, content, type));
33
33
  }
34
34
  addAssets(assets) {
35
35
  this.assetFiles.push(...assets);
@@ -117,9 +117,9 @@ class I18nInliner {
117
117
  ...rawResults.flatMap(({ file, code, map, messages }) => {
118
118
  const type = this.#fileToType.get(file);
119
119
  (0, node_assert_1.default)(type !== undefined, 'localized file should always have a type' + file);
120
- const resultFiles = [(0, utils_1.createOutputFileFromText)(file, code, type)];
120
+ const resultFiles = [(0, utils_1.createOutputFile)(file, code, type)];
121
121
  if (map) {
122
- resultFiles.push((0, utils_1.createOutputFileFromText)(file + '.map', map, type));
122
+ resultFiles.push((0, utils_1.createOutputFile)(file + '.map', map, type));
123
123
  }
124
124
  for (const message of messages) {
125
125
  if (message.type === 'error') {
@@ -60,7 +60,9 @@ async function transformWithBabel(filename, data, options) {
60
60
  const shouldLink = !options.skipLinker && (await requiresLinking(filename, data));
61
61
  const useInputSourcemap = options.sourcemap &&
62
62
  (!!options.thirdPartySourcemaps || !/[\\/]node_modules[\\/]/.test(filename));
63
- const plugins = [];
63
+ // @ts-expect-error Import attribute syntax plugin does not currently have type definitions
64
+ const { default: importAttributePlugin } = await Promise.resolve().then(() => __importStar(require('@babel/plugin-syntax-import-attributes')));
65
+ const plugins = [importAttributePlugin];
64
66
  // Lazy load the linker plugin only when linking is required
65
67
  if (shouldLink) {
66
68
  const linkerPlugin = await createLinkerPlugin(options);
@@ -11,7 +11,8 @@ import { NormalizedApplicationBuildOptions, NormalizedOutputOptions } from '../.
11
11
  import { BudgetCalculatorResult } from '../../utils/bundle-calculator';
12
12
  import { BuildOutputFile, BuildOutputFileType, InitialFileRecord } from './bundler-context';
13
13
  import { BuildOutputAsset, ExecutionResult } from './bundler-execution-result';
14
- export declare function logBuildStats(metafile: Metafile, initial: Map<string, InitialFileRecord>, budgetFailures: BudgetCalculatorResult[] | undefined, colors: boolean, changedFiles?: Set<string>, estimatedTransferSizes?: Map<string, number>, ssrOutputEnabled?: boolean, verbose?: boolean): string;
14
+ export declare function logBuildStats(metafile: Metafile, outputFiles: BuildOutputFile[], initial: Map<string, InitialFileRecord>, budgetFailures: BudgetCalculatorResult[] | undefined, colors: boolean, changedFiles?: Set<string>, estimatedTransferSizes?: Map<string, number>, ssrOutputEnabled?: boolean, verbose?: boolean): string;
15
+ export declare function getChunkNameFromMetafile(metafile: Metafile, file: string): string | undefined;
15
16
  export declare function calculateEstimatedTransferSizes(outputFiles: OutputFile[]): Promise<Map<string, number>>;
16
17
  export declare function withSpinner<T>(text: string, action: () => T | Promise<T>): Promise<T>;
17
18
  export declare function withNoProgress<T>(text: string, action: () => T | Promise<T>): Promise<T>;
@@ -25,8 +26,7 @@ export declare function withNoProgress<T>(text: string, action: () => T | Promis
25
26
  export declare function getFeatureSupport(target: string[], nativeAsyncAwait: boolean): BuildOptions['supported'];
26
27
  export declare function writeResultFiles(outputFiles: BuildOutputFile[], assetFiles: BuildOutputAsset[] | undefined, { base, browser, server }: NormalizedOutputOptions): Promise<void>;
27
28
  export declare function emitFilesToDisk<T = BuildOutputAsset | BuildOutputFile>(files: T[], writeFileCallback: (file: T) => Promise<void>): Promise<void>;
28
- export declare function createOutputFileFromText(path: string, text: string, type: BuildOutputFileType): BuildOutputFile;
29
- export declare function createOutputFileFromData(path: string, data: Uint8Array, type: BuildOutputFileType): BuildOutputFile;
29
+ export declare function createOutputFile(path: string, data: string | Uint8Array, type: BuildOutputFileType): BuildOutputFile;
30
30
  export declare function convertOutputFile(file: OutputFile, type: BuildOutputFileType): BuildOutputFile;
31
31
  /**
32
32
  * Transform browserlists result to esbuild target.
@@ -47,3 +47,4 @@ export declare function logMessages(logger: BuilderContext['logger'], executionR
47
47
  * @returns true, when the application is considered as zoneless.
48
48
  */
49
49
  export declare function isZonelessApp(polyfills: string[] | undefined): boolean;
50
+ export declare function getEntryPointName(entryPoint: string): string;