@@ -64,10 +64,10 @@ import {
6464} from "../config/config" ;
6565import * as WithProps from "./with-props" ;
6666
67- export type LoadModule = (
67+ export type LoadCssContents = (
6868 viteDevServer : Vite . ViteDevServer ,
69- url : string
70- ) => Promise < any > ;
69+ mod : Vite . ModuleNode
70+ ) => Promise < string > ;
7171
7272export async function resolveViteConfig ( {
7373 configFile,
@@ -122,11 +122,24 @@ exports are only ever used on the server. Without this optimization we can't
122122tree-shake any unused custom exports because routes are entry points. */
123123const BUILD_CLIENT_ROUTE_QUERY_STRING = "?__react-router-build-client-route" ;
124124
125- export type EnvironmentName = "client" | SsrEnvironmentName ;
125+ export type EnvironmentName =
126+ | "client"
127+ | SsrEnvironmentName
128+ | CssDevHelperEnvironmentName ;
126129
127130const SSR_BUNDLE_PREFIX = "ssrBundle_" ;
128131type SsrEnvironmentName = "ssr" | `${typeof SSR_BUNDLE_PREFIX } ${string } `;
129132
133+ // We use a separate environment for loading the critical CSS during
134+ // development. This is because "ssrLoadModule" isn't available if the "ssr"
135+ // environment has been defined by another plugin (e.g.
136+ // vite-plugin-cloudflare) as a custom Vite.DevEnvironment rather than a
137+ // Vite.RunnableDevEnvironment:
138+ // https://vite.dev/guide/api-environment-frameworks.html#runtime-agnostic-ssr
139+ const CSS_DEV_HELPER_ENVIRONMENT_NAME =
140+ "__react_router_css_dev_helper__" as const ;
141+ type CssDevHelperEnvironmentName = typeof CSS_DEV_HELPER_ENVIRONMENT_NAME ;
142+
130143type EnvironmentOptions = Pick <
131144 Vite . EnvironmentOptions ,
132145 "build" | "resolve" | "optimizeDeps"
@@ -477,6 +490,9 @@ let getServerBuildDirectory = (
477490let getClientBuildDirectory = ( reactRouterConfig : ResolvedReactRouterConfig ) =>
478491 path . join ( reactRouterConfig . buildDirectory , "client" ) ;
479492
493+ const injectQuery = ( url : string , query : string ) =>
494+ url . includes ( "?" ) ? url . replace ( "?" , `?${ query } &` ) : `${ url } ?${ query } ` ;
495+
480496let defaultEntriesDir = path . resolve (
481497 path . dirname ( require . resolve ( "@react-router/dev/package.json" ) ) ,
482498 "dist" ,
@@ -834,6 +850,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
834850 } ;
835851
836852 // In dev, the server and browser manifests are the same
853+ let currentReactRouterManifestForDev : ReactRouterManifest | null = null ;
837854 let getReactRouterManifestForDev = async ( ) : Promise < ReactRouterManifest > => {
838855 let routes : ReactRouterManifest [ "routes" ] = { } ;
839856
@@ -901,7 +918,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
901918 } ;
902919 }
903920
904- return {
921+ let reactRouterManifestForDev = {
905922 version : String ( Math . random ( ) ) ,
906923 url : combineURLs ( ctx . publicPath , virtual . browserManifest . url ) ,
907924 hmr : {
@@ -916,31 +933,56 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
916933 } ,
917934 routes,
918935 } ;
919- } ;
920936
921- // We use a separate environment for loading the server manifest and inlined
922- // CSS during development. This is because "ssrLoadModule" isn't available if
923- // the "ssr" environment has been defined by another plugin (e.g.
924- // vite-plugin-cloudflare) as a custom Vite.DevEnvironment rather than a
925- // Vite.RunnableDevEnvironment:
926- // https://vite.dev/guide/api-environment-frameworks.html#runtime-agnostic-ssr
927- const HELPER_ENVIRONMENT_NAME = "__react_router_helper__" ;
937+ currentReactRouterManifestForDev = reactRouterManifestForDev ;
928938
929- const loadModule : LoadModule = ( viteDevServer , url ) => {
930- if ( ctx . reactRouterConfig . future . unstable_viteEnvironmentApi ) {
931- const vite = getVite ( ) ;
932- const helperEnvironment =
933- viteDevServer . environments [ HELPER_ENVIRONMENT_NAME ] ;
939+ return reactRouterManifestForDev ;
940+ } ;
934941
935- invariant (
936- helperEnvironment && vite . isRunnableDevEnvironment ( helperEnvironment ) ,
937- "Missing helper environment"
938- ) ;
942+ const loadCssContents : LoadCssContents = async ( viteDevServer , dep ) => {
943+ invariant (
944+ viteCommand === "serve" ,
945+ "loadCssContents is only available in dev mode"
946+ ) ;
939947
940- return helperEnvironment . runner . import ( url ) ;
948+ if ( dep . file && isCssModulesFile ( dep . file ) ) {
949+ return cssModulesManifest [ dep . file ] ;
941950 }
942951
943- return viteDevServer . ssrLoadModule ( url ) ;
952+ const vite = getVite ( ) ;
953+ const viteMajor = parseInt ( vite . version . split ( "." ) [ 0 ] , 10 ) ;
954+
955+ const url =
956+ viteMajor >= 6
957+ ? // We need the ?inline query in Vite v6 when loading CSS in SSR
958+ // since it does not expose the default export for CSS in a
959+ // server environment. This is to align with non-SSR
960+ // environments. For backwards compatibility with v5 we keep
961+ // using the URL without ?inline query because the HMR code was
962+ // relying on the implicit SSR-client module graph relationship.
963+ injectQuery ( dep . url , "inline" )
964+ : dep . url ;
965+
966+ let cssMod : unknown ;
967+ if ( ctx . reactRouterConfig . future . unstable_viteEnvironmentApi ) {
968+ const cssDevHelperEnvironment =
969+ viteDevServer . environments [ CSS_DEV_HELPER_ENVIRONMENT_NAME ] ;
970+ invariant ( cssDevHelperEnvironment , "Missing CSS dev helper environment" ) ;
971+ invariant ( vite . isRunnableDevEnvironment ( cssDevHelperEnvironment ) ) ;
972+ cssMod = await cssDevHelperEnvironment . runner . import ( url ) ;
973+ } else {
974+ cssMod = await viteDevServer . ssrLoadModule ( url ) ;
975+ }
976+
977+ invariant (
978+ typeof cssMod === "object" &&
979+ cssMod !== null &&
980+ "default" in cssMod &&
981+ typeof cssMod . default === "string" ,
982+ `Failed to load CSS for ${ dep . file ?? dep . url } `
983+ ) ;
984+
985+ return cssMod . default ;
944986 } ;
945987
946988 return [
@@ -1094,10 +1136,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
10941136
10951137 ...( ctx . reactRouterConfig . future . unstable_viteEnvironmentApi
10961138 ? {
1097- environments : {
1098- ...environments ,
1099- [ HELPER_ENVIRONMENT_NAME ] : { } ,
1100- } ,
1139+ environments,
11011140 build : {
11021141 // This isn't honored by the SSR environment config (which seems
11031142 // to be a Vite bug?) so we set it here too.
@@ -1298,10 +1337,9 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
12981337 entryClientFilePath : ctx . entryClientFilePath ,
12991338 reactRouterConfig : ctx . reactRouterConfig ,
13001339 viteDevServer,
1301- cssModulesManifest ,
1340+ loadCssContents ,
13021341 build,
13031342 url,
1304- loadModule,
13051343 } ) ;
13061344 } ,
13071345 // If an error is caught within the request handler, let Vite fix the
@@ -1977,11 +2015,8 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
19772015
19782016 if ( route ) {
19792017 // invalidate manifest on route exports change
1980- let serverManifest = (
1981- await loadModule ( server , virtual . serverManifest . id )
1982- ) . default as ReactRouterManifest ;
1983-
1984- let oldRouteMetadata = serverManifest . routes [ route . id ] ;
2018+ let oldRouteMetadata =
2019+ currentReactRouterManifestForDev ?. routes [ route . id ] ;
19852020 let newRouteMetadata = await getRouteMetadata (
19862021 cache ,
19872022 ctx ,
@@ -3274,6 +3309,13 @@ export async function getEnvironmentOptionsResolvers(
32743309 } ) ;
32753310 }
32763311
3312+ if (
3313+ ctx . reactRouterConfig . future . unstable_viteEnvironmentApi &&
3314+ viteCommand === "serve"
3315+ ) {
3316+ environmentOptionsResolvers [ CSS_DEV_HELPER_ENVIRONMENT_NAME ] = ( ) => ( { } ) ;
3317+ }
3318+
32773319 return environmentOptionsResolvers ;
32783320}
32793321
0 commit comments