import { ComponentType, ReactElement, ReactNode } from "react"; import { Options } from "beasties"; import { HelmetProps } from "react-helmet-async"; //#region src/router-contract.d.ts interface LoaderFunctionArgs { request: Request; params: Record; } type LoaderFunction = (args: LoaderFunctionArgs) => Promise | unknown; interface RouterRouteRecord { path?: string; index?: boolean; id?: string; element?: ReactNode; Component?: ComponentType; loader?: LoaderFunction; action?: (...args: any[]) => unknown; children?: RouterRouteRecord[]; lazy?: () => Promise>; getStaticPaths?: () => string[] | Promise; entry?: string; locale?: string; } //#endregion //#region src/types.d.ts /** Minimal router shape kept for the public SSG context without a DOM-router dependency. */ interface Router { navigate?: (...args: never[]) => unknown; state?: unknown; [key: string]: unknown; } interface ViteReactSSGOptions { /** * Set the scripts' loading mode. Only works for `type="module"`. * * @default 'sync' */ script?: 'sync' | 'async' | 'defer' | 'async defer'; /** * Build format. * * @default 'esm' */ format?: 'esm' | 'cjs'; /** * The path of the main entry file (relative to the project root). * * @default 'src/main.ts' */ entry?: string; /** * The path of the index.html file (relative to the project root). * @default 'index.html' */ htmlEntry?: string; /** * Mock browser global variables (window, document, etc...) from SSG. * * @default false */ mock?: boolean; /** * Apply formatter to the generated index file. * * **It will cause Hydration Failed.** * * @default 'none' */ formatting?: 'prettify' | 'none'; /** * Vite environmeng mode. */ mode?: string; /** * Directory style of the output directory. * * flat: `/foo` -> `/foo.html` * nested: `/foo` -> `/foo/index.html` * * @default 'flat' */ dirStyle?: 'flat' | 'nested'; /** * Generate for all routes, including dynamic routes. * If enabled, you will need to configGure your serve * manually to handle dynamic routes properly. * * @default false */ includeAllRoutes?: boolean; /** * Options for the beasties package. * * @see https://github.com/danielroe/beasties */ beastiesOptions?: Options | false; /** * Critical CSS processing strategy. * * - `'zig-critters'` (default): Use zig-critters WASM for fast critical CSS inlining. * Falls back to **no critical CSS** if WASM is unavailable (no beasties fallback). * - `'beasties'`: Use beasties (JS-based) for critical CSS. Slower but always available. * - `false`: Skip critical CSS entirely. * * @default 'zig-critters' */ criticalCss?: 'zig-critters' | 'beasties' | false; criticalCssMaxSize?: number; /** * Enable turbo mode: use zig-critters WASM instead of beasties JS for critical CSS. * Falls back to beasties if the WASM binary is unavailable. * * @default false * @deprecated Use `criticalCss` instead. `turbo=true` is equivalent to `criticalCss: 'zig-critters'`. */ turbo?: boolean; /** * Custom function to modify the routes to do the SSG. * * Works only when `includeAllRoutes` is set to false. * * Defaults to a handler that filters out all the dynamic routes. * When passing your custom handler, you should also take care of the dynamic routes yourself. */ includedRoutes?: (paths: string[], routes: Readonly) => Promise | string[]; /** * Callback to be called before every page render. * * It can be used to transform the project's `index.html` file before passing it to the renderer. * * To do so, you can change the 'index.html' file contents (passed in through the `indexHTML` parameter), and return it. * The returned value will then be passed to renderer. */ onBeforePageRender?: (route: string, indexHTML: string, appCtx: Context) => Promise | string | null | undefined; /** * Callback to be called on every rendered page. * * It can be used to transform the current route's rendered HTML. * * To do so, you can transform the route's rendered HTML (passed in through the `renderedHTML` parameter), and return it. * The returned value will be used as the HTML of the route. */ onPageRendered?: (route: string, renderedHTML: string, appCtx: Context) => Promise | string | null | undefined; onFinished?: (dir: string) => Promise | void; /** * Callback invoked at each build sub-step boundary. * Used to collect step data for the pipeline summary. */ onStep?: (step: { name: string; duration: number; success: boolean; details?: string; metrics?: Record; }) => void; /** * The application's root container `id`. * * @default `root` */ rootContainerId?: string; /** * The size of the SSG processing queue. * * @default 20 */ concurrency?: number; /** * A mapping of route paths to their corresponding source file paths. */ routeToSourceFileMap?: Record; /** * The directory where SSG build cache is stored. */ cacheDir?: string; } interface ViteReactSSGContext { router?: HasRouter extends true ? Router : undefined; routes: HasRouter extends true ? Readonly : undefined; routerOptions: HasRouter extends true ? RouterOptions : undefined; initialState: Record; isClient: boolean; onSSRAppRendered: (cb: () => unknown) => void; triggerOnSSRAppRendered: (route: string, appHTML: string, appCtx: ViteReactSSGContext) => Promise; transformState?: (state: unknown) => unknown; /** * Current router path on SSG, `undefined` on client side. */ routePath?: string; base: string; getStyleCollector: (() => StyleCollector | Promise) | null; app?: HasRouter extends true ? never : ReactNode; routerType: 'remix' | 'single-page'; } interface ViteReactSSGClientOptions { transformState?: (state: unknown) => unknown; registerComponents?: boolean; /** * The application's root container query selector. * * @default `#root` */ rootContainer?: string | Element; /** * @deprecated This option is no longer needed */ ssrWhenDev?: boolean; getStyleCollector?: (() => StyleCollector | Promise) | null; useLegacyRender?: boolean; } interface CommonRouteOptions { filePath?: string; componentPath?: string; locale?: string; version?: string; collection?: string; /** * Used to obtain static resources through manifest * * **You are not required to use this field. It is only necessary when "prehydration style loss" occurs.** * * @example `src/pages/home.tsx` */ entry?: string; /** * The getStaticPaths() function should return an array of path * to determine which paths will be pre-rendered by vite-react-ssg. * * This function is only valid for dynamic route. * * @example () => ['path1', 'path2'] */ getStaticPaths?: () => string[] | Promise; } type NonIndexRouteRecord = Omit & { children?: RouteRecord[]; } & CommonRouteOptions; type IndexRouteRecord = NonIndexRouteRecord & { index: true; }; type RouteRecord = NonIndexRouteRecord | IndexRouteRecord; interface RouterFutureConfig { [key: string]: boolean | undefined; v7_fetcherPersist?: boolean; v7_normalizeFormMethod?: boolean; v7_partialHydration?: boolean; v7_relativeSplatPath?: boolean; v7_skipActionErrorRevalidation?: boolean; } interface RouterOptions { routes: RouteRecord[]; basename?: string; future?: Partial; customCreateRouter?: (...args: never[]) => Router; } interface StyleCollector { collect: (app: ReactElement) => ReactElement; toString: (html: string) => string; cleanup?: () => void; } declare module 'vite' { interface UserConfig { ssgOptions?: ViteReactSSGOptions; } } //#endregion //#region src/client/components/client-only.d.ts interface ClientOnlyProps { children?: () => React.ReactNode; fallback?: React.ReactNode; } declare function ClientOnly({ children, fallback }: ClientOnlyProps): React.ReactNode | null; //#endregion //#region src/client/components/head.d.ts type Props = HelmetProps & { children: ReactNode; }; declare function Head(props: Props): React.ReactNode; //#endregion //#region src/client/single-page.d.ts declare function ViteReactSSG(App: ReactNode, fn?: (context: ViteReactSSGContext) => Promise | void, options?: ViteReactSSGClientOptions): (client?: boolean, routePath?: string) => Promise>; //#endregion export { ClientOnly, Head, IndexRouteRecord, NonIndexRouteRecord, RouteRecord, Router, RouterFutureConfig, RouterOptions, StyleCollector, ViteReactSSG, ViteReactSSGClientOptions, ViteReactSSGContext, ViteReactSSGOptions };