Skip to content

Commit

Permalink
fix(@angular/build): provide component HMR update modules to dev-serv…
Browse files Browse the repository at this point in the history
…er 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 64f32c7)
  • Loading branch information
clydin committed Dec 11, 2024
1 parent 4203efb commit 376ee99
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,7 @@ export async function setupServer(
await createAngularMemoryPlugin({
virtualProjectRoot,
outputFiles,
templateUpdates,
external: externalMetadata.explicitBrowser,
skipViteClient: serverOptions.liveReload === false && serverOptions.hmr === false,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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
Expand All @@ -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;
Expand Down

0 comments on commit 376ee99

Please sign in to comment.