From 376ee996699a9610984f3d3e36b3331557dbeaca Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Wed, 11 Dec 2024 14:09:41 -0500 Subject: [PATCH] fix(@angular/build): provide component HMR update modules to dev-server SSR When using component HMR and SSR with the development server, the component update modules will now be available to the Vite server rendering. This prevents console errors due to missing component update paths. Additionally, it allows the server rendering to use the latest component templates if those have been changed before a new rebuild has occurred. (cherry picked from commit 64f32c769f58b4e7306faf73fdae386a30f48a41) --- .../src/builders/dev-server/vite-server.ts | 1 + .../vite/plugins/angular-memory-plugin.ts | 21 +++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/angular/build/src/builders/dev-server/vite-server.ts b/packages/angular/build/src/builders/dev-server/vite-server.ts index 49c69d278cfd..04c0cf666b9f 100644 --- a/packages/angular/build/src/builders/dev-server/vite-server.ts +++ b/packages/angular/build/src/builders/dev-server/vite-server.ts @@ -751,6 +751,7 @@ export async function setupServer( await createAngularMemoryPlugin({ virtualProjectRoot, outputFiles, + templateUpdates, external: externalMetadata.explicitBrowser, skipViteClient: serverOptions.liveReload === false && serverOptions.hmr === false, }), diff --git a/packages/angular/build/src/tools/vite/plugins/angular-memory-plugin.ts b/packages/angular/build/src/tools/vite/plugins/angular-memory-plugin.ts index 0af30710f2a9..dc83f131f299 100644 --- a/packages/angular/build/src/tools/vite/plugins/angular-memory-plugin.ts +++ b/packages/angular/build/src/tools/vite/plugins/angular-memory-plugin.ts @@ -16,10 +16,13 @@ import { AngularMemoryOutputFiles } from '../utils'; interface AngularMemoryPluginOptions { virtualProjectRoot: string; outputFiles: AngularMemoryOutputFiles; + templateUpdates?: ReadonlyMap; external?: string[]; skipViteClient?: boolean; } +const ANGULAR_PREFIX = '/@ng/'; + export async function createAngularMemoryPlugin( options: AngularMemoryPluginOptions, ): Promise { @@ -30,7 +33,12 @@ export async function createAngularMemoryPlugin( name: 'vite:angular-memory', // Ensures plugin hooks run before built-in Vite hooks enforce: 'pre', - async resolveId(source, importer) { + async resolveId(source, importer, { ssr }) { + // For SSR with component HMR, pass through as a virtual module + if (ssr && source.startsWith(ANGULAR_PREFIX)) { + return '\0' + source; + } + // Prevent vite from resolving an explicit external dependency (`externalDependencies` option) if (external?.includes(source)) { // This is still not ideal since Vite will still transform the import specifier to @@ -51,7 +59,16 @@ export async function createAngularMemoryPlugin( return join(virtualProjectRoot, source); } }, - load(id) { + load(id, loadOptions) { + // For SSR component updates, return the component update module or empty if none + if (loadOptions?.ssr && id.startsWith(`\0${ANGULAR_PREFIX}`)) { + // Extract component identifier (first character is rollup virtual module null) + const requestUrl = new URL(id.slice(1), 'http://localhost'); + const componentId = requestUrl.searchParams.get('c'); + + return (componentId && options.templateUpdates?.get(componentId)) ?? ''; + } + const [file] = id.split('?', 1); const relativeFile = '/' + normalizePath(relative(virtualProjectRoot, file)); const codeContents = outputFiles.get(relativeFile)?.contents;