Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions integration/vite-presets-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ test.describe("Vite / presets", async () => {
"serverBundles",
"serverModuleFormat",
"ssr",
"unstable_rootRouteFile",
"unstable_routeConfig",
]);

Expand Down
17 changes: 12 additions & 5 deletions packages/react-router-dev/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,10 @@ export type ResolvedReactRouterConfig = Readonly<{
* SPA without server-rendering. Default's to `true`.
*/
ssr: boolean;
/**
* The absolute path to the root route file.
*/
unstable_rootRouteFile: string;
/**
* The resolved array of route config entries exported from `routes.ts`
*/
Expand Down Expand Up @@ -345,6 +349,8 @@ type Result<T> =
error: string;
};

type ConfigResult = Result<ResolvedReactRouterConfig>;

function ok<T>(value: T): Result<T> {
return { ok: true, value };
}
Expand All @@ -365,7 +371,7 @@ async function resolveConfig({
reactRouterConfigFile?: string;
skipRoutes?: boolean;
validateConfig?: ValidateConfigFunction;
}): Promise<Result<ResolvedReactRouterConfig>> {
}): Promise<ConfigResult> {
let reactRouterUserConfig: ReactRouterConfig = {};

if (reactRouterConfigFile) {
Expand Down Expand Up @@ -506,7 +512,7 @@ async function resolveConfig({
let appDirectory = Path.resolve(root, userAppDirectory || "app");
let buildDirectory = Path.resolve(root, userBuildDirectory);

let rootRouteFile = findEntry(appDirectory, "root");
let rootRouteFile = findEntry(appDirectory, "root", { absolute: true });
if (!rootRouteFile) {
let rootRouteDisplayPath = Path.relative(
root,
Expand Down Expand Up @@ -556,7 +562,7 @@ async function resolveConfig({
{
id: "root",
path: "",
file: rootRouteFile,
file: Path.relative(appDirectory, rootRouteFile),
children: result.routeConfig,
},
];
Expand Down Expand Up @@ -609,6 +615,7 @@ async function resolveConfig({
serverBundles,
serverModuleFormat,
ssr,
unstable_rootRouteFile: rootRouteFile,
unstable_routeConfig: routeConfig,
} satisfies ResolvedReactRouterConfig);

Expand All @@ -622,7 +629,7 @@ async function resolveConfig({
type ChokidarEventName = ChokidarEmitArgs[0];

type ChangeHandler = (args: {
result: Result<ResolvedReactRouterConfig>;
result: ConfigResult;
configCodeChanged: boolean;
routeConfigCodeChanged: boolean;
configChanged: boolean;
Expand All @@ -632,7 +639,7 @@ type ChangeHandler = (args: {
}) => void;

export type ConfigLoader = {
getConfig: () => Promise<Result<ResolvedReactRouterConfig>>;
getConfig: () => Promise<ConfigResult>;
onChange: (handler: ChangeHandler) => () => void;
close: () => Promise<void>;
};
Expand Down
1 change: 1 addition & 0 deletions packages/react-router-dev/vite/rsc/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
id,
viteCommand,
routeIdByFile,
rootRouteFile: config.unstable_rootRouteFile,
viteEnvironment: this.environment,
});
},
Expand Down
2 changes: 1 addition & 1 deletion packages/react-router-dev/vite/rsc/virtual-route-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function createVirtualRouteConfig({
const routeId = route.id || createRouteId(route.file, appDirectory);
routeIdByFile.set(routeFile, routeId);
code += `lazy: () => import(${JSON.stringify(
`${routeFile}?route-module${routeId === "root" ? "&root-route=true" : ""}`,
`${routeFile}?route-module`,
)}),`;

code += `id: ${JSON.stringify(routeId)},`;
Expand Down
49 changes: 39 additions & 10 deletions packages/react-router-dev/vite/rsc/virtual-route-modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,40 +97,54 @@ export function transformVirtualRouteModules({
code,
viteCommand,
routeIdByFile,
rootRouteFile,
viteEnvironment,
}: {
id: string;
code: string;
viteCommand: ViteCommand;
routeIdByFile: Map<string, string>;
rootRouteFile: string;
viteEnvironment: Vite.Environment;
}) {
if (isVirtualRouteModuleId(id) || routeIdByFile.has(id)) {
return createVirtualRouteModuleCode({
id,
code,
rootRouteFile,
viteCommand,
viteEnvironment,
});
}

if (isVirtualServerRouteModuleId(id)) {
return createVirtualServerRouteModuleCode({ id, code, viteEnvironment });
return createVirtualServerRouteModuleCode({
id,
code,
viteEnvironment,
});
}

if (isVirtualClientRouteModuleId(id)) {
return createVirtualClientRouteModuleCode({ id, code, viteCommand });
return createVirtualClientRouteModuleCode({
id,
code,
rootRouteFile,
viteCommand,
});
}
}

async function createVirtualRouteModuleCode({
id,
code: routeSource,
rootRouteFile,
viteCommand,
viteEnvironment,
}: {
id: string;
code: string;
rootRouteFile: string;
viteCommand: ViteCommand;
viteEnvironment: Vite.Environment;
}) {
Expand Down Expand Up @@ -183,7 +197,10 @@ async function createVirtualRouteModuleCode({
}
}

if (isRootRouteId(id) && !staticExports.includes("ErrorBoundary")) {
if (
isRootRouteFile({ id, rootRouteFile }) &&
!staticExports.includes("ErrorBoundary")
) {
code += `export { ErrorBoundary } from "${clientModuleId}";\n`;
}

Expand Down Expand Up @@ -236,10 +253,12 @@ function createVirtualServerRouteModuleCode({
function createVirtualClientRouteModuleCode({
id,
code: routeSource,
rootRouteFile,
viteCommand,
}: {
id: string;
code: string;
rootRouteFile: string;
viteCommand: ViteCommand;
}) {
const { staticExports, isServerFirstRoute, hasClientExports } =
Expand All @@ -256,7 +275,10 @@ function createVirtualClientRouteModuleCode({
const generatorResult = babel.generate(clientRouteModuleAst);
generatorResult.code = '"use client";' + generatorResult.code;

if (isRootRouteId(id) && !staticExports.includes("ErrorBoundary")) {
if (
isRootRouteFile({ id, rootRouteFile }) &&
!staticExports.includes("ErrorBoundary")
) {
const hasRootLayout = staticExports.includes("Layout");
generatorResult.code += `\nimport { createElement as __rr_createElement } from "react";\n`;
generatorResult.code += `import { UNSAFE_RSCDefaultRootErrorBoundary } from "react-router";\n`;
Expand Down Expand Up @@ -288,15 +310,11 @@ export function parseRouteExports(code: string) {
}

function getVirtualClientModuleId(id: string): string {
return `${id.split("?")[0]}?client-route-module${isRootRouteId(id) ? "&root-route=true" : ""}`;
return `${id.split("?")[0]}?client-route-module`;
}

function getVirtualServerModuleId(id: string): string {
return `${id.split("?")[0]}?server-route-module${isRootRouteId(id) ? "&root-route=true" : ""}`;
}

function isRootRouteId(id: string): boolean {
return /(\?|&)root-route=true(&|$)/.test(id);
return `${id.split("?")[0]}?server-route-module`;
}

function isVirtualRouteModuleId(id: string): boolean {
Expand All @@ -310,3 +328,14 @@ export function isVirtualClientRouteModuleId(id: string): boolean {
function isVirtualServerRouteModuleId(id: string): boolean {
return /(\?|&)server-route-module(&|$)/.test(id);
}

function isRootRouteFile({
id,
rootRouteFile,
}: {
id: string;
rootRouteFile: string;
}): boolean {
const filePath = id.split("?")[0];
return filePath === rootRouteFile;
}
Loading