rsbuild-plugin-react-router
Version:
React Router plugin for Rsbuild
112 lines (104 loc) • 3.57 kB
text/typescript
import { resolve } from 'pathe';
import type { ServerBuild } from 'react-router';
import { runPluginEffect } from './effect-runtime.js';
import { resolveServerBuildModuleEffect } from './server-build-resolution.js';
import type { Route } from './types.js';
/**
* Generates the server build template string.
*
* Note: Federation mode used to require async `import()` wrappers for entrypoints.
* With Rspack/@module-federation support for `experiments.asyncStartup`, the
* server build can always use static imports.
*/
interface ServerBuildOptions {
entryServerPath: string;
assetsBuildDirectory: string;
basename: string;
appDirectory: string;
ssr: boolean;
future?: unknown;
allowedActionOrigins?: string[];
prerender?: string[];
publicPath?: string;
serverManifestId?: string;
routeDiscovery:
| {
mode: 'lazy';
manifestPath?: string;
}
| {
mode: 'initial';
}
| undefined;
}
function generateStaticTemplate(
routes: Record<string, Route>,
options: ServerBuildOptions
): string {
const manifestId =
options.serverManifestId ?? 'virtual/react-router/server-manifest';
return `
import * as entryServer from ${JSON.stringify(options.entryServerPath)};
${Object.keys(routes)
.map((key, index) => {
const route = routes[key];
return `import * as route${index} from ${JSON.stringify(
`${resolve(options.appDirectory, route.file)}?react-router-route`
)};`;
})
.join('\n')}
export { default as assets } from ${JSON.stringify(manifestId)};
export const assetsBuildDirectory = ${JSON.stringify(
options.assetsBuildDirectory
)};
export const basename = ${JSON.stringify(options.basename)};
export const future = ${JSON.stringify(options.future ?? {})};
export const isSpaMode = ${!options.ssr};
export const ssr = ${options.ssr};
export const routeDiscovery = ${JSON.stringify(options.routeDiscovery)};
export const prerender = ${JSON.stringify(options.prerender ?? [])};
export const publicPath = ${JSON.stringify(options.publicPath ?? '/')};
export const entry = { module: entryServer };
export const allowedActionOrigins = ${JSON.stringify(options.allowedActionOrigins)};
export var routes = {};
${Object.keys(routes)
.map((key, index) => {
const route = routes[key];
return `routes[${JSON.stringify(key)}] = {
id: ${JSON.stringify(route.id)},
parentId: ${JSON.stringify(route.parentId)},
path: ${JSON.stringify(route.path)},
index: ${JSON.stringify(route.index)},
caseSensitive: ${JSON.stringify(route.caseSensitive)},
module: route${index}
};`;
})
.join('\n ')}
`;
}
/**
* Generates the server build module content
* @param routes The route manifest
* @param options Build options
* @returns The generated module content as a string
*/
function generateServerBuild(
routes: Record<string, Route>,
options: ServerBuildOptions & { federation?: boolean }
): string {
return generateStaticTemplate(routes, options);
}
export function resolveServerBuildModule(
buildModule: unknown,
source: string
): Promise<ServerBuild> {
return runPluginEffect(resolveServerBuildModuleEffect(buildModule, source));
}
export function resolveReactRouterServerBuild(
buildModule: unknown
): Promise<ServerBuild> {
return runPluginEffect(
resolveServerBuildModuleEffect(buildModule, 'Imported module')
);
}
export { generateServerBuild };