vite-plugin-react-server
Version:
Vite plugin for React Server Components (RSC)
184 lines (164 loc) • 5.96 kB
text/typescript
import type { CreateHandlerOptions, PanicThreshold } from "../types.js";
import { cleanObject } from "./cleanObject.js";
import { processForSerialization } from "./serializeUserOptions.js";
/**
* Serializable handler options that can be safely passed to workers
*
* This extracts only the serializable parts of CreateHandlerOptions,
* excluding functions, React components, and other non-serializable data.
*
* WHAT'S INCLUDED:
* - All primitive values (strings, numbers, booleans)
* - Configuration objects (build, userOptions, etc.)
* - File paths and URLs
* - CSS data (cssFiles, globalCss)
*
* WHAT'S EXCLUDED:
* - React components (PageComponent, RootComponent, HtmlComponent)
* - Functions (loader, normalizer, onEvent, onMetrics)
* - Logger instances
* - Module IDs and autoDiscover functions
*/
export interface SerializableHandlerOptions {
// Core identification
id?: string;
route: string;
url: string;
// File paths
pagePath: string;
propsPath?: string;
rootPath?: string;
htmlPath?: string;
// Export names
pageExportName: string;
propsExportName: string;
rootExportName: string;
htmlExportName: string;
// Module configuration
projectRoot: string;
moduleRootPath: string;
moduleBaseURL: string;
moduleBasePath: string;
moduleBase?: string;
publicOrigin: string;
// Build configuration
build: CreateHandlerOptions["build"];
dev: CreateHandlerOptions["dev"];
// CSS configuration
css: CreateHandlerOptions["css"];
// Auto-discovery configuration
autoDiscover?: CreateHandlerOptions["autoDiscover"]
// CSS data
cssFiles?: Map<string, any>;
globalCss?: Map<string, any>;
// Page props (must be serializable)
pageProps: any;
// Panic threshold
panicThreshold: PanicThreshold;
// Timeouts
htmlTimeout?: number;
// Stream options
clientPipeableStreamOptions?: Omit<NonNullable<CreateHandlerOptions["clientPipeableStreamOptions"]>, `on${string}` | 'filterStackFrame'>;
serverPipeableStreamOptions?: Omit<NonNullable<CreateHandlerOptions["serverPipeableStreamOptions"]>, `on${string}`>;
}
/**
* Creates serializable handler options from full CreateHandlerOptions
*
* This function strips out non-serializable parts (React components, functions)
* and returns only the data that can be safely passed to workers.
*
* @param options - Full CreateHandlerOptions object
* @returns Serializable options for worker communication
*/
export function createSerializableHandlerOptions(
options: Partial<CreateHandlerOptions>
): SerializableHandlerOptions {
const {
// Extract serializable parts
id,
route,
url,
pagePath,
propsPath,
rootPath,
htmlPath,
pageExportName,
propsExportName,
rootExportName,
htmlExportName,
projectRoot,
moduleRootPath,
moduleBaseURL,
moduleBasePath,
moduleBase,
build,
cssFiles,
globalCss,
pageProps,
css,
autoDiscover,
clientPipeableStreamOptions,
serverPipeableStreamOptions,
...rest
} = options;
const result: any = {
route: route || "",
url: url || "",
};
// Only include properties if they exist
if (typeof id === 'string') result.id = id;
if (typeof pagePath === 'string') result.pagePath = pagePath;
if (typeof propsPath === 'string') result.propsPath = propsPath;
if (typeof rootPath === 'string') result.rootPath = rootPath;
if (typeof htmlPath === 'string') result.htmlPath = htmlPath;
if (typeof pageExportName === 'string') result.pageExportName = pageExportName;
if (typeof propsExportName === 'string') result.propsExportName = propsExportName;
if (typeof rootExportName === 'string') result.rootExportName = rootExportName;
if (typeof htmlExportName === 'string') result.htmlExportName = htmlExportName;
if (typeof projectRoot === 'string') result.projectRoot = projectRoot;
if (typeof moduleRootPath === 'string') result.moduleRootPath = moduleRootPath;
if (typeof moduleBaseURL === 'string') result.moduleBaseURL = moduleBaseURL;
if (typeof moduleBasePath === 'string') result.moduleBasePath = moduleBasePath;
if (typeof moduleBase === 'string') result.moduleBase = moduleBase;
if (build != null) {
// Clean the build object to remove functions that can't be cloned
const cleanedBuild = cleanObject(build, new Set([
"entryFile",
"chunkFile",
"assetFile"
]));
result.build = processForSerialization(cleanedBuild);
}
// Clean the entire options object to remove other non-serializable functions
const cleanedOptions = cleanObject(rest, new Set([
"normalizer",
"loader",
"onEvent",
"onMetrics"
]));
const processedRest = processForSerialization(cleanedOptions);
if (css != null) result.css = css;
if (autoDiscover != null) {
// Clean the autoDiscover object to remove functions that can't be cloned
const cleanedAutoDiscover = cleanObject(autoDiscover);
result.autoDiscover = processForSerialization(cleanedAutoDiscover);
}
if (cssFiles != null) result.cssFiles = cssFiles;
if (globalCss != null) result.globalCss = globalCss;
if (pageProps != null) result.pageProps = pageProps;
if (clientPipeableStreamOptions != null) {
// Use the existing helper to clean the object - this will handle all non-function properties
const cleanedClientOptions = cleanObject(clientPipeableStreamOptions);
result.clientPipeableStreamOptions = processForSerialization(cleanedClientOptions);
}
if (serverPipeableStreamOptions != null) {
// Use the existing helper to clean the object - this will handle all non-function properties
const cleanedServerOptions = cleanObject(serverPipeableStreamOptions);
result.serverPipeableStreamOptions = processForSerialization(cleanedServerOptions);
}
// Include any other serializable properties using existing helper
return {
...result,
...processedRest,
};
}