Skip to content

Commit 4d9cd10

Browse files
committed
fix(@angular/build): prevent full page reload on HMR updates with SSR enabled
This commit resolves an issue where HMR would incorrectly trigger a full page reload when used with SSR. Closes angular#29372
1 parent 612da79 commit 4d9cd10

File tree

2 files changed

+35
-35
lines changed

2 files changed

+35
-35
lines changed

packages/angular/build/src/builders/application/build-action.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ function* emitOutputResults(
295295

296296
if (needFile) {
297297
// Updates to non-JS files must signal an update with the dev server
298-
if (!/(?:\.js|\.map)?$/.test(file.path)) {
298+
if (!/(?:\.m?js|\.map)?$/.test(file.path)) {
299299
incrementalResult.background = false;
300300
}
301301

packages/angular/build/src/builders/dev-server/vite-server.ts

+34-34
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ export async function* serveWithVite(
218218
}
219219

220220
let needClientUpdate = true;
221+
const componentUpdateIds: string[] = [];
222+
221223
switch (result.kind) {
222224
case ResultKind.Full:
223225
if (result.detail?.['htmlIndexPath']) {
@@ -250,11 +252,6 @@ export async function* serveWithVite(
250252
);
251253
}
252254

253-
// Invalidate SSR module graph to ensure that only new rebuild is used and not stale component updates
254-
if (server && browserOptions.ssr && templateUpdates.size > 0) {
255-
server.moduleGraph.invalidateAll();
256-
}
257-
258255
// Clear stale template updates on code rebuilds
259256
templateUpdates.clear();
260257

@@ -302,28 +299,14 @@ export async function* serveWithVite(
302299
server,
303300
'Builder must provide an initial full build before component update results.',
304301
);
305-
306-
// Invalidate SSR module graph to ensure that new component updates are used
307-
// TODO: Use fine-grained invalidation of only the component update modules
308-
if (browserOptions.ssr) {
309-
server.moduleGraph.invalidateAll();
310-
const { ɵresetCompiledComponents } = (await server.ssrLoadModule('/main.server.mjs')) as {
311-
ɵresetCompiledComponents: () => void;
312-
};
313-
ɵresetCompiledComponents();
314-
}
315-
316302
for (const componentUpdate of result.updates) {
317303
if (componentUpdate.type === 'template') {
304+
componentUpdateIds.push(componentUpdate.id);
318305
templateUpdates.set(componentUpdate.id, componentUpdate.content);
319-
server.ws.send('angular:component-update', {
320-
id: componentUpdate.id,
321-
timestamp: Date.now(),
322-
});
323306
}
324307
}
325-
context.logger.info('Component update sent to client(s).');
326-
continue;
308+
309+
break;
327310
default:
328311
context.logger.warn(`Unknown result kind [${(result as Result).kind}] provided by build.`);
329312
continue;
@@ -367,17 +350,17 @@ export async function* serveWithVite(
367350
]),
368351
];
369352

370-
if (needClientUpdate) {
371-
await handleUpdate(
372-
normalizePath,
373-
generatedFiles,
374-
assetFiles,
375-
server,
376-
serverOptions,
377-
context.logger,
378-
componentStyles,
379-
);
380-
}
353+
await handleUpdate(
354+
normalizePath,
355+
generatedFiles,
356+
assetFiles,
357+
server,
358+
serverOptions,
359+
context.logger,
360+
componentStyles,
361+
componentUpdateIds,
362+
needClientUpdate,
363+
);
381364
} else {
382365
const projectName = context.target?.project;
383366
if (!projectName) {
@@ -491,6 +474,8 @@ async function handleUpdate(
491474
serverOptions: NormalizedDevServerOptions,
492475
logger: BuilderContext['logger'],
493476
componentStyles: Map<string, ComponentStyleRecord>,
477+
componentUpdateIds: string[],
478+
needClientUpdate: boolean,
494479
): Promise<void> {
495480
const updatedFiles: string[] = [];
496481

@@ -531,7 +516,11 @@ async function handleUpdate(
531516
updatedModules?.forEach((m) => server.moduleGraph.invalidateModule(m));
532517
}
533518

534-
if (!updatedFiles.length) {
519+
if (!needClientUpdate) {
520+
return;
521+
}
522+
523+
if (!updatedFiles.length && !componentUpdateIds.length) {
535524
return;
536525
}
537526

@@ -541,6 +530,17 @@ async function handleUpdate(
541530
}
542531

543532
if (serverOptions.hmr) {
533+
for (const id of componentUpdateIds) {
534+
server.ws.send('angular:component-update', {
535+
id,
536+
timestamp: Date.now(),
537+
});
538+
}
539+
540+
if (componentUpdateIds.length) {
541+
logger.info('Component update sent to client(s).');
542+
}
543+
544544
if (updatedFiles.every((f) => f.endsWith('.css'))) {
545545
let requiresReload = false;
546546
const timestamp = Date.now();

0 commit comments

Comments
 (0)