Skip to content

Commit 34ee782

Browse files
Support Vite middleware mode in RSC Framework Mode (#14277)
1 parent 23b62b6 commit 34ee782

File tree

7 files changed

+216
-98
lines changed

7 files changed

+216
-98
lines changed

integration/helpers/vite.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,43 @@ export const EXPRESS_SERVER = (args: {
171171
base?: string;
172172
loadContext?: Record<string, unknown>;
173173
customLogic?: string;
174-
}) =>
175-
String.raw`
174+
templateName?: TemplateName;
175+
}) => {
176+
if (args.templateName?.includes("rsc")) {
177+
return String.raw`
178+
import { createRequestListener } from "@mjackson/node-fetch-server";
179+
import express from "express";
180+
181+
const viteDevServer =
182+
process.env.NODE_ENV === "production"
183+
? undefined
184+
: await import("vite").then(({ createServer }) =>
185+
createServer({
186+
server: {
187+
middlewareMode: true,
188+
},
189+
})
190+
);
191+
const app = express();
192+
193+
${args?.customLogic || ""}
194+
195+
if (viteDevServer) {
196+
app.use(viteDevServer.middlewares);
197+
} else {
198+
app.use(
199+
"/assets",
200+
express.static("build/client/assets", { immutable: true, maxAge: "1y" })
201+
);
202+
app.all("*", createRequestListener((await import("./build/server/index.js")).default));
203+
}
204+
205+
const port = ${args.port};
206+
app.listen(port, () => console.log('http://localhost:' + port));
207+
`;
208+
}
209+
210+
return String.raw`
176211
import { createRequestHandler } from "@react-router/express";
177212
import express from "express";
178213
@@ -212,6 +247,7 @@ export const EXPRESS_SERVER = (args: {
212247
const port = ${args.port};
213248
app.listen(port, () => console.log('http://localhost:' + port));
214249
`;
250+
};
215251

216252
type FrameworkModeViteMajorTemplateName =
217253
| "vite-5-template"

integration/vite-basename-test.ts

Lines changed: 111 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -90,47 +90,85 @@ const customServerFile = ({
9090
port,
9191
base,
9292
basename,
93+
templateName,
9394
}: {
9495
port: number;
9596
base?: string;
9697
basename?: string;
98+
templateName: TemplateName;
9799
}) => {
98100
base = base ?? "/mybase/";
99101
basename = basename ?? base;
100102

101-
return js`
102-
import { createRequestHandler } from "@react-router/express";
103-
import express from "express";
104-
105-
const viteDevServer =
106-
process.env.NODE_ENV === "production"
107-
? undefined
108-
: await import("vite").then(({ createServer }) =>
109-
createServer({
110-
server: {
111-
middlewareMode: true,
112-
},
113-
})
114-
);
103+
if (templateName.includes("rsc")) {
104+
return js`
105+
import { createRequestListener } from "@mjackson/node-fetch-server";
106+
import express from "express";
107+
108+
const viteDevServer =
109+
process.env.NODE_ENV === "production"
110+
? undefined
111+
: await import("vite").then(({ createServer }) =>
112+
createServer({
113+
server: {
114+
middlewareMode: true,
115+
},
116+
})
117+
);
118+
119+
const app = express();
120+
if (viteDevServer) {
121+
app.use(viteDevServer.middlewares);
122+
} else {
123+
app.use("${base}", express.static("build/client"));
124+
app.all(
125+
"${basename}*",
126+
createRequestListener((await import("./build/server/index.js")).default),
127+
);
128+
}
129+
app.get("*", (_req, res) => {
130+
res.setHeader("content-type", "text/html")
131+
res.end('React Router app is at <a href="${basename}">${basename}</a>');
132+
});
115133
116-
const app = express();
117-
app.use("${base}", viteDevServer?.middlewares || express.static("build/client"));
118-
app.all(
119-
"${basename}*",
120-
createRequestHandler({
121-
build: viteDevServer
122-
? () => viteDevServer.ssrLoadModule("virtual:react-router/server-build")
123-
: await import("./build/server/index.js"),
124-
})
125-
);
126-
app.get("*", (_req, res) => {
127-
res.setHeader("content-type", "text/html")
128-
res.end('React Router app is at <a href="${basename}">${basename}</a>');
129-
});
134+
const port = ${port};
135+
app.listen(port, () => console.log('http://localhost:' + port));
136+
`;
137+
} else {
138+
return js`
139+
import { createRequestHandler } from "@react-router/express";
140+
import express from "express";
141+
142+
const viteDevServer =
143+
process.env.NODE_ENV === "production"
144+
? undefined
145+
: await import("vite").then(({ createServer }) =>
146+
createServer({
147+
server: {
148+
middlewareMode: true,
149+
},
150+
})
151+
);
152+
153+
const app = express();
154+
app.use("${base}", viteDevServer?.middlewares || express.static("build/client"));
155+
app.all(
156+
"${basename}*",
157+
createRequestHandler({
158+
build: viteDevServer
159+
? () => viteDevServer.ssrLoadModule("virtual:react-router/server-build")
160+
: await import("./build/server/index.js"),
161+
})
162+
);
163+
app.get("*", (_req, res) => {
164+
res.setHeader("content-type", "text/html")
165+
res.end('React Router app is at <a href="${basename}">${basename}</a>');
166+
});
130167
131-
const port = ${port};
132-
app.listen(port, () => console.log('http://localhost:' + port));
133-
`;
168+
const port = ${port};
169+
app.listen(port, () => console.log('http://localhost:' + port));
170+
`;
171+
}
134172
};
135173

136174
test.describe("Vite base + React Router basename", () => {
@@ -279,11 +317,6 @@ test.describe("Vite base + React Router basename", () => {
279317
});
280318

281319
test.describe("express dev", async () => {
282-
test.skip(
283-
templateName.includes("rsc"),
284-
"RSC Framework Mode doesn't support Vite middleware mode yet",
285-
);
286-
287320
let port: number;
288321
let cwd: string;
289322
let stop: () => void;
@@ -301,7 +334,7 @@ test.describe("Vite base + React Router basename", () => {
301334
cwd = await createProject(
302335
{
303336
...(await configFiles({ port, base, basename, templateName })),
304-
"server.mjs": customServerFile({ port, basename }),
337+
"server.mjs": customServerFile({ port, basename, templateName }),
305338
...sharedFiles,
306339
},
307340
templateName,
@@ -408,11 +441,6 @@ test.describe("Vite base + React Router basename", () => {
408441
});
409442

410443
test.describe("express build", async () => {
411-
test.skip(
412-
templateName.includes("rsc"),
413-
"Vite build test is already using Express",
414-
);
415-
416444
let port: number;
417445
let cwd: string;
418446
let stop: () => void;
@@ -434,6 +462,7 @@ test.describe("Vite base + React Router basename", () => {
434462
port,
435463
base,
436464
basename,
465+
templateName,
437466
}),
438467
...sharedFiles,
439468
},
@@ -479,29 +508,46 @@ test.describe("Vite base + React Router basename", () => {
479508
page,
480509
}) => {
481510
port = await getPort();
482-
cwd = await createProject({
483-
...(await configFiles({
484-
templateName,
485-
port,
486-
base: "https://cdn.example.com/assets/",
487-
basename: "/app/",
488-
})),
489-
// Slim server that only serves basename (route) requests from the React Router handler
490-
"server.mjs": String.raw`
491-
import { createRequestHandler } from "@react-router/express";
492-
import express from "express";
493-
494-
const app = express();
495-
app.all(
496-
"/app/*",
497-
createRequestHandler({ build: await import("./build/server/index.js") })
498-
);
499-
500-
const port = ${port};
501-
app.listen(port, () => console.log('http://localhost:' + port));
502-
`,
503-
...sharedFiles,
504-
});
511+
cwd = await createProject(
512+
{
513+
...(await configFiles({
514+
templateName,
515+
port,
516+
base: "https://cdn.example.com/assets/",
517+
basename: "/app/",
518+
})),
519+
// Slim server that only serves basename (route) requests from the React Router handler
520+
"server.mjs": templateName.includes("rsc")
521+
? String.raw`
522+
import { createRequestListener } from "@mjackson/node-fetch-server";
523+
import express from "express";
524+
525+
const app = express();
526+
app.all(
527+
"/app/*",
528+
createRequestListener((await import("./build/server/index.js")).default)
529+
);
530+
531+
const port = ${port};
532+
app.listen(port, () => console.log('http://localhost:' + port));
533+
`
534+
: String.raw`
535+
import { createRequestHandler } from "@react-router/express";
536+
import express from "express";
537+
538+
const app = express();
539+
app.all(
540+
"/app/*",
541+
createRequestHandler({ build: await import("./build/server/index.js") })
542+
);
543+
544+
const port = ${port};
545+
app.listen(port, () => console.log('http://localhost:' + port));
546+
`,
547+
...sharedFiles,
548+
},
549+
templateName,
550+
);
505551

506552
build({ cwd });
507553
stop = await customDev({

integration/vite-css-test.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -292,11 +292,6 @@ test.describe("Vite CSS", () => {
292292
});
293293

294294
test.describe("express", async () => {
295-
test.fixme(
296-
templateName.includes("rsc"),
297-
"RSC Framework mode doesn't support Vite middleware mode yet",
298-
);
299-
300295
let port: number;
301296
let cwd: string;
302297
let stop: () => void;
@@ -313,7 +308,7 @@ test.describe("Vite CSS", () => {
313308
templateName,
314309
vanillaExtract: true,
315310
}),
316-
"server.mjs": EXPRESS_SERVER({ port }),
311+
"server.mjs": EXPRESS_SERVER({ port, templateName }),
317312
...files({ templateName }),
318313
},
319314
templateName,

integration/vite-hmr-hdr-test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,9 @@ test.describe("Vite HMR & HDR", () => {
6363
});
6464

6565
test("express", async ({ page, browserName, customDev }) => {
66-
test.skip(templateName.includes("rsc"), "RSC is not supported");
6766
let files: Files = async ({ port }) => ({
6867
"vite.config.js": await viteConfig.basic({ port, templateName }),
69-
"server.mjs": EXPRESS_SERVER({ port }),
68+
"server.mjs": EXPRESS_SERVER({ port, templateName }),
7069
"app/routes/_index.tsx": indexRoute,
7170
});
7271
let { cwd, port } = await customDev(files, templateName);

0 commit comments

Comments
 (0)