@angular/build 19.1.2 → 19.1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/build",
3
- "version": "19.1.2",
3
+ "version": "19.1.3",
4
4
  "description": "Official build system for Angular",
5
5
  "keywords": [
6
6
  "Angular CLI",
@@ -23,7 +23,7 @@
23
23
  "builders": "builders.json",
24
24
  "dependencies": {
25
25
  "@ampproject/remapping": "2.3.0",
26
- "@angular-devkit/architect": "0.1901.2",
26
+ "@angular-devkit/architect": "0.1901.3",
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",
@@ -57,7 +57,7 @@
57
57
  "@angular/localize": "^19.0.0",
58
58
  "@angular/platform-server": "^19.0.0",
59
59
  "@angular/service-worker": "^19.0.0",
60
- "@angular/ssr": "^19.1.2",
60
+ "@angular/ssr": "^19.1.3",
61
61
  "less": "^4.2.0",
62
62
  "ng-packagr": "^19.0.0",
63
63
  "postcss": "^8.4.0",
@@ -187,30 +187,11 @@ function* emitOutputResults({ outputFiles, assetFiles, errors, warnings, externa
187
187
  };
188
188
  return;
189
189
  }
190
- // Template updates only exist if no other JS changes have occurred
191
- const hasTemplateUpdates = !!templateUpdates?.size;
192
- if (hasTemplateUpdates) {
193
- const updateResult = {
194
- kind: results_1.ResultKind.ComponentUpdate,
195
- updates: Array.from(templateUpdates, ([id, content]) => ({
196
- type: 'template',
197
- id,
198
- content,
199
- })),
200
- };
201
- yield updateResult;
202
- }
203
- // Use an incremental result if previous output information is available
204
- if (rebuildState && changes) {
205
- const { previousAssetsInfo, previousOutputInfo } = rebuildState;
206
- const incrementalResult = {
207
- kind: results_1.ResultKind.Incremental,
190
+ // Use a full result if there is no rebuild state (no prior build result)
191
+ if (!rebuildState || !changes) {
192
+ const result = {
193
+ kind: results_1.ResultKind.Full,
208
194
  warnings: warnings,
209
- // These files need to be updated in the dev server but should not signal any updates
210
- background: hasTemplateUpdates,
211
- added: [],
212
- removed: [],
213
- modified: [],
214
195
  files: {},
215
196
  detail: {
216
197
  externalMetadata,
@@ -219,67 +200,37 @@ function* emitOutputResults({ outputFiles, assetFiles, errors, warnings, externa
219
200
  outputOptions,
220
201
  },
221
202
  };
222
- // Initially assume all previous output files have been removed
223
- const removedOutputFiles = new Map(previousOutputInfo);
224
- for (const file of outputFiles) {
225
- removedOutputFiles.delete(file.path);
226
- const previousHash = previousOutputInfo.get(file.path)?.hash;
227
- let needFile = false;
228
- if (previousHash === undefined) {
229
- needFile = true;
230
- incrementalResult.added.push(file.path);
231
- }
232
- else if (previousHash !== file.hash) {
233
- needFile = true;
234
- incrementalResult.modified.push(file.path);
235
- }
236
- if (needFile) {
237
- // Updates to non-JS files must signal an update with the dev server
238
- if (!/(?:\.m?js|\.map)?$/.test(file.path)) {
239
- incrementalResult.background = false;
240
- }
241
- incrementalResult.files[file.path] = {
242
- type: file.type,
243
- contents: file.contents,
244
- origin: 'memory',
245
- hash: file.hash,
246
- };
247
- }
248
- }
249
- // Initially assume all previous assets files have been removed
250
- const removedAssetFiles = new Map(previousAssetsInfo);
251
- for (const { source, destination } of assetFiles) {
252
- removedAssetFiles.delete(source);
253
- if (!previousAssetsInfo.has(source)) {
254
- incrementalResult.added.push(destination);
255
- }
256
- else if (changes.modified.has(source)) {
257
- incrementalResult.modified.push(destination);
258
- }
259
- else {
260
- continue;
261
- }
262
- incrementalResult.files[destination] = {
203
+ for (const file of assetFiles) {
204
+ result.files[file.destination] = {
263
205
  type: bundler_context_1.BuildOutputFileType.Browser,
264
- inputPath: source,
206
+ inputPath: file.source,
265
207
  origin: 'disk',
266
208
  };
267
209
  }
268
- // Include the removed output and asset files
269
- incrementalResult.removed.push(...Array.from(removedOutputFiles, ([file, { type }]) => ({
270
- path: file,
271
- type,
272
- })), ...Array.from(removedAssetFiles.values(), (file) => ({
273
- path: file,
274
- type: bundler_context_1.BuildOutputFileType.Browser,
275
- })));
276
- yield incrementalResult;
210
+ for (const file of outputFiles) {
211
+ result.files[file.path] = {
212
+ type: file.type,
213
+ contents: file.contents,
214
+ origin: 'memory',
215
+ hash: file.hash,
216
+ };
217
+ }
218
+ yield result;
277
219
  return;
278
220
  }
279
- // Otherwise, use a full result
280
- const result = {
281
- kind: results_1.ResultKind.Full,
221
+ // Template updates only exist if no other JS changes have occurred.
222
+ // A full page reload may be required based on the following incremental output change analysis.
223
+ const hasTemplateUpdates = !!templateUpdates?.size;
224
+ // Use an incremental result if previous output information is available
225
+ const { previousAssetsInfo, previousOutputInfo } = rebuildState;
226
+ const incrementalResult = {
227
+ kind: results_1.ResultKind.Incremental,
282
228
  warnings: warnings,
229
+ // Initially attempt to use a background update of files to support component updates.
230
+ background: hasTemplateUpdates,
231
+ added: [],
232
+ removed: [],
233
+ modified: [],
283
234
  files: {},
284
235
  detail: {
285
236
  externalMetadata,
@@ -288,20 +239,74 @@ function* emitOutputResults({ outputFiles, assetFiles, errors, warnings, externa
288
239
  outputOptions,
289
240
  },
290
241
  };
291
- for (const file of assetFiles) {
292
- result.files[file.destination] = {
242
+ // Initially assume all previous output files have been removed
243
+ const removedOutputFiles = new Map(previousOutputInfo);
244
+ for (const file of outputFiles) {
245
+ removedOutputFiles.delete(file.path);
246
+ const previousHash = previousOutputInfo.get(file.path)?.hash;
247
+ let needFile = false;
248
+ if (previousHash === undefined) {
249
+ needFile = true;
250
+ incrementalResult.added.push(file.path);
251
+ }
252
+ else if (previousHash !== file.hash) {
253
+ needFile = true;
254
+ incrementalResult.modified.push(file.path);
255
+ }
256
+ if (needFile) {
257
+ // Updates to non-JS files must signal an update with the dev server
258
+ if (!/(?:\.m?js|\.map)$/.test(file.path)) {
259
+ incrementalResult.background = false;
260
+ }
261
+ incrementalResult.files[file.path] = {
262
+ type: file.type,
263
+ contents: file.contents,
264
+ origin: 'memory',
265
+ hash: file.hash,
266
+ };
267
+ }
268
+ }
269
+ // Initially assume all previous assets files have been removed
270
+ const removedAssetFiles = new Map(previousAssetsInfo);
271
+ for (const { source, destination } of assetFiles) {
272
+ removedAssetFiles.delete(source);
273
+ if (!previousAssetsInfo.has(source)) {
274
+ incrementalResult.added.push(destination);
275
+ incrementalResult.background = false;
276
+ }
277
+ else if (changes.modified.has(source)) {
278
+ incrementalResult.modified.push(destination);
279
+ incrementalResult.background = false;
280
+ }
281
+ else {
282
+ continue;
283
+ }
284
+ incrementalResult.files[destination] = {
293
285
  type: bundler_context_1.BuildOutputFileType.Browser,
294
- inputPath: file.source,
286
+ inputPath: source,
295
287
  origin: 'disk',
296
288
  };
297
289
  }
298
- for (const file of outputFiles) {
299
- result.files[file.path] = {
300
- type: file.type,
301
- contents: file.contents,
302
- origin: 'memory',
303
- hash: file.hash,
290
+ // Include the removed output and asset files
291
+ incrementalResult.removed.push(...Array.from(removedOutputFiles, ([file, { type }]) => ({
292
+ path: file,
293
+ type,
294
+ })), ...Array.from(removedAssetFiles.values(), (file) => ({
295
+ path: file,
296
+ type: bundler_context_1.BuildOutputFileType.Browser,
297
+ })));
298
+ yield incrementalResult;
299
+ // If there are template updates and the incremental update was background only, a component
300
+ // update is possible.
301
+ if (hasTemplateUpdates && incrementalResult.background) {
302
+ const updateResult = {
303
+ kind: results_1.ResultKind.ComponentUpdate,
304
+ updates: Array.from(templateUpdates, ([id, content]) => ({
305
+ type: 'template',
306
+ id,
307
+ content,
308
+ })),
304
309
  };
310
+ yield updateResult;
305
311
  }
306
- yield result;
307
312
  }
@@ -120,7 +120,11 @@ class AotCompilation extends angular_compilation_1.AngularCompilation {
120
120
  relativePath = relativePath.replaceAll('\\', '/');
121
121
  const updateId = encodeURIComponent(`${host.getCanonicalFileName(relativePath)}@${node.name?.text}`);
122
122
  const updateText = angularCompiler.emitHmrUpdateModule(node);
123
- if (updateText === null) {
123
+ // If compiler cannot generate an update for the component, prevent template updates.
124
+ // Also prevent template updates if $localize is directly present which also currently
125
+ // prevents a template update at runtime.
126
+ // TODO: Support localized template update modules and remove this check.
127
+ if (updateText === null || updateText.includes('$localize')) {
124
128
  // Build is needed if a template cannot be updated
125
129
  templateUpdates = undefined;
126
130
  break;
@@ -5,5 +5,5 @@
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://angular.dev/license
7
7
  */
8
- import type { Connect } from 'vite';
9
- export declare function createAngularComponentMiddleware(templateUpdates: ReadonlyMap<string, string>): Connect.NextHandleFunction;
8
+ import type { Connect, ViteDevServer } from 'vite';
9
+ export declare function createAngularComponentMiddleware(server: ViteDevServer, templateUpdates: ReadonlyMap<string, string>): Connect.NextHandleFunction;
@@ -8,13 +8,15 @@
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.createAngularComponentMiddleware = createAngularComponentMiddleware;
11
+ const utils_1 = require("../utils");
11
12
  const ANGULAR_COMPONENT_PREFIX = '/@ng/component';
12
- function createAngularComponentMiddleware(templateUpdates) {
13
+ function createAngularComponentMiddleware(server, templateUpdates) {
13
14
  return function angularComponentMiddleware(req, res, next) {
14
15
  if (req.url === undefined || res.writableEnded) {
15
16
  return;
16
17
  }
17
- if (!req.url.startsWith(ANGULAR_COMPONENT_PREFIX)) {
18
+ const pathname = (0, utils_1.pathnameWithoutBasePath)(req.url, server.config.base);
19
+ if (!pathname.includes(ANGULAR_COMPONENT_PREFIX)) {
18
20
  next();
19
21
  return;
20
22
  }
@@ -35,8 +35,11 @@ async function createAngularMemoryPlugin(options) {
35
35
  // Vite will resolve these these files example:
36
36
  // `file:///@ng/component?c=src%2Fapp%2Fapp.component.ts%40AppComponent&t=1737017253850`
37
37
  const sourcePath = (0, node_url_1.fileURLToPath)(source);
38
- const { root } = (0, node_path_1.parse)(sourcePath);
39
- const sourceWithoutRoot = normalizePath('/' + sourcePath.slice(root.length));
38
+ const sourceWithoutRoot = sourcePath.startsWith(virtualProjectRoot)
39
+ ? normalizePath('/' + (0, node_path_1.relative)(virtualProjectRoot, sourcePath))
40
+ : // TODO: remove once https://github.com/angular/angular/blob/4e6017a9f5cda389c5fbf4f2c1519ce1bba23e11/packages/compiler/src/render3/r3_hmr_compiler.ts#L57
41
+ // is changed from `/@ng` to `./@ng/`
42
+ normalizePath('/' + sourcePath.slice((0, node_path_1.parse)(sourcePath).root.length));
40
43
  if (sourceWithoutRoot.startsWith(ANGULAR_PREFIX)) {
41
44
  const [, query] = source.split('?', 2);
42
45
  return `\0${sourceWithoutRoot}?${query}`;
@@ -49,7 +49,7 @@ function createAngularSetupMiddlewaresPlugin(options) {
49
49
  const { indexHtmlTransformer, outputFiles, extensionMiddleware, assets, componentStyles, templateUpdates, ssrMode, resetComponentUpdates, } = options;
50
50
  // Headers, assets and resources get handled first
51
51
  server.middlewares.use((0, middlewares_1.createAngularHeadersMiddleware)(server));
52
- server.middlewares.use((0, middlewares_1.createAngularComponentMiddleware)(templateUpdates));
52
+ server.middlewares.use((0, middlewares_1.createAngularComponentMiddleware)(server, templateUpdates));
53
53
  server.middlewares.use((0, middlewares_1.createAngularAssetsMiddleware)(server, assets, outputFiles, componentStyles, await createEncapsulateStyle()));
54
54
  extensionMiddleware?.forEach((middleware) => server.middlewares.use(middleware));
55
55
  // Returning a function, installs middleware after the main transform middleware but
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.normalizeCacheOptions = normalizeCacheOptions;
11
11
  const node_path_1 = require("node:path");
12
12
  /** Version placeholder is replaced during the build process with actual package version */
13
- const VERSION = '19.1.2';
13
+ const VERSION = '19.1.3';
14
14
  function hasCacheMetadata(value) {
15
15
  return (!!value &&
16
16
  typeof value === 'object' &&