@angular/build 19.1.0 → 19.1.2

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.0",
3
+ "version": "19.1.2",
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.0",
26
+ "@angular-devkit/architect": "0.1901.2",
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.0",
60
+ "@angular/ssr": "^19.1.2",
61
61
  "less": "^4.2.0",
62
62
  "ng-packagr": "^19.0.0",
63
63
  "postcss": "^8.4.0",
@@ -104,16 +104,5 @@
104
104
  "bugs": {
105
105
  "url": "https://github.com/angular/angular-cli/issues"
106
106
  },
107
- "homepage": "https://github.com/angular/angular-cli",
108
- "dependenciesMeta": {
109
- "esbuild": {
110
- "built": true
111
- },
112
- "puppeteer": {
113
- "built": true
114
- }
115
- },
116
- "pnpm": {
117
- "onlyBuiltDependencies": []
118
- }
107
+ "homepage": "https://github.com/angular/angular-cli"
119
108
  }
@@ -206,6 +206,8 @@ function* emitOutputResults({ outputFiles, assetFiles, errors, warnings, externa
206
206
  const incrementalResult = {
207
207
  kind: results_1.ResultKind.Incremental,
208
208
  warnings: warnings,
209
+ // These files need to be updated in the dev server but should not signal any updates
210
+ background: hasTemplateUpdates,
209
211
  added: [],
210
212
  removed: [],
211
213
  modified: [],
@@ -221,12 +223,6 @@ function* emitOutputResults({ outputFiles, assetFiles, errors, warnings, externa
221
223
  const removedOutputFiles = new Map(previousOutputInfo);
222
224
  for (const file of outputFiles) {
223
225
  removedOutputFiles.delete(file.path);
224
- // Temporarily ignore JS files until Angular compiler plugin refactor to allow
225
- // bypassing application code bundling for template affecting only changes.
226
- // TODO: Remove once refactor is complete.
227
- if (hasTemplateUpdates && /\.js(?:\.map)?$/.test(file.path)) {
228
- continue;
229
- }
230
226
  const previousHash = previousOutputInfo.get(file.path)?.hash;
231
227
  let needFile = false;
232
228
  if (previousHash === undefined) {
@@ -238,6 +234,10 @@ function* emitOutputResults({ outputFiles, assetFiles, errors, warnings, externa
238
234
  incrementalResult.modified.push(file.path);
239
235
  }
240
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
241
  incrementalResult.files[file.path] = {
242
242
  type: file.type,
243
243
  contents: file.contents,
@@ -29,6 +29,7 @@ export interface FullResult extends BaseResult {
29
29
  }
30
30
  export interface IncrementalResult extends BaseResult {
31
31
  kind: ResultKind.Incremental;
32
+ background?: boolean;
32
33
  added: string[];
33
34
  removed: {
34
35
  path: string;
@@ -110,6 +110,12 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
110
110
  // This will also replace file-based/inline styles as code if external runtime styles are not enabled.
111
111
  browserOptions.templateUpdates =
112
112
  serverOptions.liveReload && serverOptions.hmr && environment_options_1.useComponentTemplateHmr;
113
+ if (browserOptions.templateUpdates) {
114
+ context.logger.warn('Component HMR has been enabled.\n' +
115
+ 'If you encounter application reload issues, you can manually reload the page to bypass HMR and/or disable this feature with the' +
116
+ ' `--no-hmr` command line option.\n' +
117
+ 'Please consider reporting any issues you encounter here: https://github.com/angular/angular-cli/issues\n');
118
+ }
113
119
  browserOptions.incrementalResults = true;
114
120
  // Setup the prebundling transformer that will be shared across Vite prebundling requests
115
121
  const prebundleTransformer = new internal_1.JavaScriptTransformer(
@@ -166,6 +172,7 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
166
172
  updates: [],
167
173
  });
168
174
  }
175
+ let needClientUpdate = true;
169
176
  switch (result.kind) {
170
177
  case results_1.ResultKind.Full:
171
178
  if (result.detail?.['htmlIndexPath']) {
@@ -187,15 +194,13 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
187
194
  // The initial build will not yet have a server setup
188
195
  !server);
189
196
  }
190
- // Invalidate SSR module graph to ensure that only new rebuild is used and not stale component updates
191
- if (server && browserOptions.ssr && templateUpdates.size > 0) {
192
- server.moduleGraph.invalidateAll();
193
- }
194
197
  // Clear stale template updates on code rebuilds
195
198
  templateUpdates.clear();
196
199
  break;
197
200
  case results_1.ResultKind.Incremental:
198
201
  (0, node_assert_1.default)(server, 'Builder must provide an initial full build before incremental results.');
202
+ // Background updates should only update server files/options
203
+ needClientUpdate = !result.background;
199
204
  for (const removed of result.removed) {
200
205
  const filePath = '/' + normalizePath(removed.path);
201
206
  generatedFiles.delete(filePath);
@@ -211,13 +216,6 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
211
216
  case results_1.ResultKind.ComponentUpdate:
212
217
  (0, node_assert_1.default)(serverOptions.hmr, 'Component updates are only supported with HMR enabled.');
213
218
  (0, node_assert_1.default)(server, 'Builder must provide an initial full build before component update results.');
214
- // Invalidate SSR module graph to ensure that new component updates are used
215
- // TODO: Use fine-grained invalidation of only the component update modules
216
- if (browserOptions.ssr) {
217
- server.moduleGraph.invalidateAll();
218
- const { ɵresetCompiledComponents } = (await server.ssrLoadModule('/main.server.mjs'));
219
- ɵresetCompiledComponents();
220
- }
221
219
  for (const componentUpdate of result.updates) {
222
220
  if (componentUpdate.type === 'template') {
223
221
  templateUpdates.set(componentUpdate.id, componentUpdate.content);
@@ -262,7 +260,10 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
262
260
  ...[...assetFiles.values()].map(({ source }) => source),
263
261
  ]),
264
262
  ];
265
- await handleUpdate(normalizePath, generatedFiles, assetFiles, server, serverOptions, context.logger, componentStyles);
263
+ const updatedFiles = await invalidateUpdatedFiles(normalizePath, generatedFiles, assetFiles, server);
264
+ if (needClientUpdate) {
265
+ handleUpdate(server, serverOptions, context.logger, componentStyles, updatedFiles);
266
+ }
266
267
  }
267
268
  else {
268
269
  const projectName = context.target?.project;
@@ -335,7 +336,13 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
335
336
  }
336
337
  await new Promise((resolve) => (deferred = resolve));
337
338
  }
338
- async function handleUpdate(normalizePath, generatedFiles, assetFiles, server, serverOptions, logger, componentStyles) {
339
+ /**
340
+ * Invalidates any updated asset or generated files and resets their `updated` state.
341
+ * This function also clears the server application cache when necessary.
342
+ *
343
+ * @returns A list of files that were updated and invalidated.
344
+ */
345
+ async function invalidateUpdatedFiles(normalizePath, generatedFiles, assetFiles, server) {
339
346
  const updatedFiles = [];
340
347
  // Invalidate any updated asset
341
348
  for (const [file, record] of assetFiles) {
@@ -363,13 +370,21 @@ async function handleUpdate(normalizePath, generatedFiles, assetFiles, server, s
363
370
  const updatedModules = server.moduleGraph.getModulesByFile(normalizePath((0, node_path_1.join)(server.config.root, file)));
364
371
  updatedModules?.forEach((m) => server.moduleGraph.invalidateModule(m));
365
372
  }
366
- if (!updatedFiles.length) {
367
- return;
368
- }
369
373
  if (destroyAngularServerAppCalled) {
370
374
  // Trigger module evaluation before reload to initiate dependency optimization.
371
375
  await server.ssrLoadModule('/main.server.mjs');
372
376
  }
377
+ return updatedFiles;
378
+ }
379
+ /**
380
+ * Handles updates for the client by sending HMR or full page reload commands
381
+ * based on the updated files. It also ensures proper tracking of component styles and determines if
382
+ * a full reload is needed.
383
+ */
384
+ function handleUpdate(server, serverOptions, logger, componentStyles, updatedFiles) {
385
+ if (!updatedFiles.length) {
386
+ return;
387
+ }
373
388
  if (serverOptions.hmr) {
374
389
  if (updatedFiles.every((f) => f.endsWith('.css'))) {
375
390
  let requiresReload = false;
@@ -593,6 +608,7 @@ async function setupServer(serverOptions, outputFiles, assets, preserveSymlinks,
593
608
  componentStyles,
594
609
  templateUpdates,
595
610
  ssrMode,
611
+ resetComponentUpdates: () => templateUpdates.clear(),
596
612
  }),
597
613
  (0, plugins_1.createRemoveIdPrefixPlugin)(externalMetadata.explicitBrowser),
598
614
  await (0, plugins_1.createAngularSsrTransformPlugin)(serverOptions.workspaceRoot),
@@ -7,4 +7,4 @@
7
7
  */
8
8
  import type { Connect, ViteDevServer } from 'vite';
9
9
  import { AngularMemoryOutputFiles } from '../utils';
10
- export declare function createAngularIndexHtmlMiddleware(server: ViteDevServer, outputFiles: AngularMemoryOutputFiles, indexHtmlTransformer: ((content: string) => Promise<string>) | undefined): Connect.NextHandleFunction;
10
+ export declare function createAngularIndexHtmlMiddleware(server: ViteDevServer, outputFiles: AngularMemoryOutputFiles, resetComponentUpdates: () => void, indexHtmlTransformer: ((content: string) => Promise<string>) | undefined): Connect.NextHandleFunction;
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.createAngularIndexHtmlMiddleware = createAngularIndexHtmlMiddleware;
11
11
  const node_path_1 = require("node:path");
12
12
  const utils_1 = require("../utils");
13
- function createAngularIndexHtmlMiddleware(server, outputFiles, indexHtmlTransformer) {
13
+ function createAngularIndexHtmlMiddleware(server, outputFiles, resetComponentUpdates, indexHtmlTransformer) {
14
14
  return function angularIndexHtmlMiddleware(req, res, next) {
15
15
  if (!req.url) {
16
16
  next();
@@ -29,6 +29,8 @@ function createAngularIndexHtmlMiddleware(server, outputFiles, indexHtmlTransfor
29
29
  next();
30
30
  return;
31
31
  }
32
+ // A request for the index indicates a full page reload request.
33
+ resetComponentUpdates();
32
34
  server
33
35
  .transformIndexHtml(req.url, Buffer.from(rawHtml).toString('utf-8'))
34
36
  .then(async (processedHtml) => {
@@ -14,9 +14,11 @@ exports.createAngularMemoryPlugin = createAngularMemoryPlugin;
14
14
  const node_assert_1 = __importDefault(require("node:assert"));
15
15
  const promises_1 = require("node:fs/promises");
16
16
  const node_path_1 = require("node:path");
17
+ const node_url_1 = require("node:url");
17
18
  const load_esm_1 = require("../../../utils/load-esm");
18
19
  const ANGULAR_PREFIX = '/@ng/';
19
20
  const VITE_FS_PREFIX = '/@fs/';
21
+ const FILE_PROTOCOL = 'file:';
20
22
  async function createAngularMemoryPlugin(options) {
21
23
  const { virtualProjectRoot, outputFiles, external } = options;
22
24
  const { normalizePath } = await (0, load_esm_1.loadEsmModule)('vite');
@@ -29,8 +31,16 @@ async function createAngularMemoryPlugin(options) {
29
31
  return;
30
32
  }
31
33
  // For SSR with component HMR, pass through as a virtual module
32
- if (ssr && source.startsWith(ANGULAR_PREFIX)) {
33
- return '\0' + source;
34
+ if (ssr && source.startsWith(FILE_PROTOCOL) && source.includes(ANGULAR_PREFIX)) {
35
+ // Vite will resolve these these files example:
36
+ // `file:///@ng/component?c=src%2Fapp%2Fapp.component.ts%40AppComponent&t=1737017253850`
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));
40
+ if (sourceWithoutRoot.startsWith(ANGULAR_PREFIX)) {
41
+ const [, query] = source.split('?', 2);
42
+ return `\0${sourceWithoutRoot}?${query}`;
43
+ }
34
44
  }
35
45
  // Prevent vite from resolving an explicit external dependency (`externalDependencies` option)
36
46
  if (external?.includes(source)) {
@@ -38,6 +38,7 @@ interface AngularSetupMiddlewaresPluginOptions {
38
38
  componentStyles: Map<string, ComponentStyleRecord>;
39
39
  templateUpdates: Map<string, string>;
40
40
  ssrMode: ServerSsrMode;
41
+ resetComponentUpdates: () => void;
41
42
  }
42
43
  export declare function createAngularSetupMiddlewaresPlugin(options: AngularSetupMiddlewaresPluginOptions): Plugin;
43
44
  export {};
@@ -46,7 +46,7 @@ function createAngularSetupMiddlewaresPlugin(options) {
46
46
  name: 'vite:angular-setup-middlewares',
47
47
  enforce: 'pre',
48
48
  async configureServer(server) {
49
- const { indexHtmlTransformer, outputFiles, extensionMiddleware, assets, componentStyles, templateUpdates, ssrMode, } = options;
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
52
  server.middlewares.use((0, middlewares_1.createAngularComponentMiddleware)(templateUpdates));
@@ -64,7 +64,7 @@ function createAngularSetupMiddlewaresPlugin(options) {
64
64
  server.middlewares.use((0, middlewares_1.createAngularSsrInternalMiddleware)(server, indexHtmlTransformer));
65
65
  }
66
66
  server.middlewares.use(middlewares_1.angularHtmlFallbackMiddleware);
67
- server.middlewares.use((0, middlewares_1.createAngularIndexHtmlMiddleware)(server, outputFiles, indexHtmlTransformer));
67
+ server.middlewares.use((0, middlewares_1.createAngularIndexHtmlMiddleware)(server, outputFiles, resetComponentUpdates, indexHtmlTransformer));
68
68
  };
69
69
  },
70
70
  };
@@ -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.0';
13
+ const VERSION = '19.1.2';
14
14
  function hasCacheMetadata(value) {
15
15
  return (!!value &&
16
16
  typeof value === 'object' &&