Skip to content

Commit 72e6e3c

Browse files
committed
Update
1 parent 451dcc3 commit 72e6e3c

File tree

2 files changed

+126
-109
lines changed

2 files changed

+126
-109
lines changed

packages/react-router-dev/config/config.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ type BuildEndHook = (args: {
110110
viteConfig: Vite.ResolvedConfig;
111111
}) => void | Promise<void>;
112112

113+
export type PrerenderPaths =
114+
| boolean
115+
| Array<string>
116+
| ((args: {
117+
getStaticPaths: () => string[];
118+
}) => Array<string> | Promise<Array<string>>);
119+
113120
/**
114121
* Config to be exported via the default export from `react-router.config.ts`.
115122
*/
@@ -156,7 +163,8 @@ export type ReactRouterConfig = {
156163
* but may consume more resources, and send more concurrent requests to the
157164
* server/CMS.
158165
*/
159-
prerender?: PrerenderPaths
166+
prerender?:
167+
| PrerenderPaths
160168
| {
161169
paths: PrerenderPaths;
162170
unstable_concurrency?: number;
@@ -205,10 +213,6 @@ export type ReactRouterConfig = {
205213
ssr?: boolean;
206214
};
207215

208-
export type PrerenderPaths = boolean
209-
| Array<string>
210-
| ((args: { getStaticPaths: () => string[] }) => Array<string> | Promise<Array<string>>);
211-
212216
export type ResolvedReactRouterConfig = Readonly<{
213217
/**
214218
* The absolute path to the application source directory.

packages/react-router-dev/vite/plugin.ts

Lines changed: 117 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ import {
7979
createConfigLoader,
8080
resolveEntryFiles,
8181
configRouteToBranchRoute,
82-
type PrerenderPaths,
82+
PrerenderPaths,
8383
} from "../config/config";
8484
import { getOptimizeDepsEntries } from "./optimize-deps-entries";
8585
import { decorateComponentExportsWithProps } from "./with-props";
@@ -2660,81 +2660,93 @@ async function handlePrerender(
26602660
}
26612661

26622662
let buildRoutes = createPrerenderRoutes(build.routes);
2663-
const concurrency = getPrerenderConcurrency(reactRouterConfig.prerender);
2664-
await pMap(build.prerender, async path => {
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-
);
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+
}
27012710
} else {
2702-
viteConfig.logger.warn(
2703-
`⚠️ Skipping prerendering for resource route without a loader: ${leafRoute?.id}`,
2711+
let hasLoaders = matches.some(
2712+
(m) => build.assets.routes[m.route.id]?.hasLoader,
27042713
);
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(
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(
27132727
handler,
27142728
path,
2715-
null,
27162729
clientBuildDirectory,
27172730
reactRouterConfig,
27182731
viteConfig,
2732+
data
2733+
? {
2734+
headers: {
2735+
"X-React-Router-Prerender-Data": encodeURI(data),
2736+
},
2737+
}
2738+
: undefined,
27192739
);
27202740
}
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-
}, { concurrency });
2741+
},
2742+
{
2743+
concurrency:
2744+
typeof reactRouterConfig.prerender === "object" &&
2745+
"paths" in reactRouterConfig.prerender
2746+
? reactRouterConfig.prerender.unstable_concurrency || 1
2747+
: 1,
2748+
},
2749+
);
27382750
}
27392751

27402752
function getStaticPrerenderPaths(routes: DataRouteObject[]) {
@@ -2919,48 +2931,49 @@ export async function getPrerenderPaths(
29192931
routes: GenericRouteManifest,
29202932
logWarning = false,
29212933
): Promise<string[]> {
2922-
let prerenderPaths: string[] = [];
2923-
if (prerender != null && prerender !== false) {
2924-
let prerenderRoutes = createPrerenderRoutes(routes);
2925-
if (typeof prerender === "object") {
2926-
prerender = (prerender as { paths: PrerenderPaths }).paths
2927-
}
2934+
if (prerender == null || prerender === false) {
2935+
return [];
2936+
}
29282937

2929-
if (prerender === true) {
2930-
let { paths, paramRoutes } = getStaticPrerenderPaths(prerenderRoutes);
2931-
if (logWarning && !ssr && paramRoutes.length > 0) {
2932-
console.warn(
2933-
colors.yellow(
2934-
[
2935-
"⚠️ Paths with dynamic/splat params cannot be prerendered when " +
2936-
"using `prerender: true`. You may want to use the `prerender()` " +
2937-
"API to prerender the following paths:",
2938-
...paramRoutes.map((p) => " - " + p),
2939-
].join("\n"),
2940-
),
2941-
);
2942-
}
2943-
prerenderPaths = paths;
2944-
} else if (typeof prerender === "function") {
2945-
prerenderPaths = await prerender({
2946-
getStaticPaths: () => getStaticPrerenderPaths(prerenderRoutes).paths,
2947-
});
2948-
} else {
2949-
prerenderPaths = prerender || ["/"];
2950-
}
2938+
let pathsConfig: PrerenderPaths;
2939+
2940+
if (typeof prerender === "object" && "paths" in prerender) {
2941+
pathsConfig = prerender.paths;
2942+
} else {
2943+
pathsConfig = prerender;
29512944
}
2952-
return prerenderPaths;
2953-
}
29542945

2955-
const DEFAULT_PRERENDER_CONCURRENCY = 1
2946+
if (pathsConfig === false) {
2947+
return [];
2948+
}
29562949

2957-
function getPrerenderConcurrency(
2958-
prerender: ResolvedReactRouterConfig["prerender"],
2959-
): number {
2960-
if (typeof prerender === "object") {
2961-
return (prerender as { unstable_concurrency?: number }).unstable_concurrency || DEFAULT_PRERENDER_CONCURRENCY
2950+
let prerenderRoutes = createPrerenderRoutes(routes);
2951+
2952+
if (pathsConfig === true) {
2953+
let { paths, paramRoutes } = getStaticPrerenderPaths(prerenderRoutes);
2954+
if (logWarning && !ssr && paramRoutes.length > 0) {
2955+
console.warn(
2956+
colors.yellow(
2957+
[
2958+
"⚠️ Paths with dynamic/splat params cannot be prerendered when " +
2959+
"using `prerender: true`. You may want to use the `prerender()` " +
2960+
"API to prerender the following paths:",
2961+
...paramRoutes.map((p) => " - " + p),
2962+
].join("\n"),
2963+
),
2964+
);
2965+
}
2966+
return paths;
29622967
}
2963-
return DEFAULT_PRERENDER_CONCURRENCY
2968+
2969+
if (typeof pathsConfig === "function") {
2970+
let paths = await pathsConfig({
2971+
getStaticPaths: () => getStaticPrerenderPaths(prerenderRoutes).paths,
2972+
});
2973+
return paths;
2974+
}
2975+
2976+
return pathsConfig;
29642977
}
29652978

29662979
// Note: Duplicated from react-router/lib/server-runtime

0 commit comments

Comments
 (0)