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/helpers/rsc-vite-framework/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
},
"dependencies": {
"@mjackson/node-fetch-server": "0.6.1",
"@react-router/serve": "workspace:*",
"compression": "^1.8.0",
"express": "^4.21.2",
"react": "^19.0.0",
Expand Down
25 changes: 0 additions & 25 deletions integration/helpers/vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,31 +373,6 @@ export const reactRouterServe = async ({
return () => serveProc.kill();
};

export const runStartScript = async ({
cwd,
port,
viteBase,
basename,
}: {
cwd: string;
port: number;
viteBase?: string;
basename?: string;
}) => {
let nodeBin = process.argv[0];
let proc = spawn(nodeBin, ["start.js"], {
cwd,
stdio: "pipe",
env: {
NODE_ENV: "production",
PORT: port.toFixed(0),
VITE_BASE: viteBase,
},
});
await waitForServer(proc, { port, basename });
return () => proc.kill();
};

export const wranglerPagesDev = async ({
cwd,
port,
Expand Down
84 changes: 84 additions & 0 deletions integration/react-router-serve-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { test, expect } from "@playwright/test";

import { PlaywrightFixture } from "./helpers/playwright-fixture.js";
import type { Fixture, AppFixture } from "./helpers/create-fixture.js";
import {
createAppFixture,
createFixture,
js,
} from "./helpers/create-fixture.js";
import { type TemplateName } from "./helpers/vite.js";

const templateNames = [
"vite-5-template",
"rsc-vite-framework",
] as const satisfies TemplateName[];

test.describe("react-router-serve", () => {
for (const templateName of templateNames) {
test.describe(`template: ${templateName}`, () => {
let fixture: Fixture;
let appFixture: AppFixture;

test.beforeEach(async ({ context }) => {
await context.route(/\.(data|rsc)$/, async (route) => {
await new Promise((resolve) => setTimeout(resolve, 50));
route.continue();
});
});

test.beforeAll(async () => {
fixture = await createFixture({
templateName,
useReactRouterServe: true,
files: {
"app/routes/_index.tsx": js`
import { useLoaderData, Link } from "react-router";

export function loader() {
return "pizza";
}

export default function Index() {
let data = useLoaderData();
return (
<div>
{data}
<Link to="/burgers">Other Route</Link>
</div>
)
}
`,

"app/routes/burgers.tsx": js`
export default function Index() {
return <div>cheeseburger</div>;
}
`,
},
});

// This creates an interactive app using playwright.
appFixture = await createAppFixture(fixture);
});

test.afterAll(() => {
appFixture.close();
});

test("should start and perform client side navigation", async ({
page,
}) => {
let app = new PlaywrightFixture(appFixture, page);
// You can test any request your app might get using `fixture`.
let response = await fixture.requestDocument("/");
expect(await response.text()).toMatch("pizza");

// If you need to test interactivity use the `app`
await app.goto("/");
await app.clickLink("/burgers");
await page.waitForSelector("text=cheeseburger");
});
});
}
});
69 changes: 0 additions & 69 deletions integration/remix-serve-test.ts

This file was deleted.

5 changes: 1 addition & 4 deletions integration/vite-basename-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
viteConfig,
dev,
viteDevCmd,
runStartScript,
reactRouterServe,
reactRouterConfig,
type TemplateName,
Expand Down Expand Up @@ -399,9 +398,7 @@ test.describe("Vite base + React Router basename", () => {
);
build({ cwd });
if (startServer !== false) {
stop = templateName.includes("rsc")
? await runStartScript({ cwd, port, viteBase: base, basename })
: await reactRouterServe({ cwd, port, basename });
stop = await reactRouterServe({ cwd, port, basename });
}
}

Expand Down
9 changes: 2 additions & 7 deletions integration/vite-css-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
createEditor,
dev,
build,
runStartScript,
reactRouterServe,
customDev,
EXPRESS_SERVER,
Expand Down Expand Up @@ -380,9 +379,7 @@ test.describe("Vite CSS", () => {
}
expect(stderrString).toBeFalsy();
expect(status).toBe(0);
stop = templateName.includes("rsc")
? await runStartScript({ cwd, port })
: await reactRouterServe({ cwd, port });
stop = await reactRouterServe({ cwd, port });
});
test.afterAll(() => stop());

Expand Down Expand Up @@ -446,9 +443,7 @@ test.describe("Vite CSS", () => {
});
expect(stderr.toString()).toBeFalsy();
expect(status).toBe(0);
stop = templateName.includes("rsc")
? await runStartScript({ cwd, port })
: await reactRouterServe({ cwd, port });
stop = await reactRouterServe({ cwd, port });
});
test.afterAll(() => stop());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { unstable_matchRSCServerRequest as matchRSCServerRequest } from "react-r

import routes from "virtual:react-router/unstable_rsc/routes";
import basename from "virtual:react-router/unstable_rsc/basename";
import unstable_reactRouterServeConfig from "virtual:react-router/unstable_rsc/react-router-serve-config";

export async function fetchServer(request: Request) {
return await matchRSCServerRequest({
Expand All @@ -30,6 +31,8 @@ export async function fetchServer(request: Request) {
});
}

export { unstable_reactRouterServeConfig };

export default async function handler(request: Request) {
const ssr = await import.meta.viteRsc.loadModule<
typeof import("./entry.ssr")
Expand Down
30 changes: 30 additions & 0 deletions packages/react-router-dev/vite/rsc/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as Typegen from "../../typegen";
import { readFileSync } from "fs";
import { readFile } from "fs/promises";
import path, { join, dirname } from "pathe";
import invariant from "../../invariant";
import {
type ConfigLoader,
type ResolvedReactRouterConfig,
Expand All @@ -31,6 +32,7 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
let configLoader: ConfigLoader;
let typegenWatcherPromise: Promise<Typegen.Watcher> | undefined;
let viteCommand: Vite.ConfigEnv["command"];
let resolvedViteConfig: Vite.ResolvedConfig;
let routeIdByFile: Map<string, string> | undefined;
let logger: Vite.Logger;

Expand Down Expand Up @@ -224,6 +226,9 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
},
};
},
configResolved(viteConfig) {
resolvedViteConfig = viteConfig;
},
async configureServer(viteDevServer) {
configLoader.onChange(
async ({
Expand Down Expand Up @@ -492,6 +497,30 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
return modules;
},
},
{
name: "react-router/rsc/virtual-react-router-serve-config",
resolveId(id) {
if (id === virtual.reactRouterServeConfig.id) {
return virtual.reactRouterServeConfig.resolvedId;
}
},
load(id) {
if (id === virtual.reactRouterServeConfig.resolvedId) {
const rscOutDir = resolvedViteConfig.environments.rsc?.build?.outDir;
invariant(rscOutDir, "RSC build directory config not found");
const clientOutDir =
resolvedViteConfig.environments.client?.build?.outDir;
invariant(clientOutDir, "Client build directory config not found");
const assetsBuildDirectory = Path.relative(rscOutDir, clientOutDir);
const publicPath = resolvedViteConfig.base;

return `export default ${JSON.stringify({
assetsBuildDirectory,
publicPath,
})};`;
}
},
},
validatePluginOrder(),
warnOnClientSourceMaps(),
];
Expand All @@ -503,6 +532,7 @@ const virtual = {
hmrRuntime: create("unstable_rsc/runtime"),
basename: create("unstable_rsc/basename"),
rscEntry: create("unstable_rsc/rsc-entry"),
reactRouterServeConfig: create("unstable_rsc/react-router-serve-config"),
};

function invalidateVirtualModules(viteDevServer: Vite.ViteDevServer) {
Expand Down
Loading
Loading