Skip to content

Use alternative to ssrLoadModule when Vite Environment API is enabled #13008

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Feb 18, 2025
5 changes: 5 additions & 0 deletions .changeset/new-houses-hug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@react-router/dev": patch
---

Fix `future.unstable_viteEnvironmentApi` when the `ssr` environment has been configured by another plugin to be a custom `Vite.DevEnvironment` rather than a `Vite.RunnableDevEnvironment`
1 change: 1 addition & 0 deletions contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
- JaffParker
- jakkku
- JakubDrozd
- jamesopstad
- jamesrwilliams
- janpaepke
- jasikpark
Expand Down
38 changes: 36 additions & 2 deletions packages/react-router-dev/vite/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ import {
} from "../config/config";
import * as WithProps from "./with-props";

export type LoadModule = (
viteDevServer: Vite.ViteDevServer,
url: string
) => Promise<any>;

export async function resolveViteConfig({
configFile,
mode,
Expand Down Expand Up @@ -910,6 +915,31 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
};
};

// We use a separate environment for loading the server manifest and inlined
// CSS during development. This is because "ssrLoadModule" isn't available if
// the "ssr" environment has been defined by another plugin (e.g.
// vite-plugin-cloudflare) as a custom Vite.DevEnvironment rather than a
// Vite.RunnableDevEnvironment:
// https://vite.dev/guide/api-environment-frameworks.html#runtime-agnostic-ssr
const HELPER_ENVIRONMENT_NAME = "__react_router_helper__";

const loadModule: LoadModule = (viteDevServer, url) => {
if (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi) {
const vite = getVite();
const helperEnvironment =
viteDevServer.environments[HELPER_ENVIRONMENT_NAME];

invariant(
helperEnvironment && vite.isRunnableDevEnvironment(helperEnvironment),
"Missing helper environment"
);

return helperEnvironment.runner.import(url);
}

return viteDevServer.ssrLoadModule(url);
};

return [
{
name: "react-router",
Expand Down Expand Up @@ -1061,7 +1091,10 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {

...(ctx.reactRouterConfig.future.unstable_viteEnvironmentApi
? {
environments,
environments: {
...environments,
[HELPER_ENVIRONMENT_NAME]: {},
},
build: {
// This isn't honored by the SSR environment config (which seems
// to be a Vite bug?) so we set it here too.
Expand Down Expand Up @@ -1243,6 +1276,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
cssModulesManifest,
build,
url,
loadModule,
});
},
// If an error is caught within the request handler, let Vite fix the
Expand Down Expand Up @@ -1919,7 +1953,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
if (route) {
// invalidate manifest on route exports change
let serverManifest = (
await server.ssrLoadModule(virtual.serverManifest.id)
await loadModule(server, virtual.serverManifest.id)
).default as ReactRouterManifest;

let oldRouteMetadata = serverManifest.routes[route.id];
Expand Down
9 changes: 8 additions & 1 deletion packages/react-router-dev/vite/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { ModuleNode, ViteDevServer } from "vite";
import type { ResolvedReactRouterConfig } from "../config/config";
import { resolveFileUrl } from "./resolve-file-url";
import { getVite } from "./vite";
import type { LoadModule } from "./plugin";

type ServerRouteManifest = ServerBuild["routes"];
type ServerRoute = ServerRouteManifest[string];
Expand Down Expand Up @@ -57,11 +58,13 @@ const getStylesForFiles = async ({
rootDirectory,
cssModulesManifest,
files,
loadModule,
}: {
viteDevServer: ViteDevServer;
rootDirectory: string;
cssModulesManifest: Record<string, string>;
files: string[];
loadModule: LoadModule;
}): Promise<string | undefined> => {
let vite = getVite();
let viteMajor = parseInt(vite.version.split(".")[0], 10);
Expand Down Expand Up @@ -111,7 +114,8 @@ const getStylesForFiles = async ({
let css = isCssModulesFile(dep.file)
? cssModulesManifest[dep.file]
: (
await viteDevServer.ssrLoadModule(
await loadModule(
viteDevServer,
// We need the ?inline query in Vite v6 when loading CSS in SSR
// since it does not expose the default export for CSS in a
// server environment. This is to align with non-SSR
Expand Down Expand Up @@ -224,6 +228,7 @@ export const getStylesForUrl = async ({
cssModulesManifest,
build,
url,
loadModule,
}: {
viteDevServer: ViteDevServer;
rootDirectory: string;
Expand All @@ -232,6 +237,7 @@ export const getStylesForUrl = async ({
cssModulesManifest: Record<string, string>;
build: ServerBuild;
url: string | undefined;
loadModule: LoadModule;
}): Promise<string | undefined> => {
if (url === undefined || url.includes("?_data=")) {
return undefined;
Expand All @@ -254,6 +260,7 @@ export const getStylesForUrl = async ({
// Then include any styles from the matched routes
...documentRouteFiles,
],
loadModule,
});

return styles;
Expand Down