@angular/build 19.1.0-next.1 → 19.1.0-rc.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 (43) 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 +18 -12
  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 +80 -11
  10. package/src/builders/application/execute-build.js +36 -3
  11. package/src/builders/application/index.d.ts +2 -10
  12. package/src/builders/application/index.js +33 -20
  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/dev-server/index.d.ts +1 -1
  17. package/src/builders/dev-server/vite-server.d.ts +1 -1
  18. package/src/builders/dev-server/vite-server.js +103 -76
  19. package/src/builders/extract-i18n/index.d.ts +1 -1
  20. package/src/builders/ng-packagr/builder.d.ts +19 -0
  21. package/src/builders/ng-packagr/builder.js +103 -0
  22. package/src/builders/ng-packagr/index.d.ts +12 -0
  23. package/src/builders/ng-packagr/index.js +14 -0
  24. package/src/builders/ng-packagr/schema.d.ts +21 -0
  25. package/src/builders/ng-packagr/schema.js +4 -0
  26. package/src/builders/ng-packagr/schema.json +27 -0
  27. package/src/index.d.ts +2 -1
  28. package/src/index.js +3 -1
  29. package/src/tools/babel/plugins/pure-toplevel-functions.js +14 -3
  30. package/src/tools/esbuild/angular-localize-init-warning-plugin.d.ts +16 -0
  31. package/src/tools/esbuild/angular-localize-init-warning-plugin.js +49 -0
  32. package/src/tools/esbuild/application-code-bundle.js +6 -0
  33. package/src/tools/esbuild/bundler-execution-result.d.ts +9 -3
  34. package/src/tools/esbuild/bundler-execution-result.js +12 -10
  35. package/src/tools/esbuild/javascript-transformer.js +8 -4
  36. package/src/tools/vite/plugins/angular-memory-plugin.js +20 -4
  37. package/src/tools/vite/utils.d.ts +2 -1
  38. package/src/tools/vite/utils.js +2 -1
  39. package/src/utils/bundle-calculator.d.ts +1 -0
  40. package/src/utils/bundle-calculator.js +5 -4
  41. package/src/utils/environment-options.js +1 -1
  42. package/src/utils/normalize-cache.js +1 -1
  43. package/src/utils/server-rendering/fetch-patch.js +2 -2
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License
2
2
 
3
- Copyright (c) 2010-2024 Google LLC. https://angular.dev/license
3
+ Copyright (c) 2010-2025 Google LLC. https://angular.dev/license
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/builders.json CHANGED
@@ -14,6 +14,11 @@
14
14
  "implementation": "./src/builders/extract-i18n/index",
15
15
  "schema": "./src/builders/extract-i18n/schema.json",
16
16
  "description": "Extract i18n messages from an application."
17
+ },
18
+ "ng-packagr": {
19
+ "implementation": "./src/builders/ng-packagr/index",
20
+ "schema": "./src/builders/ng-packagr/schema.json",
21
+ "description": "Build a library with ng-packagr."
17
22
  }
18
23
  }
19
24
  }
