vite-plugin-react-server
Version:
Vite plugin for React Server Components (RSC)
95 lines (85 loc) • 3.27 kB
text/typescript
import { configureRequestHandler } from "./configureRequestHandler.client.js";
import { MessageChannel } from "node:worker_threads";
import type { CreateReactWorkerServerFn } from "./types.js";
import { setMaxListenersOnPort, unrefPort } from "../stream/setMaxListeners.js";
/**
* Creates a React Worker Server that configures worker-based rendering
* Sets up middleware, HMR, and worker management like react-client/plugin.client.ts
*/
export const configureReactServer: CreateReactWorkerServerFn =
function _createReactWorkerServer({
server,
autoDiscoveredFiles,
userOptions,
configEnv,
hmrChannel,
onWorkerCreated,
serverManifest,
resolvedConfig,
}) {
const logger = server.config.customLogger || server.config.logger;
const verbose = userOptions.verbose || false;
if (verbose) {
logger?.info(
`[createReactWorkerServer] Configuring worker-based rendering`
);
}
// Set up restart listener for worker cleanup
server.ws.on("restart", async () => {
logger?.info(
"[createReactWorkerServer] Server restarting, shutting down worker..."
);
// Worker cleanup would be handled by the worker management
});
let currentWorker: any = null;
// Configure the worker request handler (sets up middleware)
const effectiveHmrChannel = (() => {
const channel = hmrChannel || new MessageChannel();
// Increase max listeners to prevent warnings during development
// This is a targeted fix for the memory leak warnings
// We need to set this on BOTH ports because listeners can be added to either side
// Use a high default (500) to accommodate large projects with many routes
// restartWorker will adjust this based on actual route count
const initialMaxListeners = 500;
setMaxListenersOnPort(channel.port1, initialMaxListeners);
setMaxListenersOnPort(channel.port2, initialMaxListeners);
unrefPort(channel.port1);
unrefPort(channel.port2);
return channel;
})();
configureRequestHandler({
server,
autoDiscoveredFiles,
userOptions,
configEnv,
hmrChannel: effectiveHmrChannel,
serverManifest,
resolvedConfig,
onWorkerCreated: (worker: any, restart?: () => Promise<void>) => {
currentWorker = worker;
if (onWorkerCreated) {
onWorkerCreated(worker, restart);
}
},
});
return {
sendHmrUpdate: (file: string, routes?: string[]) => {
if (currentWorker) {
// Notify the worker that a file changed. The worker's HMR_UPDATE
// handler invalidates the ModuleRunner cache so the next import
// re-fetches transformed code through Vite's pipeline.
const normalizedPath = file.replace(userOptions.projectRoot || server.config.root, '').replace(/^\/+/, '');
currentWorker.postMessage({
type: "HMR_UPDATE",
id: normalizedPath,
path: file,
routes: routes || [],
timestamp: Date.now(),
} satisfies any);
if (verbose) {
logger?.info(`[createReactWorkerServer] Sent HMR_UPDATE for ${file} to worker`);
}
}
},
};
};