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.
This commit is contained in:
Charles Lyding 2024-12-11 14:09:41 -05:00 committed by Charles
parent 10a5b8b6b8
commit 64f32c769f
2 changed files with 20 additions and 2 deletions

View File

@ -735,6 +735,7 @@ export async function setupServer(
await createAngularMemoryPlugin({
virtualProjectRoot,
outputFiles,
templateUpdates,
external: externalMetadata.explicitBrowser,
skipViteClient: serverOptions.liveReload === false && serverOptions.hmr === false,
}),

View File

@ -16,10 +16,13 @@ import { AngularMemoryOutputFiles } from '../utils';
interface AngularMemoryPluginOptions {
virtualProjectRoot: string;
outputFiles: AngularMemoryOutputFiles;
templateUpdates?: ReadonlyMap<string, string>;
external?: string[];
skipViteClient?: boolean;
}
const ANGULAR_PREFIX = '/@ng/';
export async function createAngularMemoryPlugin(
options: AngularMemoryPluginOptions,
): Promise<Plugin> {
@ -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;