UNPKG

vite-plugin-react-server

Version:
115 lines (105 loc) 2.89 kB
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'); } }