Repository navigation
How to provide a populated RouteContextProvider from BYO server? #15622
Replies: 2 comments
|
The keys are matched by object identity. The fix is to move the code that builds the context into the Vite build, so only one copy of the keys exists. The official // server/app.ts (compiled into build/server/index.js)
import { RouterContextProvider } from "react-router";
import { resourcesContext, type Resources } from "../app/context";
import { createKoaHandler } from "./koa-adapter"; // whatever wraps createRequestHandler today
export function createReactRouterMiddleware(resources: Resources) {
return createKoaHandler({
build: () => import("virtual:react-router/server-build"),
getLoadContext() {
const context = new RouterContextProvider();
context.set(resourcesContext, resources);
return context;
},
});
}// vite.config.ts
export default defineConfig({
environments: {
ssr: { build: { rollupOptions: { input: "./server/app.ts" } } },
},
plugins: [reactRouter()],
});// server.js (your Koa entry, not bundled)
const resources = await createResources(); // once, at startup
const app = new Koa();
if (process.env.NODE_ENV === "development") {
const vite = await (await import("vite")).createServer({
server: { middlewareMode: true },
appType: "custom",
});
// mount vite.middlewares (connect-style) here
app.use(async (ctx, next) => {
const { createReactRouterMiddleware } = await vite.ssrLoadModule("./server/app.ts");
return createReactRouterMiddleware(resources)(ctx, next);
});
} else {
const { createReactRouterMiddleware } = await import("./build/server/index.js");
app.use(createReactRouterMiddleware(resources));
}In dev, If you'd rather keep the server outside the build, add Two things that won't work on their own:
Tested with react-router, @react-router/dev and @react-router/node 8.4.0, Vite 8.3.4, Koa 3.2.1 and Node 24.18, against the |
|
Building on the object-identity answer above — the practical fix is to make both sides of your server share one module registry, because the duplication isn't in the context API, it's in how the modules get loaded. What's happening: your koa bootstrap loads the module that calls RouterContext() with one loader (Node's require/import), while the app runs through Vite's SSR pipeline. Same file, two module instances, two distinct context objects — so get() on the app side looks up a key that isn't in the Map. Ways out, pick one:
Option 1 is the cleanest — it also fixes any future double-instantiation bugs of the same kind (singletons, class instances, anything identity-sensitive). |
Uh oh!
There was an error while loading. Please reload this page.
We started with remix and BYO server (koa).
The server code populates the AppLoadContext with various server side resources (client connections and the like) that are expensive to create on startup.
Upgrading from RR7 to RR8, we are running into issues.
All works fine as an RR7 AppLoadContext, but the problem with the RouterContextProvider is the duplicate module loading for the keys (RouterContext). The RouterContextProvider is populated with key loaded by the server module but routes try to get() from RouterContextProvider with key loaded by the app module loader. It always encounters the error “No vale found for context”
How is this meant to work? How are we supposed to pass context from the server to the app?
All reactions