package/index.d.ts ADDED
@@ -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.dev/license
7
+ */
8
+ export * from './src/index';
package/index.js ADDED
@@ -0,0 +1,24 @@
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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
21
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ __exportStar(require("./src/index"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/build",
3
- "version": "19.1.0-next.1",
3
+ "version": "19.1.0-rc.0",
4
4
  "description": "Official build system for Angular",
5
5
  "keywords": [
6
6
  "Angular CLI",
@@ -23,33 +23,33 @@
23
23
  "builders": "builders.json",
24
24
  "dependencies": {
25
25
  "@ampproject/remapping": "2.3.0",
26
- "@angular-devkit/architect": "0.1901.0-next.1",
26
+ "@angular-devkit/architect": "0.1901.0-rc.0",
27
27
  "@babel/core": "7.26.0",
28
28
  "@babel/helper-annotate-as-pure": "7.25.9",
29
29
  "@babel/helper-split-export-declaration": "7.24.7",
30
30
  "@babel/plugin-syntax-import-attributes": "7.26.0",
31
- "@inquirer/confirm": "5.1.0",
31
+ "@inquirer/confirm": "5.1.1",
32
32
  "@vitejs/plugin-basic-ssl": "1.2.0",
33
33
  "beasties": "0.2.0",
34
34
  "browserslist": "^4.23.0",
35
- "esbuild": "0.24.0",
36
- "fast-glob": "3.3.2",
35
+ "esbuild": "0.24.2",
36
+ "fast-glob": "3.3.3",
37
37
  "https-proxy-agent": "7.0.6",
38
38
  "istanbul-lib-instrument": "6.0.3",
39
39
  "listr2": "8.2.5",
40
- "magic-string": "0.30.15",
40
+ "magic-string": "0.30.17",
41
41
  "mrmime": "2.0.0",
42
42
  "parse5-html-rewriting-stream": "7.0.0",
43
43
  "picomatch": "4.0.2",
44
44
  "piscina": "4.8.0",
45
- "rollup": "4.28.1",
46
- "sass": "1.82.0",
45
+ "rollup": "4.30.1",
46
+ "sass": "1.83.1",
47
47
  "semver": "7.6.3",
48
- "vite": "6.0.3",
48
+ "vite": "6.0.7",
49
49
  "watchpack": "2.4.2"
50
50
  },
51
51
  "optionalDependencies": {
52
- "lmdb": "3.2.0"
52
+ "lmdb": "3.2.2"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "@angular/compiler": "^19.0.0 || ^19.1.0-next.0",
@@ -57,8 +57,9 @@
57
57
  "@angular/localize": "^19.0.0 || ^19.1.0-next.0",
58
58
  "@angular/platform-server": "^19.0.0 || ^19.1.0-next.0",
59
59
  "@angular/service-worker": "^19.0.0 || ^19.1.0-next.0",
60
- "@angular/ssr": "^19.1.0-next.1",
60
+ "@angular/ssr": "^19.1.0-rc.0",
61
61
  "less": "^4.2.0",
62
+ "ng-packagr": "^19.0.0 || ^19.1.0-next.0",
62
63
  "postcss": "^8.4.0",
63
64
  "tailwindcss": "^2.0.0 || ^3.0.0",
64
65
  "typescript": ">=5.5 <5.8"
@@ -79,6 +80,9 @@
79
80
  "less": {
80
81
  "optional": true
81
82
  },
83
+ "ng-packagr": {
84
+ "optional": true
85
+ },
82
86
  "postcss": {
83
87
  "optional": true
84
88
  },
@@ -86,7 +90,6 @@
86
90
  "optional": true
87
91
  }
88
92
  },
89
- "packageManager": "yarn@4.5.0",
90
93
  "repository": {
91
94
  "type": "git",
92
95
  "url": "https://github.com/angular/angular-cli.git"
@@ -109,5 +112,8 @@
109
112
  "puppeteer": {
110
113
  "built": true
111
114
  }
115
+ },
116
+ "pnpm": {
117
+ "onlyBuiltDependencies": []
112
118
  }
113
119
  }
@@ -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.dev/license
7
+ */
8
+ export * from '../src/private';
@@ -0,0 +1,24 @@
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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
21
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ __exportStar(require("../src/private"), exports);
@@ -25,4 +25,5 @@ export declare function runEsBuildBuildAction(action: (rebuildState?: RebuildSta
25
25
  clearScreen?: boolean;
26
26
  colors?: boolean;
27
27
  jsonLogs?: boolean;
28
+ incrementalResults?: boolean;
28
29
  }): AsyncIterable<Result>;
@@ -65,7 +65,7 @@ const packageWatchFiles = [
65
65
  '.pnp.data.json',
66
66
  ];
67
67
  async function* runEsBuildBuildAction(action, options) {
68
- const { watch, poll, clearScreen, logger, cacheOptions, outputOptions, verbose, projectRoot, workspaceRoot, progress, preserveSymlinks, colors, jsonLogs, } = options;
68
+ const { watch, poll, clearScreen, logger, cacheOptions, outputOptions, verbose, projectRoot, workspaceRoot, progress, preserveSymlinks, colors, jsonLogs, incrementalResults, } = options;
69
69
  const withProgress = progress ? utils_1.withSpinner : utils_1.withNoProgress;
70
70
  // Initial build
71
71
  let result;
@@ -122,7 +122,7 @@ async function* runEsBuildBuildAction(action, options) {
122
122
  // Output the first build results after setting up the watcher to ensure that any code executed
123
123
  // higher in the iterator call stack will trigger the watcher. This is particularly relevant for
124
124
  // unit tests which execute the builder and modify the file system programmatically.
125
- yield await emitOutputResult(result, outputOptions);
125
+ yield* emitOutputResults(result, outputOptions);
126
126
  // Finish if watch mode is not enabled
127
127
  if (!watcher) {
128
128
  return;
@@ -143,7 +143,8 @@ async function* runEsBuildBuildAction(action, options) {
143
143
  }
144
144
  // Clear removed files from current watch files
145
145
  changes.removed.forEach((removedPath) => currentWatchFiles.delete(removedPath));
146
- result = await withProgress('Changes detected. Rebuilding...', () => action(result.createRebuildState(changes)));
146
+ const rebuildState = result.createRebuildState(changes);
147
+ result = await withProgress('Changes detected. Rebuilding...', () => action(rebuildState));
147
148
  // Log all diagnostic (error/warning/logs) messages
148
149
  await (0, utils_1.logMessages)(logger, result, colors, jsonLogs);
149
150
  // Update watched locations provided by the new build result.
@@ -163,7 +164,9 @@ async function* runEsBuildBuildAction(action, options) {
163
164
  if (staleWatchFiles?.size) {
164
165
  watcher.remove([...staleWatchFiles]);
165
166
  }
166
- yield await emitOutputResult(result, outputOptions);
167
+ for (const outputResult of emitOutputResults(result, outputOptions, incrementalResults ? rebuildState.previousOutputInfo : undefined)) {
168
+ yield outputResult;
169
+ }
167
170
  }
168
171
  }
169
172
  finally {
@@ -172,9 +175,9 @@ async function* runEsBuildBuildAction(action, options) {
172
175
  (0, sass_language_1.shutdownSassWorkerPool)();
173
176
  }
174
177
  }
175
- async function emitOutputResult({ outputFiles, assetFiles, errors, warnings, externalMetadata, htmlIndexPath, htmlBaseHref, templateUpdates, }, outputOptions) {
178
+ function* emitOutputResults({ outputFiles, assetFiles, errors, warnings, externalMetadata, htmlIndexPath, htmlBaseHref, templateUpdates, }, outputOptions, previousOutputInfo) {
176
179
  if (errors.length > 0) {
177
- return {
180
+ yield {
178
181
  kind: results_1.ResultKind.Failure,
179
182
  errors: errors,
180
183
  warnings: warnings,
@@ -182,19 +185,85 @@ async function emitOutputResult({ outputFiles, assetFiles, errors, warnings, ext
182
185
  outputOptions,
183
186
  },
184
187
  };
188
+ return;
185
189
  }
186
- // Template updates only exist if no other changes have occurred
187
- if (templateUpdates?.size) {
190
+ // Template updates only exist if no other JS changes have occurred
191
+ const hasTemplateUpdates = !!templateUpdates?.size;
192
+ if (hasTemplateUpdates) {
188
193
  const updateResult = {
189
194
  kind: results_1.ResultKind.ComponentUpdate,
190
- updates: Array.from(templateUpdates).map(([id, content]) => ({
195
+ updates: Array.from(templateUpdates, ([id, content]) => ({
191
196
  type: 'template',
192
197
  id,
193
198
  content,
194
199
  })),
195
200
  };
196
- return updateResult;
201
+ yield updateResult;
202
+ }
203
+ // Use an incremental result if previous output information is available
204
+ if (previousOutputInfo) {
205
+ const incrementalResult = {
206
+ kind: results_1.ResultKind.Incremental,
207
+ warnings: warnings,
208
+ added: [],
209
+ removed: [],
210
+ modified: [],
211
+ files: {},
212
+ detail: {
213
+ externalMetadata,
214
+ htmlIndexPath,
215
+ htmlBaseHref,
216
+ outputOptions,
217
+ },
218
+ };
219
+ // Initially assume all previous output files have been removed
220
+ const removedOutputFiles = new Map(previousOutputInfo);
221
+ for (const file of outputFiles) {
222
+ removedOutputFiles.delete(file.path);
223
+ // Temporarily ignore JS files until Angular compiler plugin refactor to allow
224
+ // bypassing application code bundling for template affecting only changes.
225
+ // TODO: Remove once refactor is complete.
226
+ if (hasTemplateUpdates && /\.js(?:\.map)?$/.test(file.path)) {
227
+ continue;
228
+ }
229
+ const previousHash = previousOutputInfo.get(file.path)?.hash;
230
+ let needFile = false;
231
+ if (previousHash === undefined) {
232
+ needFile = true;
233
+ incrementalResult.added.push(file.path);
234
+ }
235
+ else if (previousHash !== file.hash) {
236
+ needFile = true;
237
+ incrementalResult.modified.push(file.path);
238
+ }
239
+ if (needFile) {
240
+ incrementalResult.files[file.path] = {
241
+ type: file.type,
242
+ contents: file.contents,
243
+ origin: 'memory',
244
+ hash: file.hash,
245
+ };
246
+ }
247
+ }
248
+ // Include the removed output files
249
+ incrementalResult.removed.push(...Array.from(removedOutputFiles, ([file, { type }]) => ({
250
+ path: file,
251
+ type,
252
+ })));
253
+ // Always consider asset files as added to ensure new/modified assets are available.
254
+ // TODO: Consider more comprehensive asset analysis.
255
+ for (const file of assetFiles) {
256
+ incrementalResult.added.push(file.destination);
257
+ incrementalResult.files[file.destination] = {
258
+ type: bundler_context_1.BuildOutputFileType.Browser,
259
+ inputPath: file.source,
260
+ origin: 'disk',
261
+ };
262
+ }
263
+ yield incrementalResult;
264
+ return;
197
265
  }
266
+ // Otherwise, use a full result
198
267
  const result = {
199
268
  kind: results_1.ResultKind.Full,
200
269
  warnings: warnings,
@@ -221,5 +290,5 @@ async function emitOutputResult({ outputFiles, assetFiles, errors, warnings, ext
221
290
  hash: file.hash,
222
291
  };
223
292
  }
224
- return result;
293
+ yield result;
225
294
  }
@@ -6,6 +6,39 @@
6
6
  * Use of this source code is governed by an MIT-style license that can be
7
7
  * found in the LICENSE file at https://angular.dev/license
8
8
  */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
9
42
  Object.defineProperty(exports, "__esModule", { value: true });
10
43
  exports.executeBuild = executeBuild;
11
44
  const source_file_cache_1 = require("../../tools/esbuild/angular/source-file-cache");
@@ -21,7 +54,6 @@ const environment_options_1 = require("../../utils/environment-options");
21
54
  const resolve_assets_1 = require("../../utils/resolve-assets");
22
55
  const manifest_1 = require("../../utils/server-rendering/manifest");
23
56
  const supported_browsers_1 = require("../../utils/supported-browsers");
24
- const chunk_optimizer_1 = require("./chunk-optimizer");
25
57
  const execute_post_bundle_1 = require("./execute-post-bundle");
26
58
  const i18n_1 = require("./i18n");
27
59
  const setup_bundling_1 = require("./setup-bundling");
@@ -85,7 +117,8 @@ async function executeBuild(options, context, rebuildState) {
85
117
  bundlingResult = bundler_context_1.BundlerContext.mergeResults([bundlingResult, ...componentResults]);
86
118
  }
87
119
  if (options.optimizationOptions.scripts && environment_options_1.shouldOptimizeChunks) {
88
- bundlingResult = await (0, profiling_1.profileAsync)('OPTIMIZE_CHUNKS', () => (0, chunk_optimizer_1.optimizeChunks)(bundlingResult, options.sourcemapOptions.scripts ? !options.sourcemapOptions.hidden || 'hidden' : false));
120
+ const { optimizeChunks } = await Promise.resolve().then(() => __importStar(require('./chunk-optimizer')));
121
+ bundlingResult = await (0, profiling_1.profileAsync)('OPTIMIZE_CHUNKS', () => optimizeChunks(bundlingResult, options.sourcemapOptions.scripts ? !options.sourcemapOptions.hidden || 'hidden' : false));
89
122
  }
90
123
  const executionResult = new bundler_execution_result_1.ExecutionResult(bundlerContexts, componentStyleBundler, codeBundleCache, templateUpdates);
91
124
  executionResult.addWarnings(bundlingResult.warnings);
@@ -112,7 +145,7 @@ async function executeBuild(options, context, rebuildState) {
112
145
  }
113
146
  const { metafile, initialFiles, outputFiles } = bundlingResult;
114
147
  executionResult.outputFiles.push(...outputFiles);
115
- const changedFiles = rebuildState && executionResult.findChangedFiles(rebuildState.previousOutputHashes);
148
+ const changedFiles = rebuildState && executionResult.findChangedFiles(rebuildState.previousOutputInfo);
116
149
  // Analyze files for bundle budget failures if present
117
150
  let budgetFailures;
118
151
  if (options.budgets) {
@@ -6,7 +6,6 @@
6
6
  * found in the LICENSE file at https://angular.dev/license
7
7
  */
8
8
  import { BuilderContext, BuilderOutput } from '@angular-devkit/architect';
9
- import { BuildOutputFile } from '../../tools/esbuild/bundler-context';
10
9
  import { ApplicationBuilderExtensions, ApplicationBuilderInternalOptions } from './options';
11
10
  import { Result } from './results';
12
11
  import { Schema as ApplicationBuilderOptions } from './schema';
@@ -14,13 +13,6 @@ export type { ApplicationBuilderOptions };
14
13
  export declare function buildApplicationInternal(options: ApplicationBuilderInternalOptions, context: BuilderContext & {
15
14
  signal?: AbortSignal;
16
15
  }, extensions?: ApplicationBuilderExtensions): AsyncIterable<Result>;
17
- export interface ApplicationBuilderOutput extends BuilderOutput {
18
- outputFiles?: BuildOutputFile[];
19
- assetFiles?: {
20
- source: string;
21
- destination: string;
22
- }[];
23
- }
24
16
  /**
25
17
  * Builds an application using the `application` builder with the provided
26
18
  * options.
@@ -35,6 +27,6 @@ export interface ApplicationBuilderOutput extends BuilderOutput {
35
27
  * @param extensions An object contain extension points for the build.
36
28
  * @returns The build output results of the build.
37
29
  */
38
- export declare function buildApplication(options: ApplicationBuilderOptions, context: BuilderContext, extensions?: ApplicationBuilderExtensions): AsyncIterable<ApplicationBuilderOutput>;
39
- declare const _default: import("../../../../../angular_devkit/architect/src/internal").Builder<ApplicationBuilderOptions & import("../../../../../angular_devkit/core/src").JsonObject>;
30
+ export declare function buildApplication(options: ApplicationBuilderOptions, context: BuilderContext, extensions?: ApplicationBuilderExtensions): AsyncIterable<BuilderOutput>;
31
+ declare const _default: import("../../../../../angular_devkit/architect/src/internal").Builder<ApplicationBuilderOptions & import("../../../../../angular_devkit/core").JsonObject>;
40
32
  export default _default;
@@ -96,6 +96,7 @@ context, extensions) {
96
96
  clearScreen: normalizedOptions.clearScreen,
97
97
  colors: normalizedOptions.colors,
98
98
  jsonLogs: normalizedOptions.jsonLogs,
99
+ incrementalResults: normalizedOptions.incrementalResults,
99
100
  logger,
100
101
  signal,
101
102
  });
@@ -116,7 +117,8 @@ context, extensions) {
116
117
  */
117
118
  async function* buildApplication(options, context, extensions) {
118
119
  let initial = true;
119
- for await (const result of buildApplicationInternal(options, context, extensions)) {
120
+ const internalOptions = { ...options, incrementalResults: true };
121
+ for await (const result of buildApplicationInternal(internalOptions, context, extensions)) {
120
122
  const outputOptions = result.detail?.['outputOptions'];
121
123
  if (initial) {
122
124
  initial = false;
@@ -134,7 +136,7 @@ async function* buildApplication(options, context, extensions) {
134
136
  continue;
135
137
  }
136
138
  (0, node_assert_1.default)(outputOptions, 'Application output options are required for builder usage.');
137
- (0, node_assert_1.default)(result.kind === results_1.ResultKind.Full, 'Application build did not provide a full output.');
139
+ (0, node_assert_1.default)(result.kind === results_1.ResultKind.Full || result.kind === results_1.ResultKind.Incremental, 'Application build did not provide a file result output.');
138
140
  // TODO: Restructure output logging to better handle stdout JSON piping
139
141
  if (!environment_options_1.useJSONBuildLogs) {
140
142
  context.logger.info(`Output location: ${outputOptions.base}\n`);
@@ -147,24 +149,7 @@ async function* buildApplication(options, context, extensions) {
147
149
  file.type === bundler_context_1.BuildOutputFileType.ServerRoot)) {
148
150
  return;
149
151
  }
150
- let typeDirectory;
151
- switch (file.type) {
152
- case bundler_context_1.BuildOutputFileType.Browser:
153
- case bundler_context_1.BuildOutputFileType.Media:
154
- typeDirectory = outputOptions.browser;
155
- break;
156
- case bundler_context_1.BuildOutputFileType.ServerApplication:
157
- case bundler_context_1.BuildOutputFileType.ServerRoot:
158
- typeDirectory = outputOptions.server;
159
- break;
160
- case bundler_context_1.BuildOutputFileType.Root:
161
- typeDirectory = '';
162
- break;
163
- default:
164
- throw new Error(`Unhandled write for file "${filePath}" with type "${bundler_context_1.BuildOutputFileType[file.type]}".`);
165
- }
166
- // NOTE: 'base' is a fully resolved path at this point
167
- const fullFilePath = node_path_1.default.join(outputOptions.base, typeDirectory, filePath);
152
+ const fullFilePath = generateFullPath(filePath, file.type, outputOptions);
168
153
  // Ensure output subdirectories exist
169
154
  const fileBasePath = node_path_1.default.dirname(fullFilePath);
170
155
  if (fileBasePath && !directoryExists.has(fileBasePath)) {
@@ -180,7 +165,35 @@ async function* buildApplication(options, context, extensions) {
180
165
  await promises_1.default.copyFile(file.inputPath, fullFilePath, promises_1.default.constants.COPYFILE_FICLONE);
181
166
  }
182
167
  });
168
+ // Delete any removed files if incremental
169
+ if (result.kind === results_1.ResultKind.Incremental && result.removed?.length) {
170
+ await Promise.all(result.removed.map((file) => {
171
+ const fullFilePath = generateFullPath(file.path, file.type, outputOptions);
172
+ return promises_1.default.rm(fullFilePath, { force: true, maxRetries: 3 });
173
+ }));
174
+ }
183
175
  yield { success: true };
184
176
  }
185
177
  }
178
+ function generateFullPath(filePath, type, outputOptions) {
179
+ let typeDirectory;
180
+ switch (type) {
181
+ case bundler_context_1.BuildOutputFileType.Browser:
182
+ case bundler_context_1.BuildOutputFileType.Media:
183
+ typeDirectory = outputOptions.browser;
184
+ break;
185
+ case bundler_context_1.BuildOutputFileType.ServerApplication:
186
+ case bundler_context_1.BuildOutputFileType.ServerRoot:
187
+ typeDirectory = outputOptions.server;
188
+ break;
189
+ case bundler_context_1.BuildOutputFileType.Root:
190
+ typeDirectory = '';
191
+ break;
192
+ default:
193
+ throw new Error(`Unhandled write for file "${filePath}" with type "${bundler_context_1.BuildOutputFileType[type]}".`);
194
+ }
195
+ // NOTE: 'base' is a fully resolved path at this point
196
+ const fullFilePath = node_path_1.default.join(outputOptions.base, typeDirectory, filePath);
197
+ return fullFilePath;
198
+ }
186
199
  exports.default = (0, architect_1.createBuilder)(buildApplication);
@@ -74,6 +74,11 @@ interface InternalOptions {
74
74
  * template updates.
75
75
  */
76
76
  templateUpdates?: boolean;
77
+ /**
78
+ * Enables emitting incremental build results when in watch mode. A full build result will only be emitted
79
+ * for the initial build. This option also requires watch to be enabled to have an effect.
80
+ */
81
+ incrementalResults?: boolean;
77
82
  /**
78
83
  * Enables instrumentation to collect code coverage data for specific files.
79
84
  *
@@ -193,6 +198,7 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
193
198
  instrumentForCoverage: ((filename: string) => boolean) | undefined;
194
199
  security: import("./schema").Security | undefined;
195
200
  templateUpdates: boolean;
201
+ incrementalResults: boolean;
196
202
  }>;
197
203
  export declare function getLocaleBaseHref(baseHref: string | undefined, i18n: NormalizedApplicationBuildOptions['i18nOptions'], locale: string): string | undefined;
198
204
  export {};
@@ -298,6 +298,7 @@ async function normalizeOptions(context, projectName, options, extensions) {
298
298
  instrumentForCoverage,
299
299
  security,
300
300
  templateUpdates: !!options.templateUpdates,
301
+ incrementalResults: !!options.incrementalResults,
301
302
  };
302
303
  }
303
304
  async function getTailwindConfig(searchDirectories, workspaceRoot, context) {
@@ -30,7 +30,10 @@ export interface FullResult extends BaseResult {
30
30
  export interface IncrementalResult extends BaseResult {
31
31
  kind: ResultKind.Incremental;
32
32
  added: string[];
33
- removed: string[];
33
+ removed: {
34
+ path: string;
35
+ type: BuildOutputFileType;
36
+ }[];
34
37
  modified: string[];
35
38
  files: Record<string, ResultFile>;
36
39
  }
@@ -9,6 +9,6 @@ import { execute } from './builder';
9
9
  import type { DevServerBuilderOutput } from './output';
10
10
  import type { Schema as DevServerBuilderOptions } from './schema';
11
11
  export { type DevServerBuilderOptions, type DevServerBuilderOutput, execute as executeDevServerBuilder, };
12
- declare const _default: import("../../../../../angular_devkit/architect/src/internal").Builder<DevServerBuilderOptions & import("../../../../../angular_devkit/core/src").JsonObject>;
12
+ declare const _default: import("../../../../../angular_devkit/architect/src/internal").Builder<DevServerBuilderOptions & import("../../../../../angular_devkit/core").JsonObject>;
13
13
  export default _default;
14
14
  export { execute as executeDevServer };
@@ -34,5 +34,5 @@ export declare function serveWithVite(serverOptions: NormalizedDevServerOptions,
34
34
  middleware?: Connect.NextHandleFunction[];
35
35
  buildPlugins?: Plugin[];
36
36
  }): AsyncIterableIterator<DevServerBuilderOutput>;
37
- export declare function setupServer(serverOptions: NormalizedDevServerOptions, outputFiles: Map<string, OutputFileRecord>, assets: Map<string, string>, preserveSymlinks: boolean | undefined, externalMetadata: DevServerExternalResultMetadata, ssrMode: ServerSsrMode, prebundleTransformer: JavaScriptTransformer, target: string[], zoneless: boolean, componentStyles: Map<string, ComponentStyleRecord>, templateUpdates: Map<string, string>, prebundleLoaderExtensions: EsbuildLoaderOption | undefined, extensionMiddleware?: Connect.NextHandleFunction[], indexHtmlTransformer?: (content: string) => Promise<string>, thirdPartySourcemaps?: boolean): Promise<InlineConfig>;
37
+ export declare function setupServer(serverOptions: NormalizedDevServerOptions, outputFiles: Map<string, OutputFileRecord>, assets: Map<string, string>, preserveSymlinks: boolean | undefined, externalMetadata: DevServerExternalResultMetadata, ssrMode: ServerSsrMode, prebundleTransformer: JavaScriptTransformer, target: string[], zoneless: boolean, componentStyles: Map<string, ComponentStyleRecord>, templateUpdates: Map<string, string>, prebundleLoaderExtensions: EsbuildLoaderOption | undefined, define: ApplicationBuilderInternalOptions['define'], extensionMiddleware?: Connect.NextHandleFunction[], indexHtmlTransformer?: (content: string) => Promise<string>, thirdPartySourcemaps?: boolean): Promise<InlineConfig>;
38
38
  export {};