react-router 8.0.0-pre.0 → 8.0.0
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 +66 -0
- package/dist/development/dom-export.js +1 -1
- package/dist/development/index-react-server-client.js +1 -1
- package/dist/development/index-react-server.d.ts +9 -2
- package/dist/development/index-react-server.js +91 -88
- package/dist/development/index.d.ts +1 -2
- package/dist/development/index.js +2 -3
- package/dist/development/lib/actions.js +6 -18
- package/dist/development/lib/components.d.ts +11 -3
- package/dist/development/lib/components.js +8 -2
- package/dist/development/lib/context.js +1 -1
- package/dist/development/lib/dom/dom.js +1 -1
- package/dist/development/lib/dom/lib.d.ts +12 -1
- package/dist/development/lib/dom/lib.js +18 -6
- package/dist/development/lib/dom/server.js +2 -2
- package/dist/development/lib/dom/ssr/components.d.ts +4 -2
- package/dist/development/lib/dom/ssr/components.js +13 -3
- package/dist/development/lib/dom/ssr/data.js +1 -1
- package/dist/development/lib/dom/ssr/entry.d.ts +1 -0
- package/dist/development/lib/dom/ssr/errorBoundaries.js +7 -3
- package/dist/development/lib/dom/ssr/fallback.js +8 -3
- package/dist/development/lib/dom/ssr/fog-of-war.js +12 -2
- package/dist/development/lib/dom/ssr/hydration.js +1 -1
- package/dist/development/lib/dom/ssr/invariant.js +1 -1
- package/dist/development/lib/dom/ssr/links.js +1 -1
- package/dist/development/lib/dom/ssr/markup.js +1 -1
- package/dist/development/lib/dom/ssr/routeModules.js +1 -1
- package/dist/development/lib/dom/ssr/routes-test-stub.js +1 -1
- package/dist/development/lib/dom/ssr/routes.js +1 -1
- package/dist/development/lib/dom/ssr/server.d.ts +4 -1
- package/dist/development/lib/dom/ssr/server.js +2 -1
- package/dist/development/lib/dom/ssr/single-fetch.js +2 -3
- package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
- package/dist/development/lib/dom-export/hydrated-router.d.ts +1 -1
- package/dist/development/lib/dom-export/hydrated-router.js +14 -17
- package/dist/development/lib/errors.js +1 -1
- package/dist/development/lib/hooks.js +6 -4
- package/dist/development/lib/href.js +1 -1
- package/dist/development/lib/router/history.js +3 -2
- package/dist/development/lib/router/instrumentation.js +1 -1
- package/dist/development/lib/router/links.d.ts +3 -2
- package/dist/development/lib/router/router.js +13 -6
- package/dist/development/lib/router/url.js +18 -0
- package/dist/development/lib/router/utils.d.ts +6 -0
- package/dist/development/lib/router/utils.js +27 -8
- package/dist/development/lib/rsc/browser.js +21 -17
- package/dist/development/lib/rsc/errorBoundaries.js +1 -1
- package/dist/development/lib/rsc/html-stream/browser.js +1 -1
- package/dist/development/lib/rsc/html-stream/server.js +1 -1
- package/dist/development/lib/rsc/route-modules.js +1 -1
- package/dist/development/lib/rsc/server.ssr.js +27 -11
- package/dist/development/lib/server-runtime/cookies.js +1 -1
- package/dist/development/lib/server-runtime/crypto.js +1 -1
- package/dist/development/lib/server-runtime/data.js +1 -1
- package/dist/development/lib/server-runtime/dev.js +1 -1
- package/dist/development/lib/server-runtime/entry.js +1 -1
- package/dist/development/lib/server-runtime/errors.js +2 -22
- package/dist/development/lib/server-runtime/headers.js +1 -1
- package/dist/development/lib/server-runtime/invariant.js +1 -1
- package/dist/development/lib/server-runtime/mode.js +1 -1
- package/dist/development/lib/server-runtime/routeMatching.js +1 -1
- package/dist/development/lib/server-runtime/routes.js +1 -1
- package/dist/development/lib/server-runtime/server.js +17 -23
- package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/development/lib/server-runtime/sessions/cookieStorage.js +1 -1
- package/dist/development/lib/server-runtime/sessions/memoryStorage.js +1 -1
- package/dist/development/lib/server-runtime/sessions.js +1 -1
- package/dist/development/lib/server-runtime/single-fetch.js +4 -4
- package/dist/development/lib/server-runtime/urls.js +2 -5
- package/dist/development/lib/server-runtime/warnings.js +1 -1
- package/dist/development/lib/types/internal.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +2 -1
- package/dist/development/vendor/turbo-stream-v2/unflatten.js +3 -2
- package/dist/development/vendor/turbo-stream-v2/utils.js +2 -10
- package/dist/production/dom-export.js +1 -1
- package/dist/production/index-react-server-client.js +1 -1
- package/dist/production/index-react-server.d.ts +9 -2
- package/dist/production/index-react-server.js +91 -88
- package/dist/production/index.d.ts +1 -2
- package/dist/production/index.js +2 -3
- package/dist/production/lib/actions.js +6 -18
- package/dist/production/lib/components.d.ts +11 -3
- package/dist/production/lib/components.js +8 -2
- package/dist/production/lib/context.js +1 -1
- package/dist/production/lib/dom/dom.js +1 -1
- package/dist/production/lib/dom/lib.d.ts +12 -1
- package/dist/production/lib/dom/lib.js +18 -6
- package/dist/production/lib/dom/server.js +2 -2
- package/dist/production/lib/dom/ssr/components.d.ts +4 -2
- package/dist/production/lib/dom/ssr/components.js +13 -3
- package/dist/production/lib/dom/ssr/data.js +1 -1
- package/dist/production/lib/dom/ssr/entry.d.ts +1 -0
- package/dist/production/lib/dom/ssr/errorBoundaries.js +7 -3
- package/dist/production/lib/dom/ssr/fallback.js +3 -1
- package/dist/production/lib/dom/ssr/fog-of-war.js +12 -2
- package/dist/production/lib/dom/ssr/hydration.js +1 -1
- package/dist/production/lib/dom/ssr/invariant.js +1 -1
- package/dist/production/lib/dom/ssr/links.js +1 -1
- package/dist/production/lib/dom/ssr/markup.js +1 -1
- package/dist/production/lib/dom/ssr/routeModules.js +1 -1
- package/dist/production/lib/dom/ssr/routes-test-stub.js +1 -1
- package/dist/production/lib/dom/ssr/routes.js +1 -1
- package/dist/production/lib/dom/ssr/server.d.ts +4 -1
- package/dist/production/lib/dom/ssr/server.js +2 -1
- package/dist/production/lib/dom/ssr/single-fetch.js +2 -3
- package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
- package/dist/production/lib/dom-export/hydrated-router.d.ts +1 -1
- package/dist/production/lib/dom-export/hydrated-router.js +14 -17
- package/dist/production/lib/errors.js +1 -1
- package/dist/production/lib/hooks.js +6 -4
- package/dist/production/lib/href.js +1 -1
- package/dist/production/lib/router/history.js +3 -2
- package/dist/production/lib/router/instrumentation.js +1 -1
- package/dist/production/lib/router/links.d.ts +3 -2
- package/dist/production/lib/router/router.js +13 -6
- package/dist/production/lib/router/url.js +18 -0
- package/dist/production/lib/router/utils.d.ts +6 -0
- package/dist/production/lib/router/utils.js +27 -8
- package/dist/production/lib/rsc/browser.js +21 -17
- package/dist/production/lib/rsc/errorBoundaries.js +1 -1
- package/dist/production/lib/rsc/html-stream/browser.js +1 -1
- package/dist/production/lib/rsc/html-stream/server.js +1 -1
- package/dist/production/lib/rsc/route-modules.js +1 -1
- package/dist/production/lib/rsc/server.ssr.js +27 -11
- package/dist/production/lib/server-runtime/cookies.js +1 -1
- package/dist/production/lib/server-runtime/crypto.js +1 -1
- package/dist/production/lib/server-runtime/data.js +1 -1
- package/dist/production/lib/server-runtime/dev.js +1 -1
- package/dist/production/lib/server-runtime/entry.js +1 -1
- package/dist/production/lib/server-runtime/errors.js +2 -22
- package/dist/production/lib/server-runtime/headers.js +1 -1
- package/dist/production/lib/server-runtime/invariant.js +1 -1
- package/dist/production/lib/server-runtime/mode.js +1 -1
- package/dist/production/lib/server-runtime/routeMatching.js +1 -1
- package/dist/production/lib/server-runtime/routes.js +1 -1
- package/dist/production/lib/server-runtime/server.js +17 -23
- package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/production/lib/server-runtime/sessions/cookieStorage.js +1 -1
- package/dist/production/lib/server-runtime/sessions/memoryStorage.js +1 -1
- package/dist/production/lib/server-runtime/sessions.js +1 -1
- package/dist/production/lib/server-runtime/single-fetch.js +4 -4
- package/dist/production/lib/server-runtime/urls.js +2 -5
- package/dist/production/lib/server-runtime/warnings.js +1 -1
- package/dist/production/lib/types/internal.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +2 -1
- package/dist/production/vendor/turbo-stream-v2/unflatten.js +3 -2
- package/dist/production/vendor/turbo-stream-v2/utils.js +2 -10
- package/docs/explanation/code-splitting.md +1 -1
- package/docs/explanation/index-query-param.md +2 -2
- package/docs/explanation/type-safety.md +1 -1
- package/docs/how-to/data-strategy.md +5 -5
- package/docs/how-to/error-reporting.md +10 -2
- package/docs/how-to/headers.md +2 -1
- package/docs/how-to/middleware.md +8 -89
- package/docs/how-to/security.md +9 -7
- package/docs/how-to/status.md +1 -1
- package/docs/index.md +3 -6
- package/docs/start/data/installation.md +4 -0
- package/docs/start/data/route-object.md +20 -0
- package/docs/start/framework/actions.md +0 -1
- package/docs/start/framework/data-loading.md +1 -1
- package/docs/start/framework/deploying.md +4 -0
- package/docs/start/framework/installation.md +0 -1
- package/docs/start/modes.md +1 -2
- package/docs/upgrading/component-routes.md +2 -2
- package/docs/upgrading/future.md +58 -11
- package/docs/upgrading/router-provider.md +6 -3
- package/docs/upgrading/v7.md +443 -0
- package/package.json +7 -7
- package/dist/development/lib/dom/ssr/errors.d.ts +0 -7
- package/dist/development/lib/dom/ssr/errors.js +0 -36
- package/dist/production/lib/dom/ssr/errors.d.ts +0 -7
- package/dist/production/lib/dom/ssr/errors.js +0 -36
- package/docs/upgrading/remix.md +0 -403
- package/docs/upgrading/v6.md +0 -379
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.0.0
|
|
2
|
+
* react-router v8.0.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import { ErrorResponseImpl, RouterContextProvider, defaultMapRouteProperties, isRouteErrorResponse, stripBasename } from "../router/utils.js";
|
|
11
|
+
import { ErrorResponseImpl, RouterContextProvider, defaultMapRouteProperties, isRouteErrorResponse, removeTrailingSlash, stripBasename } from "../router/utils.js";
|
|
12
12
|
import { instrumentHandler } from "../router/instrumentation.js";
|
|
13
13
|
import { createStaticHandler, getStaticContextFromError, isMutationMethod, isRedirectResponse, isResponse } from "../router/router.js";
|
|
14
14
|
import { getManifestPath } from "../dom/ssr/fog-of-war.js";
|
|
15
15
|
import { createEntryRouteModules } from "./entry.js";
|
|
16
16
|
import { isServerMode } from "./mode.js";
|
|
17
|
-
import { sanitizeErrors, serializeError
|
|
17
|
+
import { sanitizeErrors, serializeError } from "./errors.js";
|
|
18
18
|
import { matchServerRoutes } from "./routeMatching.js";
|
|
19
19
|
import { getBuildTimeHeader, getDevServerHooks } from "./dev.js";
|
|
20
20
|
import { createStaticHandlerDataRoutes } from "./routes.js";
|
|
@@ -54,7 +54,7 @@ function derive(build, mode) {
|
|
|
54
54
|
}
|
|
55
55
|
loadContext = initialContext || new RouterContextProvider();
|
|
56
56
|
let requestUrl = new URL(request.url);
|
|
57
|
-
let normalizedPathname = getNormalizedPath(request
|
|
57
|
+
let normalizedPathname = getNormalizedPath(request).pathname;
|
|
58
58
|
let isSpaMode = getBuildTimeHeader(request, "X-React-Router-SPA-Mode") === "yes";
|
|
59
59
|
if (!build.ssr) {
|
|
60
60
|
let decodedPath = decodeURI(normalizedPathname);
|
|
@@ -74,7 +74,7 @@ function derive(build, mode) {
|
|
|
74
74
|
decodedPath = strippedPath;
|
|
75
75
|
}
|
|
76
76
|
if (build.prerender.length === 0) isSpaMode = true;
|
|
77
|
-
else if (!build.prerender.
|
|
77
|
+
else if (!build.prerender.some((p) => removeTrailingSlash(p) === removeTrailingSlash(decodedPath))) if (requestUrl.pathname.endsWith(".data")) {
|
|
78
78
|
errorHandler(new ErrorResponseImpl(404, "Not Found", `Refusing to SSR the path \`${decodedPath}\` because \`ssr:false\` is set and the path is not included in the \`prerender\` config, so in production the path will be a 404.`), {
|
|
79
79
|
context: loadContext,
|
|
80
80
|
params,
|
|
@@ -155,26 +155,20 @@ const createRequestHandler = (build, mode) => {
|
|
|
155
155
|
};
|
|
156
156
|
};
|
|
157
157
|
async function handleManifestRequest(build, dataRoutes, branches, url) {
|
|
158
|
-
if (build.assets.version !== url.searchParams.get("version")) return new Response(null, {
|
|
159
|
-
status: 204,
|
|
160
|
-
headers: { "X-Remix-Reload-Document": "true" }
|
|
161
|
-
});
|
|
162
158
|
if (url.toString().length > 7680) return new Response(null, {
|
|
163
159
|
statusText: "Bad Request",
|
|
164
160
|
status: 400
|
|
165
161
|
});
|
|
162
|
+
if (build.assets.version !== url.searchParams.get("version")) return new Response(null, {
|
|
163
|
+
status: 204,
|
|
164
|
+
headers: { "X-Remix-Reload-Document": "true" }
|
|
165
|
+
});
|
|
166
166
|
let patches = {};
|
|
167
167
|
if (url.searchParams.has("paths")) {
|
|
168
|
-
let
|
|
169
|
-
|
|
170
|
-
if (!path.startsWith("/")) path = `/${path}`;
|
|
171
|
-
let segments = path.split("/").slice(1);
|
|
172
|
-
segments.forEach((_, i) => {
|
|
173
|
-
let partialPath = segments.slice(0, i + 1).join("/");
|
|
174
|
-
paths.add(`/${partialPath}`);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
168
|
+
let pathParam = url.searchParams.get("paths") || "";
|
|
169
|
+
let paths = new Set(pathParam.split(",").filter(Boolean));
|
|
177
170
|
for (let path of paths) {
|
|
171
|
+
if (!path.startsWith("/")) path = `/${path}`;
|
|
178
172
|
let matches = matchServerRoutes(build.routes, dataRoutes, branches, path, build.basename);
|
|
179
173
|
if (matches) for (let match of matches) {
|
|
180
174
|
let routeId = match.route.id;
|
|
@@ -192,7 +186,7 @@ async function handleSingleFetchRequest(serverMode, build, staticHandler, reques
|
|
|
192
186
|
async function handleDocumentRequest(serverMode, build, staticHandler, request, loadContext, handleError, isSpaMode, criticalCss) {
|
|
193
187
|
try {
|
|
194
188
|
if (isMutationMethod(request.method)) try {
|
|
195
|
-
throwIfPotentialCSRFAttack(request
|
|
189
|
+
throwIfPotentialCSRFAttack(request, Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []);
|
|
196
190
|
} catch (e) {
|
|
197
191
|
handleError(e);
|
|
198
192
|
return new Response("Bad Request", { status: 400 });
|
|
@@ -209,7 +203,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
|
|
|
209
203
|
return new Response(null, { status: 500 });
|
|
210
204
|
}
|
|
211
205
|
},
|
|
212
|
-
normalizePath: (r) => getNormalizedPath(r
|
|
206
|
+
normalizePath: (r) => getNormalizedPath(r)
|
|
213
207
|
});
|
|
214
208
|
if (!isResponse(result)) result = await renderHtml(result, isSpaMode);
|
|
215
209
|
return result;
|
|
@@ -232,7 +226,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
|
|
|
232
226
|
let state = {
|
|
233
227
|
loaderData: context.loaderData,
|
|
234
228
|
actionData: context.actionData,
|
|
235
|
-
errors:
|
|
229
|
+
errors: context.errors
|
|
236
230
|
};
|
|
237
231
|
let baseServerHandoff = {
|
|
238
232
|
basename: build.basename,
|
|
@@ -274,7 +268,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
|
|
|
274
268
|
let state = {
|
|
275
269
|
loaderData: context.loaderData,
|
|
276
270
|
actionData: context.actionData,
|
|
277
|
-
errors:
|
|
271
|
+
errors: context.errors
|
|
278
272
|
};
|
|
279
273
|
entryContext = {
|
|
280
274
|
...entryContext,
|
|
@@ -304,7 +298,7 @@ async function handleResourceRequest(serverMode, build, staticHandler, routeId,
|
|
|
304
298
|
return handleQueryRouteError(error);
|
|
305
299
|
}
|
|
306
300
|
},
|
|
307
|
-
normalizePath: (r) => getNormalizedPath(r
|
|
301
|
+
normalizePath: (r) => getNormalizedPath(r)
|
|
308
302
|
}));
|
|
309
303
|
} catch (error) {
|
|
310
304
|
return handleQueryRouteError(error);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.0.0
|
|
2
|
+
* react-router v8.0.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -22,7 +22,7 @@ const SERVER_NO_BODY_STATUS_CODES = new Set([...NO_BODY_STATUS_CODES, 304]);
|
|
|
22
22
|
async function singleFetchAction(build, serverMode, staticHandler, request, loadContext, handleError) {
|
|
23
23
|
try {
|
|
24
24
|
try {
|
|
25
|
-
throwIfPotentialCSRFAttack(request
|
|
25
|
+
throwIfPotentialCSRFAttack(request, Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []);
|
|
26
26
|
} catch (e) {
|
|
27
27
|
return handleQueryError(/* @__PURE__ */ new Error("Bad Request"), 400);
|
|
28
28
|
}
|
|
@@ -37,7 +37,7 @@ async function singleFetchAction(build, serverMode, staticHandler, request, load
|
|
|
37
37
|
return handleQueryError(error);
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
|
-
normalizePath: (r) => getNormalizedPath(r
|
|
40
|
+
normalizePath: (r) => getNormalizedPath(r)
|
|
41
41
|
}));
|
|
42
42
|
} catch (error) {
|
|
43
43
|
return handleQueryError(error);
|
|
@@ -90,7 +90,7 @@ async function singleFetchLoaders(build, serverMode, staticHandler, request, loa
|
|
|
90
90
|
return handleQueryError(error);
|
|
91
91
|
}
|
|
92
92
|
},
|
|
93
|
-
normalizePath: (r) => getNormalizedPath(r
|
|
93
|
+
normalizePath: (r) => getNormalizedPath(r)
|
|
94
94
|
}));
|
|
95
95
|
} catch (error) {
|
|
96
96
|
return handleQueryError(error);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.0.0
|
|
2
|
+
* react-router v8.0.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -8,15 +8,12 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import { stripBasename } from "../router/utils.js";
|
|
12
11
|
//#region lib/server-runtime/urls.ts
|
|
13
|
-
function getNormalizedPath(request
|
|
14
|
-
basename = basename || "/";
|
|
12
|
+
function getNormalizedPath(request) {
|
|
15
13
|
let url = new URL(request.url);
|
|
16
14
|
let pathname = url.pathname;
|
|
17
15
|
if (pathname.endsWith("/_.data")) pathname = pathname.replace(/_\.data$/, "");
|
|
18
16
|
else pathname = pathname.replace(/\.data$/, "");
|
|
19
|
-
if (stripBasename(pathname, basename) !== "/" && pathname.endsWith("/")) pathname = pathname.slice(0, -1);
|
|
20
17
|
let searchParams = new URLSearchParams(url.search);
|
|
21
18
|
searchParams.delete("_routes");
|
|
22
19
|
let search = searchParams.toString();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.0.0
|
|
2
|
+
* react-router v8.0.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
+
import "../../lib/router/utils.js";
|
|
11
12
|
import { Deferred, createLineSplittingTransform } from "./utils.js";
|
|
12
13
|
import { flatten } from "./flatten.js";
|
|
13
14
|
import { unflatten } from "./unflatten.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.0.0
|
|
2
|
+
* react-router v8.0.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
11
|
+
import { SUPPORTED_ERROR_TYPES } from "../../lib/router/utils.js";
|
|
12
|
+
import { Deferred } from "./utils.js";
|
|
12
13
|
//#region vendor/turbo-stream-v2/unflatten.ts
|
|
13
14
|
const globalObj = typeof window !== "undefined" ? window : typeof globalThis !== "undefined" ? globalThis : void 0;
|
|
14
15
|
function unflatten(parsed) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.0.0
|
|
2
|
+
* react-router v8.0.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -9,14 +9,6 @@
|
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
11
|
//#region vendor/turbo-stream-v2/utils.ts
|
|
12
|
-
const SUPPORTED_ERROR_TYPES = [
|
|
13
|
-
"EvalError",
|
|
14
|
-
"RangeError",
|
|
15
|
-
"ReferenceError",
|
|
16
|
-
"SyntaxError",
|
|
17
|
-
"TypeError",
|
|
18
|
-
"URIError"
|
|
19
|
-
];
|
|
20
12
|
var Deferred = class {
|
|
21
13
|
promise;
|
|
22
14
|
resolve;
|
|
@@ -44,4 +36,4 @@ function createLineSplittingTransform() {
|
|
|
44
36
|
});
|
|
45
37
|
}
|
|
46
38
|
//#endregion
|
|
47
|
-
export { Deferred,
|
|
39
|
+
export { Deferred, createLineSplittingTransform };
|
|
@@ -74,4 +74,4 @@ export default function Component({ loaderData }) {
|
|
|
74
74
|
|
|
75
75
|
After building for the browser, only the `Component` will still be in the bundle, so you can use server-only code in the other module exports.
|
|
76
76
|
|
|
77
|
-
[route-module]:
|
|
77
|
+
[route-module]: ../start/framework/route-module
|
|
@@ -80,7 +80,7 @@ function Component() {
|
|
|
80
80
|
}
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
[loader]: ../
|
|
83
|
+
[loader]: ../start/data/route-object#loader
|
|
84
84
|
[form_element]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form
|
|
85
85
|
[form_component]: ../api/components/Form
|
|
86
|
-
[action]: ../
|
|
86
|
+
[action]: ../start/data/route-object#action
|
|
@@ -50,7 +50,7 @@ React Router's type generation executes your route config (`app/routes.ts` by de
|
|
|
50
50
|
It then generates a `+types/<route file>.d.ts` for each route within a special `.react-router/types/` directory.
|
|
51
51
|
With [`rootDirs` configured][route-module-type-safety], TypeScript can import these generated files as if they were right next to their corresponding route modules.
|
|
52
52
|
|
|
53
|
-
For a deeper dive into some of the design decisions, check out our [type inference decision doc](https://github.com/remix-run/react-router/blob/
|
|
53
|
+
For a deeper dive into some of the design decisions, check out our [type inference decision doc](https://github.com/remix-run/react-router/blob/main/decisions/0012-type-inference.md).
|
|
54
54
|
|
|
55
55
|
[route-module-type-safety]: ../how-to/route-module-type-safety
|
|
56
56
|
|
|
@@ -158,11 +158,11 @@ const matchesToLoad = matches.filter((match) => {
|
|
|
158
158
|
|
|
159
159
|
## Migrating away from `shouldLoad`
|
|
160
160
|
|
|
161
|
-
Now that we have stabilized the new `match.shouldCallHandler()`/`match.shouldRevalidateArgs` fields, it's recommended to move away from the now-deprecated `match.shouldLoad` API. The prior boolean approach did not allow for custom `dataStrategy`functions to alter the default revalidation behavior, so the new function-based APIs were created to allow that.
|
|
161
|
+
Now that we have stabilized the new `match.shouldCallHandler()`/`match.shouldRevalidateArgs` fields, it's recommended to move away from the now-deprecated `match.shouldLoad` API. The prior boolean approach did not allow for custom `dataStrategy` functions to alter the default revalidation behavior, so the new function-based APIs were created to allow that.
|
|
162
162
|
|
|
163
163
|
The major difference between these two APIs is that when using `shouldLoad`, calling `resolve()` would _only_ call the handler if `shouldLoad` was `true`. You could safely call it for all matches even if only a subset needed to have their handlers executed.
|
|
164
164
|
|
|
165
|
-
With `shouldCallHandler`, you are in charge of which handlers should be called so calling resolve will automatically call the handler. You should only call resolve on
|
|
165
|
+
With `shouldCallHandler`, you are in charge of which handlers should be called so calling resolve will automatically call the handler. You should only call resolve on the set of matches you wish to run handlers for.
|
|
166
166
|
|
|
167
167
|
Here's an example change from the prior API to the new API. Note that we pre-filter the `matchesToLoad` before calling `resolve()`:
|
|
168
168
|
|
|
@@ -184,9 +184,9 @@ return results;
|
|
|
184
184
|
|
|
185
185
|
<docs-info>This is an unlikely use-case now that React Router has built-in middleware, but if you wish to use a custom middleware you can do so with a `dataStrategy`.</docs-info>
|
|
186
186
|
|
|
187
|
-
Let's define a middleware on each route via [`handle`](
|
|
187
|
+
Let's define a middleware on each route via [`handle`](../start/data/route-object#handle)
|
|
188
188
|
and call middleware sequentially first, then call all
|
|
189
|
-
[`loader`](
|
|
189
|
+
[`loader`](../start/data/route-object#loader)s in parallel - providing
|
|
190
190
|
any data made available via the middleware:
|
|
191
191
|
|
|
192
192
|
```ts
|
|
@@ -258,7 +258,7 @@ let router = createBrowserRouter(routes, {
|
|
|
258
258
|
|
|
259
259
|
### Custom Handler
|
|
260
260
|
|
|
261
|
-
It's also possible you don't even want to define a [`loader`](
|
|
261
|
+
It's also possible you don't even want to define a [`loader`](../start/data/route-object#loader)
|
|
262
262
|
implementation at the route level. Maybe you want to just determine the
|
|
263
263
|
routes and issue a single GraphQL request for all of your data. You can do
|
|
264
264
|
that by setting your `route.loader=true` so it qualifies as "having a
|
|
@@ -104,7 +104,11 @@ See also:
|
|
|
104
104
|
This function is called whenever React Router catches an error in your application on the client.
|
|
105
105
|
|
|
106
106
|
```tsx
|
|
107
|
-
import {
|
|
107
|
+
import {
|
|
108
|
+
createBrowserRouter,
|
|
109
|
+
type ClientOnErrorFunction,
|
|
110
|
+
} from "react-router";
|
|
111
|
+
import { RouterProvider } from "react-router/dom";
|
|
108
112
|
|
|
109
113
|
const onError: ClientOnErrorFunction = (
|
|
110
114
|
error,
|
|
@@ -116,8 +120,12 @@ const onError: ClientOnErrorFunction = (
|
|
|
116
120
|
console.error(error, errorInfo);
|
|
117
121
|
};
|
|
118
122
|
|
|
123
|
+
const router = createBrowserRouter(routes);
|
|
124
|
+
|
|
119
125
|
function App() {
|
|
120
|
-
return
|
|
126
|
+
return (
|
|
127
|
+
<RouterProvider router={router} onError={onError} />
|
|
128
|
+
);
|
|
121
129
|
}
|
|
122
130
|
```
|
|
123
131
|
|
package/docs/how-to/headers.md
CHANGED
|
@@ -110,7 +110,8 @@ The easiest way is to simply append to the parent headers. This avoids overwriti
|
|
|
110
110
|
```tsx
|
|
111
111
|
export function headers({ parentHeaders }: HeadersArgs) {
|
|
112
112
|
parentHeaders.append(
|
|
113
|
-
"Permissions-Policy
|
|
113
|
+
"Permissions-Policy",
|
|
114
|
+
"geolocation=()",
|
|
114
115
|
);
|
|
115
116
|
return parentHeaders;
|
|
116
117
|
}
|
|
@@ -91,24 +91,18 @@ export default function Dashboard({
|
|
|
91
91
|
}
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
### 3.
|
|
94
|
+
### 3. Add a `getLoadContext` function (if applicable)
|
|
95
95
|
|
|
96
|
-
If you're using a custom server
|
|
96
|
+
If you're using a custom server, you can use a `getLoadContext` function to pass information to into the react router handlers:
|
|
97
97
|
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
+ RouterContextProvider,
|
|
102
|
-
+} from "react-router";
|
|
103
|
-
import { createDb } from "./db";
|
|
104
|
-
|
|
105
|
-
+const dbContext = createContext<Database>();
|
|
98
|
+
```tsx
|
|
99
|
+
import { RouterContextProvider } from "react-router";
|
|
100
|
+
import { dbContext, createDb } from "./db";
|
|
106
101
|
|
|
107
102
|
function getLoadContext(req, res) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
+ return context;
|
|
103
|
+
const context = new RouterContextProvider();
|
|
104
|
+
context.set(dbContext, createDb());
|
|
105
|
+
return context;
|
|
112
106
|
}
|
|
113
107
|
```
|
|
114
108
|
|
|
@@ -474,72 +468,6 @@ export const middleware: Route.MiddlewareFunction[] = [
|
|
|
474
468
|
|
|
475
469
|
Which `ErrorBoundary` is rendered will differ based on whether your middleware threw _before_ or _after_ calling then `next()` function. If it throws _after_ then it will bubble up from the throwing route just like a normal loader error because we've already run the loaders and have the appropriate `loaderData` to render in the route components. However, if an error is thrown _before_ calling `next()`, then we haven't called any loaders yet and there is no `loaderData` available. When this happens, we must bubble up to the highest route with a `loader` and start looking for an `ErrorBoundary` there. We cannot render any route components at that level or below without any `loaderData`.
|
|
476
470
|
|
|
477
|
-
## Changes to `getLoadContext`/`AppLoadContext`
|
|
478
|
-
|
|
479
|
-
<docs-info>This only applies if you are using a custom server and a custom `getLoadContext` function</docs-info>
|
|
480
|
-
|
|
481
|
-
Middleware introduces a breaking change to the `context` parameter generated by `getLoadContext` and passed to your `action`s and `loader`s. The current approach of a module-augmented `AppLoadContext` isn't really type-safe and instead just sort of tells TypeScript to "trust me".
|
|
482
|
-
|
|
483
|
-
Middleware needs an equivalent `context` on the client for `clientMiddleware`, but we didn't want to duplicate this pattern from the server that we already weren't thrilled with, so we decided to introduce a new API where we could tackle type-safety.
|
|
484
|
-
|
|
485
|
-
When opting into middleware, the `context` parameter changes to an instance of [`RouterContextProvider`][RouterContextProvider]:
|
|
486
|
-
|
|
487
|
-
```ts
|
|
488
|
-
let dbContext = createContext<Database>();
|
|
489
|
-
let context = new RouterContextProvider();
|
|
490
|
-
context.set(dbContext, getDb());
|
|
491
|
-
// ^ type-safe
|
|
492
|
-
let db = context.get(dbContext);
|
|
493
|
-
// ^ Database
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
If you're using a custom server and a `getLoadContext` function, you will need to update your implementation to return an instance of [`RouterContextProvider`][RouterContextProvider], instead of a plain JavaScript object:
|
|
497
|
-
|
|
498
|
-
```diff
|
|
499
|
-
+import {
|
|
500
|
-
+ createContext,
|
|
501
|
-
+ RouterContextProvider,
|
|
502
|
-
+} from "react-router";
|
|
503
|
-
import { createDb } from "./db";
|
|
504
|
-
|
|
505
|
-
+const dbContext = createContext<Database>();
|
|
506
|
-
|
|
507
|
-
function getLoadContext(req, res) {
|
|
508
|
-
- return { db: createDb() };
|
|
509
|
-
+ const context = new RouterContextProvider();
|
|
510
|
-
+ context.set(dbContext, createDb());
|
|
511
|
-
+ return context;
|
|
512
|
-
}
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
### Migration from `AppLoadContext`
|
|
516
|
-
|
|
517
|
-
If you're currently using `AppLoadContext`, you can migrate incrementally by using your existing module augmentation to augment [`RouterContextProvider`][RouterContextProvider] instead of `AppLoadContext`. Then, update your `getLoadContext` function to return an instance of [`RouterContextProvider`][RouterContextProvider]:
|
|
518
|
-
|
|
519
|
-
```diff
|
|
520
|
-
declare module "react-router" {
|
|
521
|
-
- interface AppLoadContext {
|
|
522
|
-
+ interface RouterContextProvider {
|
|
523
|
-
db: Database;
|
|
524
|
-
user: User;
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
function getLoadContext() {
|
|
529
|
-
const loadContext = {...};
|
|
530
|
-
- return loadContext;
|
|
531
|
-
+ let context = new RouterContextProvider();
|
|
532
|
-
+ Object.assign(context, loadContext);
|
|
533
|
-
+ return context;
|
|
534
|
-
}
|
|
535
|
-
```
|
|
536
|
-
|
|
537
|
-
This allows you to leave your `action`s/`loader`s untouched during initial adoption of middleware, since they can still read values directly (i.e., `context.db`).
|
|
538
|
-
|
|
539
|
-
<docs-warning>This approach is only intended to be used as a migration strategy when adopting middleware in React Router v7, allowing you to incrementally migrate to `context.set`/`context.get`. It is not safe to assume this approach will work in the next major version of React Router.</docs-warning>
|
|
540
|
-
|
|
541
|
-
<docs-warning>The [`RouterContextProvider`][RouterContextProvider] class is also used for the client-side `context` parameter via `<HydratedRouter getContext>` and `<RouterProvider getContext>`. Since `AppLoadContext` is primarily intended as a hand-off from your HTTP server into the React Router handlers, you need to be aware that these augmented fields will not be available in `clientMiddleware`, `clientLoader`, or `clientAction` functions even thought TypeScript will tell you they are (unless, of course, you provide the fields via `getContext` on the client).</docs-warning>
|
|
542
|
-
|
|
543
471
|
## Common Patterns
|
|
544
472
|
|
|
545
473
|
### Authentication
|
|
@@ -700,24 +628,15 @@ export async function loader({
|
|
|
700
628
|
}
|
|
701
629
|
```
|
|
702
630
|
|
|
703
|
-
[future-flags]: ../upgrading/future
|
|
704
631
|
[Response]: https://developer.mozilla.org/en-US/docs/Web/API/Response
|
|
705
632
|
[common-patterns]: #common-patterns
|
|
706
633
|
[server-client]: #server-vs-client-middleware
|
|
707
|
-
[create-browser-router]: ../api/data-routers/createBrowserRouter
|
|
708
|
-
[create-hash-router]: ../api/data-routers/createHashRouter
|
|
709
|
-
[create-memory-router]: ../api/data-routers/createMemoryRouter
|
|
710
|
-
[create-static-handler]: ../api/data-routers/createStaticHandler
|
|
711
634
|
[framework-action]: ../start/framework/route-module#action
|
|
712
635
|
[framework-loader]: ../start/framework/route-module#loader
|
|
713
|
-
[getloadcontext]: #changes-to-getloadcontextapploadcontext
|
|
714
636
|
[datastrategy]: ../api/data-routers/createBrowserRouter#optsdatastrategy
|
|
715
637
|
[cms-redirect]: #cms-redirect-on-404
|
|
716
638
|
[createContext]: ../api/utils/createContext
|
|
717
|
-
[RouterContextProvider]: ../api/utils/RouterContextProvider
|
|
718
639
|
[getContext]: ../api/data-routers/createBrowserRouter#optsgetContext
|
|
719
|
-
[window]: https://developer.mozilla.org/en-US/docs/Web/API/Window
|
|
720
|
-
[document]: https://developer.mozilla.org/en-US/docs/Web/API/Document
|
|
721
640
|
[request]: https://developer.mozilla.org/en-US/docs/Web/API/Request
|
|
722
641
|
[data-action]: ../start/data/route-object#action
|
|
723
642
|
[data-loader]: ../start/data/route-object#loader
|
package/docs/how-to/security.md
CHANGED
|
@@ -13,18 +13,20 @@ This is by no means a comprehensive guide, but React Router provides features to
|
|
|
13
13
|
|
|
14
14
|
## `Content-Security-Policy`
|
|
15
15
|
|
|
16
|
-
If you are implementing a [Content-Security-Policy (CSP)][csp] in your application, specifically one using the `unsafe-inline` directive, you will need to specify a [`nonce`][nonce] attribute on the inline `<script>` elements rendered in your HTML.
|
|
16
|
+
If you are implementing a [Content-Security-Policy (CSP)][csp] in your application, specifically one using the `unsafe-inline` directive, you will need to specify a [`nonce`][nonce] attribute on the inline `<script>` elements rendered in your HTML.
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- [`<ServerRouter nonce>`][serverrouter]
|
|
21
|
-
-
|
|
22
|
-
-
|
|
18
|
+
Add a nonce to these two spots in [`entry.server.tsx`][entryserver]:
|
|
19
|
+
|
|
20
|
+
- The [`<ServerRouter nonce>`][serverrouter] prop
|
|
21
|
+
- This will be proxied along through React Context and used for other Framework Mode components that output `nonce`-aware elements, including [`<Scripts>`][scripts], [`<ScrollRestoration>`][scrollrestoration]
|
|
22
|
+
- If those components specify their own `nonce` prop, it will override the `ServerRouter` value
|
|
23
|
+
- The `nonce` options of [`renderToPipeableStream`][renderToPipeableStream]/[`renderToReadableStream`][renderToReadableStream]
|
|
23
24
|
|
|
24
25
|
[csp]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP
|
|
26
|
+
[entryserver]: ../api/framework-conventions/entry.server.tsx
|
|
25
27
|
[nonce]: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce
|
|
26
28
|
[renderToPipeableStream]: https://react.dev/reference/react-dom/server/renderToPipeableStream
|
|
27
29
|
[renderToReadableStream]: https://react.dev/reference/react-dom/server/renderToReadableStream
|
|
28
30
|
[scripts]: ../api/components/Scripts
|
|
29
31
|
[scrollrestoration]: ../api/components/ScrollRestoration
|
|
30
|
-
[serverrouter]: ../api/
|
|
32
|
+
[serverrouter]: ../api/framework-routers/ServerRouter
|
package/docs/how-to/status.md
CHANGED
|
@@ -54,7 +54,7 @@ export async function loader({ params }: Route.ActionArgs) {
|
|
|
54
54
|
let project = await fakeDb.getProject(params.id);
|
|
55
55
|
if (!project) {
|
|
56
56
|
// throw to ErrorBoundary
|
|
57
|
-
throw data(
|
|
57
|
+
throw data("Not Found", { status: 404 });
|
|
58
58
|
}
|
|
59
59
|
return project;
|
|
60
60
|
}
|
package/docs/index.md
CHANGED
|
@@ -5,7 +5,7 @@ order: 1
|
|
|
5
5
|
|
|
6
6
|
# React Router Home
|
|
7
7
|
|
|
8
|
-
React Router is a multi-strategy router for React
|
|
8
|
+
React Router is a multi-strategy router for React. You can use it maximally as a React framework or as minimally as you want.
|
|
9
9
|
|
|
10
10
|
## Getting Started
|
|
11
11
|
|
|
@@ -29,11 +29,8 @@ These icons indicate which mode the content is relevant to.
|
|
|
29
29
|
|
|
30
30
|
Additional auto-generated reference documentation is available:
|
|
31
31
|
|
|
32
|
-
[Autogenerated Reference Docs ↗](https://api.reactrouter.com/
|
|
32
|
+
[Autogenerated Reference Docs ↗](https://api.reactrouter.com/v8/)
|
|
33
33
|
|
|
34
34
|
## Upgrading
|
|
35
35
|
|
|
36
|
-
If you are caught up on future flags, upgrading from React Router
|
|
37
|
-
|
|
38
|
-
- [Upgrade from v6](./upgrading/v6)
|
|
39
|
-
- [Upgrade from Remix](./upgrading/remix)
|
|
36
|
+
If you are caught up on future flags, [upgrading from React Router v7](./upgrading/v7) is generally non-breaking.
|
|
@@ -47,6 +47,10 @@ ReactDOM.createRoot(root).render(
|
|
|
47
47
|
);
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
<docs-info>Data Routers should not be held in React state. You should create your router
|
|
51
|
+
once outside of the React tree and pass it to `<RouterProvider>`. You can use
|
|
52
|
+
`patchRoutesOnNavigation` to add additional routes programmatically.</docs-info>
|
|
53
|
+
|
|
50
54
|
---
|
|
51
55
|
|
|
52
56
|
Next: [Routing](./routing)
|
|
@@ -240,9 +240,29 @@ createBrowserRouter([
|
|
|
240
240
|
]);
|
|
241
241
|
```
|
|
242
242
|
|
|
243
|
+
## `handle`
|
|
244
|
+
|
|
245
|
+
Route handle allows apps to add anything to a route match in `useMatches` to create abstractions (like breadcrumbs, etc.).
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
createBrowserRouter([
|
|
249
|
+
{
|
|
250
|
+
path: "/app",
|
|
251
|
+
handle: {
|
|
252
|
+
breadcrumb: "App",
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
]);
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
See also:
|
|
259
|
+
|
|
260
|
+
- [`useMatches`][use-matches]
|
|
261
|
+
|
|
243
262
|
---
|
|
244
263
|
|
|
245
264
|
Next: [Data Loading](./data-loading)
|
|
246
265
|
|
|
247
266
|
[loader-params]: https://api.reactrouter.com/v7/interfaces/react-router.LoaderFunctionArgs
|
|
248
267
|
[middleware]: ../../how-to/middleware
|
|
268
|
+
[use-matches]: ../../api/hooks/useMatches
|
|
@@ -142,7 +142,7 @@ export async function clientLoader({
|
|
|
142
142
|
}: Route.ClientLoaderArgs) {
|
|
143
143
|
const res = await fetch(`/api/products/${params.pid}`);
|
|
144
144
|
const serverData = await serverLoader();
|
|
145
|
-
return { ...serverData, ...res.json() };
|
|
145
|
+
return { ...serverData, ...(await res.json()) };
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
export default function Product({
|