@react-router/dev 0.0.0-experimental-66357d4 → 0.0.0-experimental-4c49981eb
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +111 -0
- package/dist/cli/index.js +41 -8
- package/dist/config/default-rsc-entries/entry.client.tsx +2 -2
- package/dist/config.d.ts +14 -4
- package/dist/config.js +1 -1
- package/dist/routes.js +1 -1
- package/dist/vite/cloudflare.js +15 -6
- package/dist/vite.js +126 -34
- package/package.json +7 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,116 @@
|
|
|
1
1
|
# `@react-router/dev`
|
|
2
2
|
|
|
3
|
+
## 7.9.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Update `valibot` dependency to `^1.1.0` ([#14379](https://github.com/remix-run/react-router/pull/14379))
|
|
8
|
+
|
|
9
|
+
- New (unstable) `useRoute` hook for accessing data from specific routes ([#14407](https://github.com/remix-run/react-router/pull/14407))
|
|
10
|
+
|
|
11
|
+
For example, let's say you have an `admin` route somewhere in your app and you want any child routes of `admin` to all have access to the `loaderData` and `actionData` from `admin.`
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
// app/routes/admin.tsx
|
|
15
|
+
import { Outlet } from "react-router";
|
|
16
|
+
|
|
17
|
+
export const loader = () => ({ message: "Hello, loader!" });
|
|
18
|
+
|
|
19
|
+
export const action = () => ({ count: 1 });
|
|
20
|
+
|
|
21
|
+
export default function Component() {
|
|
22
|
+
return (
|
|
23
|
+
<div>
|
|
24
|
+
{/* ... */}
|
|
25
|
+
<Outlet />
|
|
26
|
+
{/* ... */}
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
You might even want to create a reusable widget that all of the routes nested under `admin` could use:
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { unstable_useRoute as useRoute } from "react-router";
|
|
36
|
+
|
|
37
|
+
export function AdminWidget() {
|
|
38
|
+
// How to get `message` and `count` from `admin` route?
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
In framework mode, `useRoute` knows all your app's routes and gives you TS errors when invalid route IDs are passed in:
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
export function AdminWidget() {
|
|
46
|
+
const admin = useRoute("routes/dmin");
|
|
47
|
+
// ^^^^^^^^^^^
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`useRoute` returns `undefined` if the route is not part of the current page:
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
export function AdminWidget() {
|
|
55
|
+
const admin = useRoute("routes/admin");
|
|
56
|
+
if (!admin) {
|
|
57
|
+
throw new Error(`AdminWidget used outside of "routes/admin"`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Note: the `root` route is the exception since it is guaranteed to be part of the current page.
|
|
63
|
+
As a result, `useRoute` never returns `undefined` for `root`.
|
|
64
|
+
|
|
65
|
+
`loaderData` and `actionData` are marked as optional since they could be accessed before the `action` is triggered or after the `loader` threw an error:
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
export function AdminWidget() {
|
|
69
|
+
const admin = useRoute("routes/admin");
|
|
70
|
+
if (!admin) {
|
|
71
|
+
throw new Error(`AdminWidget used outside of "routes/admin"`);
|
|
72
|
+
}
|
|
73
|
+
const { loaderData, actionData } = admin;
|
|
74
|
+
console.log(loaderData);
|
|
75
|
+
// ^? { message: string } | undefined
|
|
76
|
+
console.log(actionData);
|
|
77
|
+
// ^? { count: number } | undefined
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
If instead of a specific route, you wanted access to the _current_ route's `loaderData` and `actionData`, you can call `useRoute` without arguments:
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
export function AdminWidget() {
|
|
85
|
+
const currentRoute = useRoute();
|
|
86
|
+
currentRoute.loaderData;
|
|
87
|
+
currentRoute.actionData;
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
This usage is equivalent to calling `useLoaderData` and `useActionData`, but consolidates all route data access into one hook: `useRoute`.
|
|
92
|
+
|
|
93
|
+
Note: when calling `useRoute()` (without a route ID), TS has no way to know which route is the current route.
|
|
94
|
+
As a result, `loaderData` and `actionData` are typed as `unknown`.
|
|
95
|
+
If you want more type-safety, you can either narrow the type yourself with something like `zod` or you can refactor your app to pass down typed props to your `AdminWidget`:
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
export function AdminWidget({
|
|
99
|
+
message,
|
|
100
|
+
count,
|
|
101
|
+
}: {
|
|
102
|
+
message: string;
|
|
103
|
+
count: number;
|
|
104
|
+
}) {
|
|
105
|
+
/* ... */
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- Updated dependencies:
|
|
110
|
+
- `react-router@7.9.4`
|
|
111
|
+
- `@react-router/node@7.9.4`
|
|
112
|
+
- `@react-router/serve@7.9.4`
|
|
113
|
+
|
|
3
114
|
## 7.9.3
|
|
4
115
|
|
|
5
116
|
### Patch Changes
|
package/dist/cli/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* @react-router/dev v0.0.0-experimental-
|
|
3
|
+
* @react-router/dev v0.0.0-experimental-4c49981eb
|
|
4
4
|
*
|
|
5
5
|
* Copyright (c) Remix Software Inc.
|
|
6
6
|
*
|
|
@@ -390,11 +390,20 @@ async function resolveConfig({
|
|
|
390
390
|
if (!ssr && serverBundles) {
|
|
391
391
|
serverBundles = void 0;
|
|
392
392
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
393
|
+
if (prerender) {
|
|
394
|
+
let isValidPrerenderPathsConfig = (p) => typeof p === "boolean" || typeof p === "function" || Array.isArray(p);
|
|
395
|
+
let isValidPrerenderConfig = isValidPrerenderPathsConfig(prerender) || typeof prerender === "object" && "paths" in prerender && isValidPrerenderPathsConfig(prerender.paths);
|
|
396
|
+
if (!isValidPrerenderConfig) {
|
|
397
|
+
return err(
|
|
398
|
+
"The `prerender`/`prerender.paths` config must be a boolean, an array of string paths, or a function returning a boolean or array of string paths."
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
let isValidConcurrencyConfig = typeof prerender != "object" || !("unstable_concurrency" in prerender) || typeof prerender.unstable_concurrency === "number" && Number.isInteger(prerender.unstable_concurrency) && prerender.unstable_concurrency > 0;
|
|
402
|
+
if (!isValidConcurrencyConfig) {
|
|
403
|
+
return err(
|
|
404
|
+
"The `prerender.unstable_concurrency` config must be a positive integer if specified."
|
|
405
|
+
);
|
|
406
|
+
}
|
|
398
407
|
}
|
|
399
408
|
let routeDiscovery;
|
|
400
409
|
if (userRouteDiscovery == null) {
|
|
@@ -980,9 +989,10 @@ function generateRoutes(ctx) {
|
|
|
980
989
|
interface Register {
|
|
981
990
|
pages: Pages
|
|
982
991
|
routeFiles: RouteFiles
|
|
992
|
+
routeModules: RouteModules
|
|
983
993
|
}
|
|
984
994
|
}
|
|
985
|
-
` + "\n\n" + generate(pagesType(allPages)).code + "\n\n" + generate(routeFilesType({ fileToRoutes, routeToPages })).code
|
|
995
|
+
` + "\n\n" + generate(pagesType(allPages)).code + "\n\n" + generate(routeFilesType({ fileToRoutes, routeToPages })).code + "\n\n" + generate(routeModulesType(ctx)).code
|
|
986
996
|
};
|
|
987
997
|
const allAnnotations = Array.from(fileToRoutes.entries()).filter(([file]) => isInAppDirectory(ctx, file)).map(
|
|
988
998
|
([file, routeIds]) => getRouteAnnotations({ ctx, file, routeIds, lineages })
|
|
@@ -1051,6 +1061,28 @@ function routeFilesType({
|
|
|
1051
1061
|
)
|
|
1052
1062
|
);
|
|
1053
1063
|
}
|
|
1064
|
+
function routeModulesType(ctx) {
|
|
1065
|
+
return t2.tsTypeAliasDeclaration(
|
|
1066
|
+
t2.identifier("RouteModules"),
|
|
1067
|
+
null,
|
|
1068
|
+
t2.tsTypeLiteral(
|
|
1069
|
+
Object.values(ctx.config.routes).map(
|
|
1070
|
+
(route) => t2.tsPropertySignature(
|
|
1071
|
+
t2.stringLiteral(route.id),
|
|
1072
|
+
t2.tsTypeAnnotation(
|
|
1073
|
+
isInAppDirectory(ctx, route.file) ? t2.tsTypeQuery(
|
|
1074
|
+
t2.tsImportType(
|
|
1075
|
+
t2.stringLiteral(
|
|
1076
|
+
`./${Path3.relative(ctx.rootDirectory, ctx.config.appDirectory)}/${route.file}`
|
|
1077
|
+
)
|
|
1078
|
+
)
|
|
1079
|
+
) : t2.tsUnknownKeyword()
|
|
1080
|
+
)
|
|
1081
|
+
)
|
|
1082
|
+
)
|
|
1083
|
+
)
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1054
1086
|
function isInAppDirectory(ctx, routeFile) {
|
|
1055
1087
|
const path9 = Path3.resolve(ctx.config.appDirectory, routeFile);
|
|
1056
1088
|
return path9.startsWith(ctx.config.appDirectory);
|
|
@@ -1748,7 +1780,7 @@ function resolveEnvironmentsOptions(environmentResolvers, resolverOptions) {
|
|
|
1748
1780
|
function isNonNullable(x) {
|
|
1749
1781
|
return x != null;
|
|
1750
1782
|
}
|
|
1751
|
-
var import_node_crypto, import_node_fs3, import_promises2, path7, url, babel2, import_node_fetch_server2, import_react_router2, import_es_module_lexer, import_pick3, import_jsesc, import_picocolors5, import_kebabCase, CLIENT_NON_COMPONENT_EXPORTS, CLIENT_ROUTE_EXPORTS, BUILD_CLIENT_ROUTE_QUERY_STRING, SSR_BUNDLE_PREFIX, virtualHmrRuntime, virtualInjectHmrRuntime, virtual, getServerBuildDirectory, getClientBuildDirectory, defaultEntriesDir, defaultEntries, REACT_REFRESH_HEADER;
|
|
1783
|
+
var import_node_crypto, import_node_fs3, import_promises2, path7, url, babel2, import_node_fetch_server2, import_react_router2, import_es_module_lexer, import_pick3, import_jsesc, import_picocolors5, import_kebabCase, import_p_map, CLIENT_NON_COMPONENT_EXPORTS, CLIENT_ROUTE_EXPORTS, BUILD_CLIENT_ROUTE_QUERY_STRING, SSR_BUNDLE_PREFIX, virtualHmrRuntime, virtualInjectHmrRuntime, virtual, getServerBuildDirectory, getClientBuildDirectory, defaultEntriesDir, defaultEntries, REACT_REFRESH_HEADER;
|
|
1752
1784
|
var init_plugin = __esm({
|
|
1753
1785
|
"vite/plugin.ts"() {
|
|
1754
1786
|
"use strict";
|
|
@@ -1765,6 +1797,7 @@ var init_plugin = __esm({
|
|
|
1765
1797
|
import_jsesc = __toESM(require("jsesc"));
|
|
1766
1798
|
import_picocolors5 = __toESM(require("picocolors"));
|
|
1767
1799
|
import_kebabCase = __toESM(require("lodash/kebabCase"));
|
|
1800
|
+
import_p_map = __toESM(require("p-map"));
|
|
1768
1801
|
init_typegen();
|
|
1769
1802
|
init_invariant();
|
|
1770
1803
|
init_babel();
|
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
unstable_createCallServer as createCallServer,
|
|
13
13
|
unstable_getRSCStream as getRSCStream,
|
|
14
14
|
unstable_RSCHydratedRouter as RSCHydratedRouter,
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
type unstable_RSCPayload as RSCPayload,
|
|
16
|
+
} from "react-router/dom";
|
|
17
17
|
|
|
18
18
|
setServerCallback(
|
|
19
19
|
createCallServer({
|
package/dist/config.d.ts
CHANGED
|
@@ -58,6 +58,9 @@ type BuildEndHook = (args: {
|
|
|
58
58
|
reactRouterConfig: ResolvedReactRouterConfig;
|
|
59
59
|
viteConfig: Vite.ResolvedConfig;
|
|
60
60
|
}) => void | Promise<void>;
|
|
61
|
+
type PrerenderPaths = boolean | Array<string> | ((args: {
|
|
62
|
+
getStaticPaths: () => string[];
|
|
63
|
+
}) => Array<string> | Promise<Array<string>>);
|
|
61
64
|
/**
|
|
62
65
|
* Config to be exported via the default export from `react-router.config.ts`.
|
|
63
66
|
*/
|
|
@@ -93,10 +96,17 @@ type ReactRouterConfig = {
|
|
|
93
96
|
/**
|
|
94
97
|
* An array of URLs to prerender to HTML files at build time. Can also be a
|
|
95
98
|
* function returning an array to dynamically generate URLs.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
*
|
|
100
|
+
* `unstable_concurrency` defaults to 1, which means "no concurrency" - fully serial execution.
|
|
101
|
+
* Setting it to a value more than 1 enables concurrent prerendering.
|
|
102
|
+
* Setting it to a value higher than one can increase the speed of the build,
|
|
103
|
+
* but may consume more resources, and send more concurrent requests to the
|
|
104
|
+
* server/CMS.
|
|
105
|
+
*/
|
|
106
|
+
prerender?: PrerenderPaths | {
|
|
107
|
+
paths: PrerenderPaths;
|
|
108
|
+
unstable_concurrency?: number;
|
|
109
|
+
};
|
|
100
110
|
/**
|
|
101
111
|
* An array of React Router plugin config presets to ease integration with
|
|
102
112
|
* other platforms and tools.
|
package/dist/config.js
CHANGED
package/dist/routes.js
CHANGED
package/dist/vite/cloudflare.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @react-router/dev v0.0.0-experimental-
|
|
2
|
+
* @react-router/dev v0.0.0-experimental-4c49981eb
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -420,11 +420,20 @@ async function resolveConfig({
|
|
|
420
420
|
if (!ssr && serverBundles) {
|
|
421
421
|
serverBundles = void 0;
|
|
422
422
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
423
|
+
if (prerender) {
|
|
424
|
+
let isValidPrerenderPathsConfig = (p) => typeof p === "boolean" || typeof p === "function" || Array.isArray(p);
|
|
425
|
+
let isValidPrerenderConfig = isValidPrerenderPathsConfig(prerender) || typeof prerender === "object" && "paths" in prerender && isValidPrerenderPathsConfig(prerender.paths);
|
|
426
|
+
if (!isValidPrerenderConfig) {
|
|
427
|
+
return err(
|
|
428
|
+
"The `prerender`/`prerender.paths` config must be a boolean, an array of string paths, or a function returning a boolean or array of string paths."
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
let isValidConcurrencyConfig = typeof prerender != "object" || !("unstable_concurrency" in prerender) || typeof prerender.unstable_concurrency === "number" && Number.isInteger(prerender.unstable_concurrency) && prerender.unstable_concurrency > 0;
|
|
432
|
+
if (!isValidConcurrencyConfig) {
|
|
433
|
+
return err(
|
|
434
|
+
"The `prerender.unstable_concurrency` config must be a positive integer if specified."
|
|
435
|
+
);
|
|
436
|
+
}
|
|
428
437
|
}
|
|
429
438
|
let routeDiscovery;
|
|
430
439
|
if (userRouteDiscovery == null) {
|
package/dist/vite.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @react-router/dev v0.0.0-experimental-
|
|
2
|
+
* @react-router/dev v0.0.0-experimental-4c49981eb
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -59,6 +59,7 @@ var import_pick3 = __toESM(require("lodash/pick"));
|
|
|
59
59
|
var import_jsesc = __toESM(require("jsesc"));
|
|
60
60
|
var import_picocolors4 = __toESM(require("picocolors"));
|
|
61
61
|
var import_kebabCase = __toESM(require("lodash/kebabCase"));
|
|
62
|
+
var import_p_map = __toESM(require("p-map"));
|
|
62
63
|
|
|
63
64
|
// typegen/index.ts
|
|
64
65
|
var import_promises = __toESM(require("fs/promises"));
|
|
@@ -447,11 +448,20 @@ async function resolveConfig({
|
|
|
447
448
|
if (!ssr && serverBundles) {
|
|
448
449
|
serverBundles = void 0;
|
|
449
450
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
451
|
+
if (prerender) {
|
|
452
|
+
let isValidPrerenderPathsConfig = (p) => typeof p === "boolean" || typeof p === "function" || Array.isArray(p);
|
|
453
|
+
let isValidPrerenderConfig = isValidPrerenderPathsConfig(prerender) || typeof prerender === "object" && "paths" in prerender && isValidPrerenderPathsConfig(prerender.paths);
|
|
454
|
+
if (!isValidPrerenderConfig) {
|
|
455
|
+
return err(
|
|
456
|
+
"The `prerender`/`prerender.paths` config must be a boolean, an array of string paths, or a function returning a boolean or array of string paths."
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
let isValidConcurrencyConfig = typeof prerender != "object" || !("unstable_concurrency" in prerender) || typeof prerender.unstable_concurrency === "number" && Number.isInteger(prerender.unstable_concurrency) && prerender.unstable_concurrency > 0;
|
|
460
|
+
if (!isValidConcurrencyConfig) {
|
|
461
|
+
return err(
|
|
462
|
+
"The `prerender.unstable_concurrency` config must be a positive integer if specified."
|
|
463
|
+
);
|
|
464
|
+
}
|
|
455
465
|
}
|
|
456
466
|
let routeDiscovery;
|
|
457
467
|
if (userRouteDiscovery == null) {
|
|
@@ -968,9 +978,10 @@ function generateRoutes(ctx) {
|
|
|
968
978
|
interface Register {
|
|
969
979
|
pages: Pages
|
|
970
980
|
routeFiles: RouteFiles
|
|
981
|
+
routeModules: RouteModules
|
|
971
982
|
}
|
|
972
983
|
}
|
|
973
|
-
` + "\n\n" + generate(pagesType(allPages)).code + "\n\n" + generate(routeFilesType({ fileToRoutes, routeToPages })).code
|
|
984
|
+
` + "\n\n" + generate(pagesType(allPages)).code + "\n\n" + generate(routeFilesType({ fileToRoutes, routeToPages })).code + "\n\n" + generate(routeModulesType(ctx)).code
|
|
974
985
|
};
|
|
975
986
|
const allAnnotations = Array.from(fileToRoutes.entries()).filter(([file]) => isInAppDirectory(ctx, file)).map(
|
|
976
987
|
([file, routeIds]) => getRouteAnnotations({ ctx, file, routeIds, lineages })
|
|
@@ -1039,6 +1050,28 @@ function routeFilesType({
|
|
|
1039
1050
|
)
|
|
1040
1051
|
);
|
|
1041
1052
|
}
|
|
1053
|
+
function routeModulesType(ctx) {
|
|
1054
|
+
return t2.tsTypeAliasDeclaration(
|
|
1055
|
+
t2.identifier("RouteModules"),
|
|
1056
|
+
null,
|
|
1057
|
+
t2.tsTypeLiteral(
|
|
1058
|
+
Object.values(ctx.config.routes).map(
|
|
1059
|
+
(route) => t2.tsPropertySignature(
|
|
1060
|
+
t2.stringLiteral(route.id),
|
|
1061
|
+
t2.tsTypeAnnotation(
|
|
1062
|
+
isInAppDirectory(ctx, route.file) ? t2.tsTypeQuery(
|
|
1063
|
+
t2.tsImportType(
|
|
1064
|
+
t2.stringLiteral(
|
|
1065
|
+
`./${Path3.relative(ctx.rootDirectory, ctx.config.appDirectory)}/${route.file}`
|
|
1066
|
+
)
|
|
1067
|
+
)
|
|
1068
|
+
) : t2.tsUnknownKeyword()
|
|
1069
|
+
)
|
|
1070
|
+
)
|
|
1071
|
+
)
|
|
1072
|
+
)
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1042
1075
|
function isInAppDirectory(ctx, routeFile) {
|
|
1043
1076
|
const path9 = Path3.resolve(ctx.config.appDirectory, routeFile);
|
|
1044
1077
|
return path9.startsWith(ctx.config.appDirectory);
|
|
@@ -2526,7 +2559,7 @@ var getClientEntryChunk = (ctx, viteManifest) => {
|
|
|
2526
2559
|
invariant(chunk, `Chunk not found: ${filePath}`);
|
|
2527
2560
|
return chunk;
|
|
2528
2561
|
};
|
|
2529
|
-
var getReactRouterManifestBuildAssets = (ctx, viteConfig, viteManifest, entryFilePath, route) => {
|
|
2562
|
+
var getReactRouterManifestBuildAssets = (ctx, viteConfig, viteManifest, allDynamicCssFiles, entryFilePath, route) => {
|
|
2530
2563
|
let entryChunk = resolveChunk(ctx, viteManifest, entryFilePath);
|
|
2531
2564
|
invariant(entryChunk, `Chunk not found: ${entryFilePath}`);
|
|
2532
2565
|
let isRootRoute = Boolean(route && route.parentId === void 0);
|
|
@@ -2559,7 +2592,10 @@ var getReactRouterManifestBuildAssets = (ctx, viteConfig, viteManifest, entryFil
|
|
|
2559
2592
|
// in the manifest that isn't tied to any route file. If we want to render these
|
|
2560
2593
|
// styles correctly, we need to include them in the root route.
|
|
2561
2594
|
isRootRoute ? getCssCodeSplitDisabledFile(ctx, viteConfig, viteManifest) : null,
|
|
2562
|
-
chunks.flatMap((e) => e.css ?? []).map((href) =>
|
|
2595
|
+
chunks.flatMap((e) => e.css ?? []).map((href) => {
|
|
2596
|
+
let publicHref = `${ctx.publicPath}${href}`;
|
|
2597
|
+
return allDynamicCssFiles.has(href) ? `${publicHref}#` : publicHref;
|
|
2598
|
+
})
|
|
2563
2599
|
].flat(1).filter(isNonNullable)
|
|
2564
2600
|
)
|
|
2565
2601
|
};
|
|
@@ -2582,6 +2618,44 @@ function resolveDependantChunks(viteManifest, entryChunks) {
|
|
|
2582
2618
|
}
|
|
2583
2619
|
return Array.from(chunks);
|
|
2584
2620
|
}
|
|
2621
|
+
function getAllDynamicCssFiles(ctx, viteManifest) {
|
|
2622
|
+
let allDynamicCssFiles = /* @__PURE__ */ new Set();
|
|
2623
|
+
for (let route of Object.values(ctx.reactRouterConfig.routes)) {
|
|
2624
|
+
let routeFile = path6.join(ctx.reactRouterConfig.appDirectory, route.file);
|
|
2625
|
+
let entryChunk = resolveChunk(
|
|
2626
|
+
ctx,
|
|
2627
|
+
viteManifest,
|
|
2628
|
+
`${routeFile}${BUILD_CLIENT_ROUTE_QUERY_STRING}`
|
|
2629
|
+
);
|
|
2630
|
+
if (entryChunk) {
|
|
2631
|
+
let walk2 = function(chunk, isDynamicImportContext) {
|
|
2632
|
+
if (visitedChunks.has(chunk)) {
|
|
2633
|
+
return;
|
|
2634
|
+
}
|
|
2635
|
+
visitedChunks.add(chunk);
|
|
2636
|
+
if (isDynamicImportContext && chunk.css) {
|
|
2637
|
+
for (let cssFile of chunk.css) {
|
|
2638
|
+
allDynamicCssFiles.add(cssFile);
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
if (chunk.dynamicImports) {
|
|
2642
|
+
for (let dynamicImportKey of chunk.dynamicImports) {
|
|
2643
|
+
walk2(viteManifest[dynamicImportKey], true);
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
if (chunk.imports) {
|
|
2647
|
+
for (let importKey of chunk.imports) {
|
|
2648
|
+
walk2(viteManifest[importKey], isDynamicImportContext);
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
};
|
|
2652
|
+
var walk = walk2;
|
|
2653
|
+
let visitedChunks = /* @__PURE__ */ new Set();
|
|
2654
|
+
walk2(entryChunk, false);
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
return allDynamicCssFiles;
|
|
2658
|
+
}
|
|
2585
2659
|
function dedupe(array2) {
|
|
2586
2660
|
return [...new Set(array2)];
|
|
2587
2661
|
}
|
|
@@ -2871,10 +2945,12 @@ var reactRouterVitePlugin = () => {
|
|
|
2871
2945
|
let viteManifest = await loadViteManifest(
|
|
2872
2946
|
getClientBuildDirectory(ctx.reactRouterConfig)
|
|
2873
2947
|
);
|
|
2948
|
+
let allDynamicCssFiles = getAllDynamicCssFiles(ctx, viteManifest);
|
|
2874
2949
|
let entry = getReactRouterManifestBuildAssets(
|
|
2875
2950
|
ctx,
|
|
2876
2951
|
viteConfig2,
|
|
2877
2952
|
viteManifest,
|
|
2953
|
+
allDynamicCssFiles,
|
|
2878
2954
|
ctx.entryClientFilePath,
|
|
2879
2955
|
null
|
|
2880
2956
|
);
|
|
@@ -2926,6 +3002,7 @@ var reactRouterVitePlugin = () => {
|
|
|
2926
3002
|
ctx,
|
|
2927
3003
|
viteConfig2,
|
|
2928
3004
|
viteManifest,
|
|
3005
|
+
allDynamicCssFiles,
|
|
2929
3006
|
`${routeFile}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
2930
3007
|
route
|
|
2931
3008
|
),
|
|
@@ -4179,10 +4256,10 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
|
|
|
4179
4256
|
}
|
|
4180
4257
|
}
|
|
4181
4258
|
let buildRoutes = createPrerenderRoutes(build.routes);
|
|
4182
|
-
|
|
4259
|
+
let prerenderSinglePath = async (path9) => {
|
|
4183
4260
|
let matches = (0, import_react_router2.matchRoutes)(buildRoutes, `/${path9}/`.replace(/^\/\/+/, "/"));
|
|
4184
4261
|
if (!matches) {
|
|
4185
|
-
|
|
4262
|
+
return;
|
|
4186
4263
|
}
|
|
4187
4264
|
let leafRoute = matches ? matches[matches.length - 1].route : null;
|
|
4188
4265
|
let manifestRoute = leafRoute ? build.routes[leafRoute.id]?.module : null;
|
|
@@ -4239,7 +4316,13 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
|
|
|
4239
4316
|
} : void 0
|
|
4240
4317
|
);
|
|
4241
4318
|
}
|
|
4319
|
+
};
|
|
4320
|
+
let concurrency = 1;
|
|
4321
|
+
let { prerender } = reactRouterConfig;
|
|
4322
|
+
if (typeof prerender === "object" && "unstable_concurrency" in prerender) {
|
|
4323
|
+
concurrency = prerender.unstable_concurrency ?? 1;
|
|
4242
4324
|
}
|
|
4325
|
+
await (0, import_p_map.default)(build.prerender, prerenderSinglePath, { concurrency });
|
|
4243
4326
|
}
|
|
4244
4327
|
function getStaticPrerenderPaths(routes) {
|
|
4245
4328
|
let paths = ["/"];
|
|
@@ -4355,31 +4438,40 @@ ${content.toString("utf8")}`
|
|
|
4355
4438
|
);
|
|
4356
4439
|
}
|
|
4357
4440
|
async function getPrerenderPaths(prerender, ssr, routes, logWarning = false) {
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4441
|
+
if (prerender == null || prerender === false) {
|
|
4442
|
+
return [];
|
|
4443
|
+
}
|
|
4444
|
+
let pathsConfig;
|
|
4445
|
+
if (typeof prerender === "object" && "paths" in prerender) {
|
|
4446
|
+
pathsConfig = prerender.paths;
|
|
4447
|
+
} else {
|
|
4448
|
+
pathsConfig = prerender;
|
|
4449
|
+
}
|
|
4450
|
+
if (pathsConfig === false) {
|
|
4451
|
+
return [];
|
|
4452
|
+
}
|
|
4453
|
+
let prerenderRoutes = createPrerenderRoutes(routes);
|
|
4454
|
+
if (pathsConfig === true) {
|
|
4455
|
+
let { paths, paramRoutes } = getStaticPrerenderPaths(prerenderRoutes);
|
|
4456
|
+
if (logWarning && !ssr && paramRoutes.length > 0) {
|
|
4457
|
+
console.warn(
|
|
4458
|
+
import_picocolors4.default.yellow(
|
|
4459
|
+
[
|
|
4460
|
+
"\u26A0\uFE0F Paths with dynamic/splat params cannot be prerendered when using `prerender: true`. You may want to use the `prerender()` API to prerender the following paths:",
|
|
4461
|
+
...paramRoutes.map((p) => " - " + p)
|
|
4462
|
+
].join("\n")
|
|
4463
|
+
)
|
|
4464
|
+
);
|
|
4380
4465
|
}
|
|
4466
|
+
return paths;
|
|
4467
|
+
}
|
|
4468
|
+
if (typeof pathsConfig === "function") {
|
|
4469
|
+
let paths = await pathsConfig({
|
|
4470
|
+
getStaticPaths: () => getStaticPrerenderPaths(prerenderRoutes).paths
|
|
4471
|
+
});
|
|
4472
|
+
return paths;
|
|
4381
4473
|
}
|
|
4382
|
-
return
|
|
4474
|
+
return pathsConfig;
|
|
4383
4475
|
}
|
|
4384
4476
|
function groupRoutesByParentId2(manifest) {
|
|
4385
4477
|
let routes = {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-router/dev",
|
|
3
|
-
"version": "0.0.0-experimental-
|
|
3
|
+
"version": "0.0.0-experimental-4c49981eb",
|
|
4
4
|
"description": "Dev tools and CLI for React Router",
|
|
5
5
|
"homepage": "https://reactrouter.com",
|
|
6
6
|
"bugs": {
|
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
"isbot": "^5.1.11",
|
|
79
79
|
"jsesc": "3.0.2",
|
|
80
80
|
"lodash": "^4.17.21",
|
|
81
|
+
"p-map": "^7.0.3",
|
|
81
82
|
"pathe": "^1.1.2",
|
|
82
83
|
"picocolors": "^1.1.1",
|
|
83
84
|
"prettier": "^3.6.2",
|
|
@@ -86,7 +87,7 @@
|
|
|
86
87
|
"tinyglobby": "^0.2.14",
|
|
87
88
|
"valibot": "^1.1.0",
|
|
88
89
|
"vite-node": "^3.2.2",
|
|
89
|
-
"@react-router/node": "0.0.0-experimental-
|
|
90
|
+
"@react-router/node": "0.0.0-experimental-4c49981eb"
|
|
90
91
|
},
|
|
91
92
|
"devDependencies": {
|
|
92
93
|
"@types/babel__core": "^7.20.5",
|
|
@@ -109,16 +110,16 @@
|
|
|
109
110
|
"vite": "^6.1.0",
|
|
110
111
|
"wireit": "0.14.9",
|
|
111
112
|
"wrangler": "^4.23.0",
|
|
112
|
-
"@react-router/serve": "0.0.0-experimental-
|
|
113
|
-
"react-router": "^0.0.0-experimental-
|
|
113
|
+
"@react-router/serve": "0.0.0-experimental-4c49981eb",
|
|
114
|
+
"react-router": "^0.0.0-experimental-4c49981eb"
|
|
114
115
|
},
|
|
115
116
|
"peerDependencies": {
|
|
116
117
|
"@vitejs/plugin-rsc": "*",
|
|
117
118
|
"typescript": "^5.1.0",
|
|
118
119
|
"vite": "^5.1.0 || ^6.0.0 || ^7.0.0",
|
|
119
120
|
"wrangler": "^3.28.2 || ^4.0.0",
|
|
120
|
-
"@react-router/serve": "^0.0.0-experimental-
|
|
121
|
-
"react-router": "^0.0.0-experimental-
|
|
121
|
+
"@react-router/serve": "^0.0.0-experimental-4c49981eb",
|
|
122
|
+
"react-router": "^0.0.0-experimental-4c49981eb"
|
|
122
123
|
},
|
|
123
124
|
"peerDependenciesMeta": {
|
|
124
125
|
"@vitejs/plugin-rsc": {
|