vite-plugin-react-server
Version:
Vite plugin for React Server Components (RSC)
115 lines (105 loc) • 2.89 kB
text/typescript
import type React from "react";
import { createFromFetch } from "react-server-dom-esm/client.browser";
import { createCallServer } from "./createCallServer.js";
import { env } from "./env.js";
import { createPageURL } from "./urls.js";
export function createReactFetcher({
moduleBaseURL = env.BASE_URL,
publicOrigin = env.PUBLIC_ORIGIN,
url = window.location.pathname,
indexRSC = "index.rsc",
headers = {
Accept: "text/x-component",
},
}: {
url?: string;
moduleBaseURL?: string;
publicOrigin?: string;
indexRSC?: string;
headers?: HeadersInit;
} = {}): PromiseLike<React.ReactNode> {
const parsedURL = createPageURL(
moduleBaseURL,
publicOrigin,
env.DEV
)(url, indexRSC);
return createFromFetch(
fetch(parsedURL.indexRSC, {
headers: headers,
}),
{
callServer: createCallServer(parsedURL.moduleBaseURL),
moduleBaseURL: parsedURL.moduleBaseURL,
}
);
}
/** HMR event name used by the plugin */
export const RSC_HMR_EVENT = 'vite-plugin-react-server:server-component-update';
/** Data sent with RSC HMR events */
export interface RscHmrData {
file: string;
path: string;
}
/**
* Set up HMR for React Server Components (non-React API).
*
* For React components, use `useRscHmr()` hook instead.
*
* @example
* ```tsx
* import { setupRscHmr } from 'vite-plugin-react-server/utils';
*
* // Default: refetch current page's RSC stream (smart refresh)
* setupRscHmr();
*
* // Custom handler
* setupRscHmr({
* onUpdate: async (data) => {
* console.log('Changed:', data.file);
* myCustomRefetch();
* }
* });
* ```
*/
export function setupRscHmr(options: {
/**
* Custom handler for server component updates.
* If not provided, defaults to refetching the RSC stream for the current page.
* Set to `'reload'` for full page reload behavior.
*/
onUpdate?: ((data: RscHmrData) => void | Promise<void>) | 'reload';
/**
* Whether to log HMR events to console.
* @default true in development
*/
verbose?: boolean;
} = {}) {
const { onUpdate, verbose = env.DEV } = options;
if (typeof import.meta.hot === 'undefined') {
return;
}
import.meta.hot.on(RSC_HMR_EVENT, async (data: RscHmrData) => {
if (verbose) {
console.log('[RSC HMR] Server component updated:', data.file);
}
if (onUpdate === 'reload') {
window.location.reload();
return;
}
if (onUpdate) {
try {
await onUpdate(data);
} catch (error) {
console.error('[RSC HMR] Error in onUpdate handler:', error);
window.location.reload();
}
} else {
// Default: full page reload
// For smart RSC refetch, use useRscHmr() hook in your React tree
window.location.reload();
}
});
if (verbose) {
console.log('[RSC HMR] Listening for server component updates');
}
}