@@ -36,6 +36,7 @@ import pick from "lodash/pick";
3636import jsesc from "jsesc" ;
3737import colors from "picocolors" ;
3838import kebabCase from "lodash/kebabCase" ;
39+ import pMap from "p-map" ;
3940
4041import * as Typegen from "../typegen" ;
4142import type { RouteManifestEntry , RouteManifest } from "../config/routes" ;
@@ -86,7 +87,6 @@ import { decorateComponentExportsWithProps } from "./with-props";
8687import { loadDotenv } from "./load-dotenv" ;
8788import { validatePluginOrder } from "./plugins/validate-plugin-order" ;
8889import { warnOnClientSourceMaps } from "./plugins/warn-on-client-source-maps" ;
89- import { pMap } from "./pmap" ;
9090
9191export type LoadCssContents = (
9292 viteDevServer : Vite . ViteDevServer ,
@@ -2660,93 +2660,89 @@ async function handlePrerender(
26602660 }
26612661
26622662 let buildRoutes = createPrerenderRoutes ( build . routes ) ;
2663- await pMap (
2664- build . prerender ,
2665- async ( path ) => {
2666- // Ensure we have a leading slash for matching
2667- let matches = matchRoutes (
2668- buildRoutes ,
2669- `/${ path } /` . replace ( / ^ \/ \/ + / , "/" ) ,
2670- ) ;
2671- if ( ! matches ) {
2672- return ;
2673- }
2674- // When prerendering a resource route, we don't want to pass along the
2675- // `.data` file since we want to prerender the raw Response returned from
2676- // the loader. Presumably this is for routes where a file extension is
2677- // already included, such as `app/routes/items[.json].tsx` that will
2678- // render into `/items.json`
2679- let leafRoute = matches ? matches [ matches . length - 1 ] . route : null ;
2680- let manifestRoute = leafRoute ? build . routes [ leafRoute . id ] ?. module : null ;
2681- let isResourceRoute =
2682- manifestRoute && ! manifestRoute . default && ! manifestRoute . ErrorBoundary ;
2683-
2684- if ( isResourceRoute ) {
2685- invariant ( leafRoute ) ;
2686- invariant ( manifestRoute ) ;
2687- if ( manifestRoute . loader ) {
2688- // Prerender a .data file for turbo-stream consumption
2689- await prerenderData (
2690- handler ,
2691- path ,
2692- [ leafRoute . id ] ,
2693- clientBuildDirectory ,
2694- reactRouterConfig ,
2695- viteConfig ,
2696- ) ;
2697- // Prerender a raw file for external consumption
2698- await prerenderResourceRoute (
2699- handler ,
2700- path ,
2701- clientBuildDirectory ,
2702- reactRouterConfig ,
2703- viteConfig ,
2704- ) ;
2705- } else {
2706- viteConfig . logger . warn (
2707- `⚠️ Skipping prerendering for resource route without a loader: ${ leafRoute ?. id } ` ,
2708- ) ;
2709- }
2663+
2664+ let prerenderSinglePath = async ( path : string ) => {
2665+ // Ensure we have a leading slash for matching
2666+ let matches = matchRoutes ( buildRoutes , `/${ path } /` . replace ( / ^ \/ \/ + / , "/" ) ) ;
2667+ if ( ! matches ) {
2668+ return ;
2669+ }
2670+ // When prerendering a resource route, we don't want to pass along the
2671+ // `.data` file since we want to prerender the raw Response returned from
2672+ // the loader. Presumably this is for routes where a file extension is
2673+ // already included, such as `app/routes/items[.json].tsx` that will
2674+ // render into `/items.json`
2675+ let leafRoute = matches ? matches [ matches . length - 1 ] . route : null ;
2676+ let manifestRoute = leafRoute ? build . routes [ leafRoute . id ] ?. module : null ;
2677+ let isResourceRoute =
2678+ manifestRoute && ! manifestRoute . default && ! manifestRoute . ErrorBoundary ;
2679+
2680+ if ( isResourceRoute ) {
2681+ invariant ( leafRoute ) ;
2682+ invariant ( manifestRoute ) ;
2683+ if ( manifestRoute . loader ) {
2684+ // Prerender a .data file for turbo-stream consumption
2685+ await prerenderData (
2686+ handler ,
2687+ path ,
2688+ [ leafRoute . id ] ,
2689+ clientBuildDirectory ,
2690+ reactRouterConfig ,
2691+ viteConfig ,
2692+ ) ;
2693+ // Prerender a raw file for external consumption
2694+ await prerenderResourceRoute (
2695+ handler ,
2696+ path ,
2697+ clientBuildDirectory ,
2698+ reactRouterConfig ,
2699+ viteConfig ,
2700+ ) ;
27102701 } else {
2711- let hasLoaders = matches . some (
2712- ( m ) => build . assets . routes [ m . route . id ] ?. hasLoader ,
2702+ viteConfig . logger . warn (
2703+ `⚠️ Skipping prerendering for resource route without a loader: ${ leafRoute ?. id } ` ,
27132704 ) ;
2714- let data : string | undefined ;
2715- if ( ! isResourceRoute && hasLoaders ) {
2716- data = await prerenderData (
2717- handler ,
2718- path ,
2719- null ,
2720- clientBuildDirectory ,
2721- reactRouterConfig ,
2722- viteConfig ,
2723- ) ;
2724- }
2725-
2726- await prerenderRoute (
2705+ }
2706+ } else {
2707+ let hasLoaders = matches . some (
2708+ ( m ) => build . assets . routes [ m . route . id ] ?. hasLoader ,
2709+ ) ;
2710+ let data : string | undefined ;
2711+ if ( ! isResourceRoute && hasLoaders ) {
2712+ data = await prerenderData (
27272713 handler ,
27282714 path ,
2715+ null ,
27292716 clientBuildDirectory ,
27302717 reactRouterConfig ,
27312718 viteConfig ,
2732- data
2733- ? {
2734- headers : {
2735- "X-React-Router-Prerender-Data" : encodeURI ( data ) ,
2736- } ,
2737- }
2738- : undefined ,
27392719 ) ;
27402720 }
2741- } ,
2742- {
2743- concurrency :
2744- typeof reactRouterConfig . prerender === "object" &&
2745- "paths" in reactRouterConfig . prerender
2746- ? reactRouterConfig . prerender . unstable_concurrency || 1
2747- : 1 ,
2748- } ,
2749- ) ;
2721+
2722+ await prerenderRoute (
2723+ handler ,
2724+ path ,
2725+ clientBuildDirectory ,
2726+ reactRouterConfig ,
2727+ viteConfig ,
2728+ data
2729+ ? {
2730+ headers : {
2731+ "X-React-Router-Prerender-Data" : encodeURI ( data ) ,
2732+ } ,
2733+ }
2734+ : undefined ,
2735+ ) ;
2736+ }
2737+ } ;
2738+
2739+ let concurrency = 1 ;
2740+ let { prerender } = reactRouterConfig ;
2741+ if ( typeof prerender === "object" && "unstable_concurrency" in prerender ) {
2742+ concurrency = prerender . unstable_concurrency ?? 1 ;
2743+ }
2744+
2745+ await pMap ( build . prerender , prerenderSinglePath , { concurrency } ) ;
27502746}
27512747
27522748function getStaticPrerenderPaths ( routes : DataRouteObject [ ] ) {
0 commit comments