UNPKG

vite-plugin-react-server

Version:
1,142 lines 43.8 kB
import type { Readable } from "node:stream"; import type { Worker, Serializable as WorkerSerializable } from "node:worker_threads"; import type React from "react"; import type { NormalizedOutputOptions, OutputBundle, PreRenderedAsset, PreRenderedChunk } from "rollup"; import type { PassThrough, Transform } from "stream"; import type { AliasOptions, BuildOptions, Connect, Logger, Manifest, Plugin, ResolveOptions, UserConfig, ViteDevServer } from "vite"; import type { serializeResolvedConfig, serializeResolvedUserConfig } from "./helpers/serializeUserOptions.js"; import type { AllowedDirectives, Program } from "react-server-loader/directives"; import type { LoaderConfig, TransformOptions } from "./loader/types.js"; import type { RenderMetrics, StreamMetrics, WorkerStartupMetrics, ModuleResolutionMetrics } from "./metrics/types.js"; import type { HtmlWorkerOutputMessage } from "./worker/html/types.js"; import type { RscChunkOutputMessage } from "./worker/rsc/types.js"; import type { WorkerMessage } from "./worker/types.js"; import type { Strategy } from "./orchestrator/createPluginOrchestrator.server.js"; import type { RenderToPipeableStreamOptions as ClientRenderToPipeableStreamOptions } from "react-dom/server"; import type { RenderToPipeableStreamOptions as ServerRenderToPipeableStreamOptions } from "react-server-dom-esm/server.node"; export type OnEvent<Interface extends ViteReactServerComponentsPlugin = ViteReactServerComponentsPlugin> = (event: PluginEvent<Interface>) => void; export type OnMetrics = (metrics: RenderMetrics<"rsc-full" | "rsc-headless" | "html"> | WorkerStartupMetrics | ModuleResolutionMetrics) => void; export type MessageHandler<T extends HtmlWorkerOutputMessage | RscChunkOutputMessage = HtmlWorkerOutputMessage | RscChunkOutputMessage> = (message: T) => void | Promise<unknown>; export type CreateInputNormalizerProps = { root: string; preserveModulesRoot?: string | undefined; removeExtension?: boolean | RegExp | string | ((path: string) => boolean); moduleBasePath: string | undefined; moduleBaseURL: string | undefined; }; export type Serializable = WorkerSerializable | Serializable[] | SerializableRecord; export type SerializableRecord = { [key: string]: Serializable; }; export type HmrState = { timestamp: number; invalidated: boolean; routes: string[]; }; export type RenderPageResult = { type: "skip"; reason?: unknown; html: { abort: (reason?: unknown) => void; pipe: <Writable extends NodeJS.WritableStream>(destination: Writable) => Writable; }; rsc: { abort: (reason?: unknown) => void; pipe: <Writable extends NodeJS.WritableStream>(destination: Writable) => Writable; }; metrics: { rscFull: RenderMetrics & { type: "rsc-full"; }; rscHeadless: RenderMetrics & { type: "rsc-headless"; }; html: RenderMetrics & { type: "html"; }; }; } | { type: "error"; error: unknown; metrics: { rscFull: RenderMetrics & { type: "rsc-full"; }; rscHeadless: RenderMetrics & { type: "rsc-headless"; }; html: RenderMetrics & { type: "html"; }; }; } | { type: "success"; html: { abort: (reason?: unknown) => void; pipe: <Writable extends NodeJS.WritableStream>(destination: Writable) => Writable; }; rsc: { abort: (reason?: unknown) => void; pipe: <Writable extends NodeJS.WritableStream>(destination: Writable) => Writable; }; metrics: { rscFull: RenderMetrics & { type: "rsc-full"; }; rscHeadless: RenderMetrics & { type: "rsc-headless"; }; html: RenderMetrics & { type: "html"; }; }; }; export type AutoDiscoveredFiles = ResolvedBuildPages & { workerPaths: Record<string, string>; serverEntry: Record<string, string> | null; clientEntry: Record<string, string>; clientInputs: Record<string, string>; staticInputs: Record<string, string>; serverInputs: Record<string, string>; serverActions: Record<string, string>; }; export type NormalizerInput = unknown; export type InputNormalizer = (input: NormalizerInput) => [string, string]; export type HtmlContent = { raw: string; transformed?: string; assets?: string[]; }; export type PartialPageData = { route: string; html?: { raw: string; transformed?: string; assets?: string[]; }; rsc?: { modules: unknown[]; content: string; }; }; export type InputNormalizerWorker = (input: NormalizerInput) => Promise<[string, string]>; export type ResolvedUserConfig = Required<Pick<UserConfig, "root" | "mode" | "build" | "resolve">> & Omit<UserConfig, "root" | "mode" | "build" | "resolve"> & { resolve: ResolveOptions; } & { build: NonNullable<Required<Pick<BuildOptions, "target" | "outDir" | "assetsDir" | "ssr" | "ssrEmitAssets" | "ssrManifest" | "manifest" | "rollupOptions" | "modulePreload">>> & Omit<BuildOptions, "target" | "outDir" | "assetsDir" | "ssr" | "ssrEmitAssets" | "ssrManifest" | "manifest">; }; export type SerializedUserConfig<T extends ResolvedUserConfig = ResolvedUserConfig> = ReturnType<typeof serializeResolvedUserConfig<T>>; export type SerializedUserOptions = { [k in keyof ResolvedUserOptions]: Extract<ResolvedUserOptions[k], Serializable | Record<string, Serializable>> extends infer X ? X extends never ? undefined : X : undefined; }; export type SerializedResolvedConfig = ReturnType<typeof serializeResolvedConfig>; export type StreamPluginOptionsClient = { outDir?: string; build?: BuildConfig; assetsDir?: string; projectRoot?: string; moduleBase?: string; moduleBasePath?: string; moduleBaseURL?: string; clientComponents?: AliasOptions; cssFiles?: AliasOptions; }; export type StringKeys = "moduleBase" | "moduleBasePath" | "moduleBaseURL" | "moduleRootPath" | "projectRoot" | "pageExportName" | "propsExportName" | "htmlWorkerPath" | "rscWorkerPath" | "loaderPath" | "reactLoaderPath" | "cssLoaderPath" | "envLoaderPath" | "clientEntry" | "serverEntry" | "publicOrigin"; export type NumberKeys = "rscTimeout" | "htmlTimeout" | "htmlWorkerStartupTimeout" | "rscWorkerStartupTimeout" | "fileWriteTimeout" | "workerShutdownTimeout"; export type BooleanKeys = "verbose"; export type NestedConfigKeys = "build" | "autoDiscover" | "loader" | "css" | "pipeableStreamOptions" | "serverPipeableStreamOptions" | "clientPipeableStreamOptions"; export type EventKeys = "onMetrics" | "onEvent"; export type NormalizerKeys = "normalizer" | "moduleID"; export type ComponentKeys = "Html" | "Root"; export type SourceURLKeys = "Page" | "props"; export type OptKey = StringKeys | NumberKeys | BooleanKeys | EventKeys | NormalizerKeys | ComponentKeys | SourceURLKeys; export type AutoDiscoverConfig = { clientEntry: string; serverEntry: string; cssEntry: string; jsonEntry: string; htmlEntry: string; modulePattern: RegExp; serverPattern: RegExp; clientPattern: RegExp; pagePattern: RegExp; propsPattern: RegExp; cssPattern: RegExp; jsonPattern: RegExp; htmlPattern: RegExp; cssModulePattern: RegExp; vendorPattern: RegExp; nodePattern: RegExp; dotPattern: RegExp; virtualPattern: RegExp; rscPattern: RegExp; }; export type GenericModuleLoader = (id: string) => Promise<Record<string, unknown>>; export type BuildModuleLoader<Opt extends Pick<ResolvedUserOptions, "pageExportName" | "propsExportName"> = Pick<ResolvedUserOptions, "pageExportName" | "propsExportName">, T extends PagePropOpt = PagePropOpt> = <STR extends string, ID extends string = STR extends `${infer I extends string}${string}${string}` ? I : never, Special extends "?" | "#" | "" = STR extends `${string}${infer X extends "?" | "#"}${string}` ? X : "", Extra extends string = STR extends `${string}${string}${infer Y extends string}` ? Y : "">(moduleId: STR) => Promise<STR extends `${ID}${Special}${Extra}` ? `${Special}${Extra}` extends "?inline" ? { default: string; } : Extra extends Opt["pageExportName"] ? { [k in Extra]: (props: T) => unknown; } : Extra extends Opt["propsExportName"] ? { [k in Extra]: T; } : Extra extends string ? Special extends "#" ? { [k in Extra]: unknown; } : Record<string, unknown> : Record<string, unknown> : Record<string, unknown>>; export type InterfaceAwareBuildModuleLoader<Interface extends ViteReactServerComponentsPlugin = DefaultInterface, Opt extends Pick<ResolvedUserOptions, "pageExportName" | "propsExportName"> = Pick<ResolvedUserOptions, "pageExportName" | "propsExportName">> = BuildModuleLoader<Opt, Interface["PageProps"]>; export type StreamError = { code?: string; } & Error; export type PanicThreshold = "none" | "critical_errors" | "all_errors"; export type ResolvedUserOptions = { projectRoot: string; moduleBase: string; moduleBasePath: string; moduleBaseURL: string; moduleRootPath: string; publicOrigin: string; pageExportName: string; propsExportName: string; htmlExportName: string; rootExportName: string; htmlWorkerPath: string; rscWorkerPath: string; loaderPath: string; reactLoaderPath?: string; cssLoaderPath?: string; envLoaderPath?: string; verbose: boolean; rscTimeout: number; htmlTimeout: number; htmlWorkerStartupTimeout: number; rscWorkerStartupTimeout: number; fileWriteTimeout: number; workerShutdownTimeout: number; panicThreshold: PanicThreshold; availableEnvironments?: string[]; strategy?: Strategy; onEvent?: OnEvent<ViteReactServerComponentsPlugin> | undefined; props?: StreamPluginOptions["props"]; clientEntry?: string; serverEntry?: string; /** * Packages whose internal `"use client"` per-file directives should be * honored by the RSC pipeline (Chakra UI, MUI, Mantine, react-aria, …). * When set, the matching node_modules paths bypass the transformer's * node_modules early-return, get added to `optimizeDeps.exclude` so esbuild * doesn't strip directives, and get added to `resolve.noExternal` so they * land in the server bundle where the transform actually runs. */ clientPackages?: readonly string[]; Page: StreamPluginOptions["Page"]; Html: StreamPluginOptions["Html"]; Root: StreamPluginOptions["Root"]; normalizer: InputNormalizer; moduleID: ((id: string, sourceContent?: string, isClientByDirective?: boolean) => string) | undefined; onMetrics: OnMetrics | undefined; pipeableStreamOptions: any; serverPipeableStreamOptions?: any; clientPipeableStreamOptions?: any; autoDiscover: Required<AutoDiscoverConfig>; loader?: Required<LoaderConfig> | undefined; build: Required<BuildConfig>; dev: Required<DevConfig>; css: RootOptions<boolean>; components?: StreamPluginOptions["components"]; }; export type DirectiveOptions = Pick<TransformOptions, "verbose" | "panicThreshold" | "loader"> & { loader: Pick<Required<NonNullable<TransformOptions["loader"]>>, "isServerFunctionCode" | "isClientComponentCode" | "getDirectiveType" | "parse"> & { allowedDirectives: AllowedDirectives; }; logger?: Logger; }; export type RootOptions<InlineCSS extends InlineCssOpt = InlineCssOpt> = { inlineCss?: InlineCSS; inlineThreshold?: number; inlinePatterns?: RegExp[]; linkPatterns?: RegExp[]; }; export type CssContent<InlineCSS extends InlineCssOpt = InlineCssOpt> = InlineCSS extends true ? StyleCssProps : InlineCSS extends false ? LinkCssProps : InlineCSS extends undefined | boolean ? StyleCssProps | LinkCssProps : never; /** * Boxed component type for the Root */ export type CssComponentType<InlineCSS extends InlineCssOpt = InlineCssOpt, R = any> = (props: { cssFiles: Map<string, CssContent<InlineCSS>> | CssContent[]; }) => R; export type FileWriteEvent = { type: "file.write"; data: { path: string; fileType: "html" | "rsc"; route: string; stream: Readable; onComplete: () => Promise<void>; }; }; export type FileWriteDoneEvent = { type: "file.write.done"; data: { route: string; fileType: "html" | "rsc"; content: string; chunks: number; path: string; fileName: string; baseDir: string; routePath: string; }; }; export type RouteErrorEvent = { type: "route.error"; data: { route: string; error?: unknown | null; errorInfo?: { componentStack?: string | null; digest?: string | null; }; reason?: unknown; isPanic?: boolean; panicThreshold?: PanicThreshold; }; }; export type RouteShellErrorEvent = { type: "route.shellError"; data: { route: string; error: unknown; }; }; export type RoutePostponeEvent = { type: "route.postpone"; data: { route: string; reason?: unknown; }; }; export type RouteShellReadyEvent = { type: "route.shellReady"; data: { route: string; }; }; export type RouteAllReadyEvent = { type: "route.allReady"; data: { route: string; }; }; export type PropsLoadEvent = { type: "props.load"; data: { route: string; propsPath: string; props: unknown; }; }; export type CssProcessEvent<Interface extends ViteReactServerComponentsPlugin = DefaultInterface> = { type: "css.process"; data: InterfaceAwareCssContent<Interface>; }; export type BuildStartEvent = { type: "build.start"; data: { pages: string[]; files: AutoDiscoveredFiles; }; }; export type BuildWriteBundleEventServer = { type: "build.writeBundle.server"; data: { pages: string[]; options: NormalizedOutputOptions; bundle: OutputBundle; }; }; export type BuildWriteBundleEventClient = { type: "build.writeBundle.client"; data: { pages: string[]; options: NormalizedOutputOptions; bundle: OutputBundle; }; }; export type BuildWriteBundleEventStatic = { type: "build.writeBundle.static"; data: { pages: string[]; options: NormalizedOutputOptions; bundle: OutputBundle; }; }; export type BuildEventStaticSiteGenerationStart = { type: "build.ssg.start"; data: { pages: string[]; options: NormalizedOutputOptions; bundle: OutputBundle; }; }; export type BuildEventStaticSiteGenerationEnd = { type: "build.ssg.end"; data: { pages: string[]; options: NormalizedOutputOptions; bundle: OutputBundle; }; }; export type BuildWriteBundleEvent = BuildWriteBundleEventServer | BuildWriteBundleEventClient | BuildEventStaticSiteGenerationStart | BuildEventStaticSiteGenerationEnd | BuildWriteBundleEventStatic; export type PluginEvent<Interface extends ViteReactServerComponentsPlugin = ViteReactServerComponentsPlugin> = FileWriteEvent | FileWriteDoneEvent | RouteErrorEvent | RouteShellErrorEvent | RoutePostponeEvent | PropsLoadEvent | CssProcessEvent<Interface> | BuildStartEvent | BuildWriteBundleEvent | RouteShellReadyEvent | RouteAllReadyEvent; export type PluginEventType = PluginEvent["type"]; export interface StreamPluginOptions<Interface extends ViteReactServerComponentsPlugin = DefaultInterface> { projectRoot?: string; moduleBase: string; moduleBasePath?: string; moduleBaseURL?: string; moduleRootPath?: string; publicOrigin?: string; clientEntry?: string; serverEntry?: string; loader?: { importServerPath?: string; importClientPath?: string; registerClientReferenceName?: string; registerServerReferenceName?: string; serverDirective?: RegExpOpt; clientDirective?: RegExpOpt; directivePattern?: RegExpOpt; isServerFunctionCode?: (code: string, moduleId?: string) => boolean; isClientComponentCode?: (code: string, moduleId?: string) => boolean; isClientComponentByCode?: (code: string) => boolean; isClientComponentByName?: (moduleId: string) => boolean; moduleID?: (moduleId: string) => string; allowedDirectives?: string[] | AllowedDirectives; mode?: "development" | "production" | "test"; getDirectiveType?: (directive: string, moduleId?: string) => "client" | "server" | undefined; parse?: (source: string) => Promise<{ ast: Program; code: string; map?: { url: string; start: number; end: number; lines: number; } | null; }>; }; autoDiscover?: { clientEntry: string; serverEntry: string; cssEntry: string; jsonEntry: string; htmlEntry: string; /** * Pattern to match CSS files. If not provided, uses default pattern. * Provide either a string pattern or RegExp. * @example ```ts * autoDiscover: { * // String pattern * cssPattern: ".css$", * // Or RegExp pattern * cssPattern: /\.css$/ * } */ cssPattern?: RegExpOpt; /** * Pattern to match CSS module files. If not provided, uses default pattern. * Provide either a string pattern or RegExp. * @example ```ts * autoDiscover: { * // String pattern * cssModulePattern: ".css\\.js$", * // Or RegExp pattern * cssModulePattern: /\.css\.js$/ * } */ cssModulePattern?: RegExpOpt; /** * Pattern to match client component files. If not provided, uses default pattern. * Provide either a string pattern or RegExp. * @example ```ts * autoDiscover: { * // String pattern * clientPattern: ".client\\.(js|ts|jsx|tsx)$", * // Or RegExp pattern * clientPattern: /\.client\.(js|ts|jsx|tsx)$/ * } */ clientPattern?: RegExpOpt; /** * Pattern to match server function files. If not provided, uses default pattern. * Provide either a string pattern or RegExp. * @example ```ts * autoDiscover: { * // String pattern * serverPattern: ".server\\.(js|ts|jsx|tsx)$", * // Or RegExp pattern * serverPattern: /\.server\.(js|ts|jsx|tsx)$/ * } */ serverPattern?: RegExpOpt; /** * Pattern to match HTML files. If not provided, uses default pattern. * Provide either a string pattern or RegExp. * @example ```ts * autoDiscover: { * // String pattern * htmlPattern: ".html$", * // Or RegExp pattern * htmlPattern: /\.html$/ * } */ htmlPattern?: RegExpOpt; /** * Pattern to match JSON files. If not provided, uses default pattern. * Provide either a string pattern or RegExp. * @example ```ts * autoDiscover: { * // String pattern * jsonPattern: ".json$", * // Or RegExp pattern * jsonPattern: /\.json$/ * } */ jsonPattern?: RegExpOpt; /** * Pattern to match module files. If not provided, uses default pattern. * Provide either a string pattern or RegExp. * @example ```ts * autoDiscover: { * // String pattern * modulePattern: "\\.(js|ts|jsx|tsx)$", * // Or RegExp pattern * modulePattern: /\.(js|ts|jsx|tsx)$/ * } */ modulePattern?: RegExpOpt; /** * Pattern to match RSC files. If not provided, uses default pattern. * Provide either a string pattern or RegExp. * @example ```ts * autoDiscover: { * // String pattern * rscPattern: ".rsc$", * // Or RegExp pattern * rscPattern: /\.rsc$/ * } */ rscPattern?: RegExpOpt; /** * Pattern to match page files. If not provided, uses default pattern. * Provide either a string pattern or RegExp. * @example ```ts * autoDiscover: { * // String pattern * pagePattern: "[Pp]age\\.(js|ts|jsx|tsx)$", * // Or RegExp pattern * pagePattern: /[Pp]age\.(js|ts|jsx|tsx)$/ * } */ pagePattern?: RegExpOpt; /** * Pattern to match props files. If not provided, uses default pattern. * Provide either a string pattern or RegExp. * @example ```ts * autoDiscover: { * // String pattern * propsPattern: "[Pp]rops\\.(js|ts|jsx|tsx)$", * // Or RegExp pattern * propsPattern: /[Pp]rops\.(js|ts|jsx|tsx)$/ * } */ propsPattern?: RegExpOpt; /** * Pattern to match dot files. No interpolation support. * @example ```ts * autoDiscover: { * dotFiles: /^\.[^/]+$/ * } */ dotPattern?: RegExpOpt; /** * Pattern to match Node.js native modules. No interpolation support. * @example ```ts * autoDiscover: { * nodePattern: /.node/ * } */ nodePattern?: RegExpOpt; /** * Pattern to match vendor files. No interpolation support. * @example ```ts * autoDiscover: { * vendorPattern: /node_modules|_virtual/ * } */ vendorPattern?: RegExpOpt; /** * Pattern to match virtual files. No interpolation support. * @example ```ts * autoDiscover: { * virtualPattern: /^virtual:/ * } */ virtualPattern?: RegExpOpt; } | undefined; Page?: UrlOpt; props?: UrlOpt; htmlWorkerPath?: string; rscWorkerPath?: string; loaderPath?: string; reactLoaderPath?: string; cssLoaderPath?: string; envLoaderPath?: string; pageExportName?: Interface["PageExportName"]; propsExportName?: Interface["PropsExportName"]; htmlExportName?: Interface["HtmlExportName"]; rootExportName?: Interface["RootExportName"]; Html?: UrlOpt; Root?: UrlOpt; components?: { Html?: HtmlComponentType<Interface["PageProps"], Interface["As"], Interface["InlineCSS"], Interface["ReactType"]>; Root?: RootComponentType<Interface["PageProps"], Interface["As"], Interface["InlineCSS"], Interface["ReactType"]>; Page?: PageComponentType<Interface["PageProps"], Interface["ReactType"]>; }; build?: BuildConfig; dev?: DevConfig; css?: RootOptions<Interface["InlineCSS"]>; pipeableStreamOptions?: any; serverPipeableStreamOptions?: any; clientPipeableStreamOptions?: any; onMetrics?: OnMetrics; onEvent?: OnEvent<Interface>; normalizer?: InputNormalizer; moduleID?: (id: string, sourceContent?: string, isClientByDirective?: boolean) => string; verbose?: boolean; rscTimeout?: number; htmlTimeout?: number; htmlWorkerStartupTimeout?: number; rscWorkerStartupTimeout?: number; fileWriteTimeout?: number; workerShutdownTimeout?: number; panicThreshold?: PanicThreshold; } export type MultiPageHandlerOptions<Opt extends ResolvedUserOptions = ResolvedUserOptions> = Omit<CreateHandlerOptions<Opt>, "pagePath" | "route" | "cssFiles" | "propsPath" | "rootPath" | "htmlPath" | "pageProps" | "PageComponent" | "RootComponent" | "HtmlComponent">; export type CreateHandlerOptions<Opt extends Record<string, unknown> = ResolvedUserOptions, Interface extends ViteReactServerComponentsPlugin = DefaultInterface, R = Interface["ReactType"]> = Pick<Opt, "autoDiscover" | "css" | "pageExportName" | "propsExportName" | "rootExportName" | "htmlExportName" | "moduleBase" | "moduleRootPath" | "moduleBasePath" | "moduleBaseURL" | "publicOrigin" | "onEvent" | "onMetrics" | "projectRoot" | "normalizer" | "moduleID" | "verbose" | "components" | "panicThreshold" | "projectRoot" | "rscTimeout" | "htmlTimeout" | "fileWriteTimeout" | "workerShutdownTimeout" | "rscWorkerPath" | "htmlWorkerPath"> & { id?: string; /** ID of headless stream to reuse for efficiency */ reuseHeadlessStreamId?: string; /** Storage for headless stream reuse Map<id, { PageComponent: any, errored: boolean }> */ headlessStreamElements?: Map<string, { PageComponent: any; errored: boolean; }>; signal?: AbortSignal; logger: Logger; loader: BuildModuleLoader | GenericModuleLoader; pagePath: string; propsPath?: string; rootPath?: string; htmlPath?: string; pageProps?: Interface["PageProps"]; PageComponent?: PageComponentType<Interface["PageProps"], R> | typeof React.Fragment; RootComponent?: RootComponentType<Interface["PageProps"], Interface["As"], Interface["InlineCSS"], R> | typeof React.Fragment; HtmlComponent?: HtmlComponentType<Interface["PageProps"], Interface["As"], Interface["InlineCSS"], R> | typeof React.Fragment; route: string; url?: string; as?: Interface["As"]; manifest: Manifest; staticManifest?: Manifest; serverManifest?: Manifest; clientManifest?: Manifest; worker?: Worker; rscWorker?: Worker; htmlWorker?: Worker; server?: ViteDevServer; importedCss?: Set<string>; cssFiles: Map<string, InterfaceAwareCssContent<Interface>>; globalCss: Map<string, InterfaceAwareCssContent<Interface>>; serverPipeableStreamOptions?: ServerRenderToPipeableStreamOptions; clientPipeableStreamOptions?: ClientRenderToPipeableStreamOptions; rscStream?: import("node:stream").Readable; htmlStream?: import("node:stream").Readable; metrics?: import("./metrics/types.js").StreamMetrics; build: Pick<ResolvedUserOptions["build"], "outDir" | "pages" | "server" | "static" | "client" | "rscOutputPath" | "htmlOutputPath" | "assetsDir" | "preserveModulesRoot">; dev: Pick<ResolvedUserOptions["dev"], "useHtmlWorker" | "useRscWorker">; children?: React.ReactNode; }; export type ResolvePageOptions = { pagePath: string; pageExportName: string; url: string; }; export type ResolvePropsOptions = { propsPath: string; propsExportName: string; url: string; }; export type StreamResult = { type: "success"; stream: PassThrough; assets?: { css?: string[]; }; } | { type: "error"; error: unknown; } | { type: "skip"; }; export type RouteConfig = { path: string; pattern?: { page?: string; props?: string; }; paths?: { page: string; props: string; }; }; export type BuildOutput = { dir?: string; rsc?: string; ext?: string; }; export type BuildConfig = { useRscWorker?: boolean; useHtmlWorker?: boolean; pages?: string[] | (() => Promise<string[]> | string[]) | Promise<string[]>; assetsDir?: string; client?: string; server?: string; static?: string; api?: string; outDir?: string; hash?: string | { format?: "vite" | "hex" | "custom"; length?: number; characters?: string; prefix?: string; suffix?: string; }; preserveModulesRoot?: boolean; rscOutputPath?: string; htmlOutputPath?: string; entryFile?: (n: PreRenderedChunk, ssr: boolean, sourceContent?: string) => string; chunkFile?: (n: PreRenderedChunk, ssr: boolean, sourceContent?: string) => string; assetFile?: (n: PreRenderedAsset, ssr: boolean) => string; extensionMap?: Record<string, string>; moduleExtension?: string; jsExtension?: string; cssExtension?: string; htmlExtension?: string; jsonExtension?: string; rscExtension?: string; cssModuleExtension?: string; nodeExtension?: string; /** * Controls how pages are rendered during static generation. * * - `"parallel"` (default): Renders pages in concurrent batches for faster builds. * Use `batchSize` to control concurrency (default: 8). * - `"sequential"`: Renders pages one at a time. Slower but uses less memory * and produces deterministic output order. */ renderMode?: "parallel" | "sequential"; /** * Number of pages to render concurrently when `renderMode` is `"parallel"`. * Higher values use more memory but build faster. * @default 8 */ batchSize?: number; }; export type DevConfig = { useHtmlWorker?: boolean | undefined; useRscWorker?: boolean | undefined; }; export type RequestHandler = Connect.NextHandleFunction; export type RscServerModule = { /** * Get RSC data for a route * @param path - Route path (e.g. "/", "/about") * @returns Page component and props */ getRscData: (path: string) => Promise<{ /** Page component to render */ Page: React.ComponentType; /** Props to pass to the page */ props: unknown; }>; }; export type RegisterComponentMessage = { type: "REGISTER_COMPONENT"; id: string; code: string; }; export type RscBuildResult = string[]; export type ReactStreamPluginMeta = { timing: BuildTiming; }; export type BuildTiming = { start: number; configResolved?: number; buildStart?: number; buildEnd?: number; renderStart?: number; renderEnd?: number; closeBundle?: number; render?: number; total?: number; }; export type ResolvedBuildPages = { propsMap: Map<string, string>; pageMap: Map<string, string>; rootMap: Map<string, string>; htmlMap: Map<string, string>; /** * ## routeMap * * Maps props & page paths to routes * * @example * const routeMap = new Map<string, string[]>(); * routeMap.set("src/page/home/page.tsx", ["/", "/home"]); */ routeMap: Map<string, string[]>; /** * ## urlMap * * Maps urls to props & page paths * * @example * ```ts * const urlMap = new Map<string, { props?: string; page: string }>(); * urlMap.set("/", { props: "/props", page: "/page" }); * ``` */ urlMap: Map<string, { props?: string; page: string; root?: string; html?: string; }>; errors: unknown[]; }; export type ModuleId = string & { readonly __brand: unique symbol; }; export type PagePath = string & { readonly __brand: unique symbol; }; export interface DeserializedRegExp { source: string; flags: string; __isRegExp: boolean; } export type RegExpOpt = RegExp | string | DeserializedRegExp; export type UrlOpt = string | ((url: string) => string) | ((url: string) => Promise<string>); export type PageName = "Page"; export type PropsName = "props"; export type HtmlName = "Html"; export type RootName = "Root"; export type HtmlProps<PageProps extends ViteReactServerComponentsPlugin["PageProps"] = DefaultInterface["PageProps"], InlineCSS extends ViteReactServerComponentsPlugin["InlineCSS"] = DefaultInterface["InlineCSS"], As extends ViteReactServerComponentsPlugin["As"] = DefaultInterface["As"], R = DefaultInterface["ReactType"]> = { pageProps?: PageProps; Page: PageComponentType<PageProps, R>; route: string; url: string; projectRoot: string; moduleBase: string; moduleBaseURL: string; moduleBasePath: string; moduleRootPath: string; cssFiles: Map<string, CssContent<InlineCSS>>; manifest: Manifest; Root: RootComponentType<PageProps, As, InlineCSS, R> | typeof React.Fragment; globalCss: Map<string, CssContent<InlineCSS>>; as?: As; }; export type PageAsset = { type: "css" | "js"; path: string; parentUrl: string; }; type BaseCssProps = { as: string; id: string; }; export type LinkCssProps = BaseCssProps & { as: "link"; type?: never; children?: never; id: string; href: string; rel: "stylesheet"; precedence?: string; }; export type StyleCssProps = BaseCssProps & { as: "style"; type: "text/css"; children?: React.ReactNode; precedence?: never; rel?: never; href?: never; }; export type CssProps<InlineCSS extends InlineCssOpt = InlineCssOpt> = { cssFiles: Map<string, CssContent<InlineCSS>>; }; export type HtmlRenderState = { id: string; rscStream: PassThrough; htmlStream: PassThrough; progressStream: PassThrough; errorTransform: Transform; htmlChunks: string[]; pipeableStreamOptions: any; streamState: StreamMetrics; }; export type RenderPagesResult = { type: "error" | "success" | "skip"; error?: unknown; route?: string; completedRoutes: Set<string>; failedRoutes: Map<string, unknown>; results: Map<string, RenderPageResult>; }; export type HandlerAssets<InlineCSS extends InlineCssOpt = InlineCssOpt> = { css: CssContent<InlineCSS>[]; js: string[]; bootstrapModules: string[]; }; export type CreateHandlerResult<InlineCSS extends InlineCssOpt = InlineCssOpt> = { type: "success"; controller: AbortController; stream: PassThrough; assets: { css: CssContent<InlineCSS>[]; js: string[]; bootstrapModules: string[]; }; route: string; metrics: StreamMetrics; } | { type: "error"; error: unknown; } | { type: "skip"; }; export type LoaderContext = { format?: string; importAttributes?: Record<string, string>; conditions?: string[]; env?: { targetEnvironment?: "client" | "server" | "browser"; }; url: string; userOptions?: SerializedUserOptions; }; declare global { interface ImportMeta { cssModules?: Record<string, Record<string, string>>; } } export type VendorInteropConfig = { react: string; reactDOMServer: string; }; export type RSCClientBrowserInteropConfig = { createFromFetch: string; createFromReadableStream: string; createServerReference: string; createTemporaryReferenceSet: string; encodeReply: string; registerServerReference: string; }; export type RSCClientNodeInteropConfig = { createFromNodeStream: string; createServerReference: string; registerServerReference: string; }; export type RSCServerInteropConfig = { createTemporaryReferenceSet: string; decodeAction: string; decodeFormState: string; decodeReply: string; decodeReplyFromBusboy: string; registerClientReference: string; registerServerReference: string; renderToPipeableStream: string; unstable_prerenderToNodeStream: string; }; export type RSCInteropConfig = { client: { browser: { production: string; development: string; test: string; exports: RSCClientBrowserInteropConfig; }; node: { production: string; development: string; test: string; exports: RSCClientNodeInteropConfig; }; }; server: { production: string; development: string; test: string; exports: RSCServerInteropConfig; }; }; export type FlightTarget = "default" | "webpack" | "nextjs" | "react-server-dom-esm" | "react-server-dom-webpack" | "react-server-dom-parcel"; export type FlightConfig = { rsc: RSCInteropConfig; vendor: VendorInteropConfig; }; export type VitePluginMainFn = <Opt extends StreamPluginOptions<any> = StreamPluginOptions<any>>(options: Opt, strategy?: Strategy) => Plugin<Opt>[]; export type VitePluginMainAsyncFn = <Opt extends StreamPluginOptions<any> = StreamPluginOptions<any>>(options: Opt) => Promise<Plugin<Opt>[]>; export type VitePluginFn = <Opt extends StreamPluginOptions = StreamPluginOptions>(options: Opt) => Plugin; export type ComponentResolutionStrategy = "serializable-path" | "direct-import" | "worker-internal" | "external-reference"; export type SerializableComponentPath = string & { readonly __brand: "SerializableComponentPath"; }; export type ComponentResolutionConfig = { strategy: ComponentResolutionStrategy; path?: SerializableComponentPath; moduleId?: string; exportName?: string; }; export type ClientEnvironmentOptions = { PageComponent?: never; RootComponent?: never; HtmlComponent?: never; pageComponentConfig?: ComponentResolutionConfig; rootComponentConfig?: ComponentResolutionConfig; htmlComponentConfig?: ComponentResolutionConfig; pagePath?: string; rootPath?: string; htmlPath?: string; }; export type ServerEnvironmentOptions = { PageComponent?: CreateHandlerOptions["PageComponent"]; RootComponent?: CreateHandlerOptions["RootComponent"]; HtmlComponent?: CreateHandlerOptions["HtmlComponent"]; pageComponentConfig?: ComponentResolutionConfig; rootComponentConfig?: ComponentResolutionConfig; htmlComponentConfig?: ComponentResolutionConfig; pagePath?: string; rootPath?: string; htmlPath?: string; }; export type ReactStreamCommonOptions<Env extends "client" | "server" = "client" | "server", Handles extends keyof CreateHandlerOptions = never> = Omit<CreateHandlerOptions, Handles | "PageComponent" | "RootComponent" | "HtmlComponent" | "pagePath" | "rootPath" | "htmlPath"> & Partial<Pick<CreateHandlerOptions, Handles>> & (Env extends "client" ? ClientEnvironmentOptions : ServerEnvironmentOptions); export type ReactStreamHandlerFn<Env extends "client" | "server", Handles extends keyof CreateHandlerOptions, ReturnType> = (options: ReactStreamCommonOptions<Env, Handles>) => ReturnType; export type RscWorkerMessage = { pageComponentConfig?: ComponentResolutionConfig; rootComponentConfig?: ComponentResolutionConfig; htmlComponentConfig?: ComponentResolutionConfig; pagePath?: string; rootPath?: string; htmlPath?: string; route: string; url: string; pageProps?: Record<string, unknown>; cssFiles: Array<[string, unknown]>; manifest: Record<string, unknown>; PageComponent?: never; RootComponent?: never; HtmlComponent?: never; }; export type RscRenderOpt = WorkerMessage & { type: "INIT"; } & { dataPort: MessagePort; controlPort: MessagePort; options: Omit<CreateHandlerOptions<ResolvedUserOptions>, "onEvent" | "onMetrics" | "loader" | "build" | "autoDiscover" | "normalizer" | "moduleID" | "PageComponent" | "RootComponent" | "HtmlComponent" | "url" | "logger" | "cssFiles"> & { url?: string; pageComponentConfig?: ComponentResolutionConfig; rootComponentConfig?: ComponentResolutionConfig; htmlComponentConfig?: ComponentResolutionConfig; cssFiles: Array<[string, unknown]>; build: Omit<CreateHandlerOptions<ResolvedUserOptions>["build"], "entryFileNames" | "chunkFileNames" | "assetFileNames" | "pages"> & { pages: string[]; }; }; }; export type PluginComponentReference = { type: "plugin-component"; componentName: "Html" | "Root" | "Css"; modulePath: string; exportName: string; }; export type ResolvedComponent<T = unknown> = { type: "success"; component: T; source: "direct" | "resolved" | "plugin" | "worker-internal"; } | { type: "error"; error: Error; source: "direct" | "resolved" | "plugin" | "worker-internal"; }; export type WorkerComponentLoader = { loadComponent: (config: ComponentResolutionConfig) => Promise<ResolvedComponent>; loadPluginComponent: (reference: PluginComponentReference) => Promise<ResolvedComponent>; hasInternalComponent: (componentName: string) => boolean; }; export type { RenderMetrics, StreamMetrics, WorkerStartupMetrics, ModuleResolutionMetrics, }; export type InferReactType<R = React.ReactNode> = R; export type CustomInterface<R = React.ReactNode> = { ReactType: R; PageProps: any; As: any; PropsExportName: string; PageExportName: string; RootExportName: string; HtmlExportName: string; InlineCSS: undefined | boolean; }; declare global { interface ViteReactServerComponentsPlugin { PageProps: any; As: any; InlineCSS: undefined | boolean; ReactType: InferReactType; PropsExportName: string; PageExportName: string; RootExportName: string; HtmlExportName: string; } } export interface DefaultInterface<T extends React.ComponentProps<any> = React.ComponentProps<any>, As extends React.JSXElementConstructor<any> | keyof React.JSX.IntrinsicElements = React.JSXElementConstructor<any> | keyof React.JSX.IntrinsicElements> extends ViteReactServerComponentsPlugin { ReactType: InferReactType; PageProps: T; As: As; PropsExportName: PropsName; PageExportName: PageName; RootExportName: RootName; HtmlExportName: HtmlName; } export type PagePropOpt = DefaultInterface["PageProps"]; export type AsOpt = DefaultInterface["As"]; export type InlineCssOpt = DefaultInterface["InlineCSS"]; export type PageComponentType<PageProps extends ViteReactServerComponentsPlugin["PageProps"] = DefaultInterface["PageProps"], R = DefaultInterface["ReactType"]> = (props: PageProps) => R; export type RootComponentType<PageProps extends ViteReactServerComponentsPlugin["PageProps"] = DefaultInterface["PageProps"], As extends ViteReactServerComponentsPlugin["As"] = DefaultInterface["As"], InlineCSS extends ViteReactServerComponentsPlugin["InlineCSS"] = DefaultInterface["InlineCSS"], R = DefaultInterface["ReactType"]> = (props: RootProps<PageProps, InlineCSS, As, R>) => R; export type RootProps<PageProps extends ViteReactServerComponentsPlugin["PageProps"] = DefaultInterface["PageProps"], InlineCSS extends ViteReactServerComponentsPlugin["InlineCSS"] = DefaultInterface["InlineCSS"], As extends ViteReactServerComponentsPlugin["As"] = DefaultInterface["As"], R = DefaultInterface["ReactType"]> = { as: As; cssFiles?: Map<string, CssContent<InlineCSS>>; pageProps?: Omit<PageProps, "children">; Page: PageComponentType<Omit<PageProps, "children">, R>; id?: string; }; /** * Boxed component type for the Html component */ export type HtmlComponentType<T extends ViteReactServerComponentsPlugin["PageProps"] = DefaultInterface["PageProps"], As extends ViteReactServerComponentsPlugin["As"] = DefaultInterface["As"], InlineCSS extends ViteReactServerComponentsPlugin["InlineCSS"] = DefaultInterface["InlineCSS"], R = DefaultInterface["ReactType"]> = (props: HtmlProps<T, InlineCSS, As, R>) => R; export type InterfaceAwareCssContent<Interface extends ViteReactServerComponentsPlugin> = CssContent<Interface["InlineCSS"]>; export type InterfaceAwareRootOptions<Interface extends ViteReactServerComponentsPlugin> = RootOptions<Interface["InlineCSS"]>; export type InterfaceAwareCssComponentType<Interface extends ViteReactServerComponentsPlugin, R = Interface["ReactType"]> = CssComponentType<Interface["InlineCSS"], R>; export type InterfaceAwareCssProps<Interface extends ViteReactServerComponentsPlugin> = CssProps<Interface["InlineCSS"]>; export type InterfaceAwareHandlerAssets<Interface extends ViteReactServerComponentsPlugin> = HandlerAssets<Interface["InlineCSS"]>; export type InterfaceAwareCreateHandlerResult<Interface extends ViteReactServerComponentsPlugin> = CreateHandlerResult<Interface["InlineCSS"]>; export type VitePluginReactClientFn = <Opt extends StreamPluginOptions = StreamPluginOptions>(options: Opt) => Plugin[]; export type VitePluginReactServerFn = <Opt extends StreamPluginOptions = StreamPluginOptions>(options: Opt) => Plugin[]; //# sourceMappingURL=types.d.ts.map