@remix-run/router 1.4.0 → 1.5.0-pre.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 +20 -1
- package/dist/index.d.ts +1 -1
- package/dist/router.cjs.js +49 -42
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +15 -8
- package/dist/router.js +49 -42
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +49 -42
- package/dist/router.umd.js.map +1 -1
- package/dist/router.umd.min.js +2 -2
- package/dist/router.umd.min.js.map +1 -1
- package/dist/utils.d.ts +20 -3
- package/index.ts +2 -1
- package/package.json +1 -1
- package/router.ts +93 -58
- package/utils.ts +23 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# `@remix-run/router`
|
|
2
2
|
|
|
3
|
+
## 1.5.0-pre.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Added support for [**Future Flags**](https://reactrouter.com/en/main/guides/api-development-strategy) in React Router. The first flag being introduced is `future.v7_normalizeFormMethod` which will normalize the exposed `useNavigation()/useFetcher()` `formMethod` fields as uppercase HTTP methods to align with the `fetch()` behavior. ([#10207](https://github.com/remix-run/react-router/pull/10207))
|
|
8
|
+
|
|
9
|
+
- When `future.v7_normalizeFormMethod === false` (default v6 behavior),
|
|
10
|
+
- `useNavigation().formMethod` is lowercase
|
|
11
|
+
- `useFetcher().formMethod` is lowercase
|
|
12
|
+
- When `future.v7_normalizeFormMethod === true`:
|
|
13
|
+
- `useNavigation().formMethod` is uppercase
|
|
14
|
+
- `useFetcher().formMethod` is uppercase
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Provide fetcher submission to `shouldRevalidate` if the fetcher action redirects ([#10208](https://github.com/remix-run/react-router/pull/10208))
|
|
19
|
+
- Properly handle `lazy()` errors during router initialization ([#10201](https://github.com/remix-run/react-router/pull/10201))
|
|
20
|
+
- Update to latest `@remix-run/web-fetch@4.3.3` ([#10216](https://github.com/remix-run/react-router/pull/10216))
|
|
21
|
+
|
|
3
22
|
## 1.4.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
|
@@ -64,7 +83,7 @@
|
|
|
64
83
|
|
|
65
84
|
### Patch Changes
|
|
66
85
|
|
|
67
|
-
- Fix `generatePath` incorrectly applying parameters in some cases ([
|
|
86
|
+
- Fix `generatePath` incorrectly applying parameters in some cases ([#10078](https://github.com/remix-run/react-router/pull/10078))
|
|
68
87
|
|
|
69
88
|
## 1.3.3
|
|
70
89
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { ActionFunction, ActionFunctionArgs, AgnosticDataIndexRouteObject, AgnosticDataNonIndexRouteObject, AgnosticDataRouteMatch, AgnosticDataRouteObject, AgnosticIndexRouteObject, AgnosticNonIndexRouteObject, AgnosticRouteMatch, AgnosticRouteObject, LazyRouteFunction, TrackedPromise, FormEncType, FormMethod, JsonFunction, LoaderFunction, LoaderFunctionArgs, ParamParseKey, Params, PathMatch, PathPattern, RedirectFunction, ShouldRevalidateFunction,
|
|
1
|
+
export type { ActionFunction, ActionFunctionArgs, AgnosticDataIndexRouteObject, AgnosticDataNonIndexRouteObject, AgnosticDataRouteMatch, AgnosticDataRouteObject, AgnosticIndexRouteObject, AgnosticNonIndexRouteObject, AgnosticRouteMatch, AgnosticRouteObject, LazyRouteFunction, TrackedPromise, FormEncType, FormMethod, HTMLFormMethod, JsonFunction, LoaderFunction, LoaderFunctionArgs, ParamParseKey, Params, PathMatch, PathPattern, RedirectFunction, ShouldRevalidateFunction, V7_FormMethod, } from "./utils";
|
|
2
2
|
export { AbortedDeferredError, ErrorResponse, defer, generatePath, getToPathname, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, redirect, resolvePath, resolveTo, stripBasename, } from "./utils";
|
|
3
3
|
export type { BrowserHistory, BrowserHistoryOptions, HashHistory, HashHistoryOptions, History, InitialEntry, Location, MemoryHistory, MemoryHistoryOptions, Path, To, } from "./history";
|
|
4
4
|
export { Action, createBrowserHistory, createPath, createHashHistory, createMemoryHistory, parsePath, } from "./history";
|
package/dist/router.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/router v1.
|
|
2
|
+
* @remix-run/router v1.5.0-pre.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -1488,7 +1488,12 @@ function createRouter(init) {
|
|
|
1488
1488
|
let manifest = {}; // Routes in tree format for matching
|
|
1489
1489
|
|
|
1490
1490
|
let dataRoutes = convertRoutesToDataRoutes(init.routes, detectErrorBoundary, undefined, manifest);
|
|
1491
|
-
let inFlightDataRoutes; //
|
|
1491
|
+
let inFlightDataRoutes; // Config driven behavior flags
|
|
1492
|
+
|
|
1493
|
+
let future = _extends({
|
|
1494
|
+
v7_normalizeFormMethod: false
|
|
1495
|
+
}, init.future); // Cleanup function for history
|
|
1496
|
+
|
|
1492
1497
|
|
|
1493
1498
|
let unlistenHistory = null; // Externally-provided functions to call on all state changes
|
|
1494
1499
|
|
|
@@ -1652,35 +1657,16 @@ function createRouter(init) {
|
|
|
1652
1657
|
}
|
|
1653
1658
|
|
|
1654
1659
|
return startNavigation(historyAction, location);
|
|
1655
|
-
});
|
|
1660
|
+
}); // Kick off initial data load if needed. Use Pop to avoid modifying history
|
|
1661
|
+
// Note we don't do any handling of lazy here. For SPA's it'll get handled
|
|
1662
|
+
// in the normal navigation flow. For SSR it's expected that lazy modules are
|
|
1663
|
+
// resolved prior to router creation since we can't go into a fallbackElement
|
|
1664
|
+
// UI for SSR'd apps
|
|
1656
1665
|
|
|
1657
|
-
if (state.initialized) {
|
|
1658
|
-
return router;
|
|
1659
|
-
}
|
|
1660
|
-
|
|
1661
|
-
let lazyMatches = state.matches.filter(m => m.route.lazy);
|
|
1662
|
-
|
|
1663
|
-
if (lazyMatches.length === 0) {
|
|
1664
|
-
// Kick off initial data load if needed. Use Pop to avoid modifying history
|
|
1666
|
+
if (!state.initialized) {
|
|
1665
1667
|
startNavigation(exports.Action.Pop, state.location);
|
|
1666
|
-
|
|
1667
|
-
} // Load lazy modules, then kick off initial data load if needed
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
let lazyPromises = lazyMatches.map(m => loadLazyRouteModule(m.route, detectErrorBoundary, manifest));
|
|
1671
|
-
Promise.all(lazyPromises).then(() => {
|
|
1672
|
-
let initialized = !state.matches.some(m => m.route.loader) || init.hydrationData != null;
|
|
1668
|
+
}
|
|
1673
1669
|
|
|
1674
|
-
if (initialized) {
|
|
1675
|
-
// We already have required loaderData so we can just set initialized
|
|
1676
|
-
updateState({
|
|
1677
|
-
initialized: true
|
|
1678
|
-
});
|
|
1679
|
-
} else {
|
|
1680
|
-
// We still need to kick off initial data loads
|
|
1681
|
-
startNavigation(exports.Action.Pop, state.location);
|
|
1682
|
-
}
|
|
1683
|
-
});
|
|
1684
1670
|
return router;
|
|
1685
1671
|
} // Clean up a router and it's side effects
|
|
1686
1672
|
|
|
@@ -1797,7 +1783,7 @@ function createRouter(init) {
|
|
|
1797
1783
|
path,
|
|
1798
1784
|
submission,
|
|
1799
1785
|
error
|
|
1800
|
-
} = normalizeNavigateOptions(to, opts);
|
|
1786
|
+
} = normalizeNavigateOptions(to, future, opts);
|
|
1801
1787
|
let currentLocation = state.location;
|
|
1802
1788
|
let nextLocation = createLocation(state.location, path, opts && opts.state); // When using navigate as a PUSH/REPLACE we aren't reading an already-encoded
|
|
1803
1789
|
// URL from window.location, so we need to encode it here so the behavior
|
|
@@ -1989,7 +1975,7 @@ function createRouter(init) {
|
|
|
1989
1975
|
shortCircuited,
|
|
1990
1976
|
loaderData,
|
|
1991
1977
|
errors
|
|
1992
|
-
} = await handleLoaders(request, location, matches, loadingNavigation, opts && opts.submission, opts && opts.replace, pendingActionData, pendingError);
|
|
1978
|
+
} = await handleLoaders(request, location, matches, loadingNavigation, opts && opts.submission, opts && opts.fetcherSubmission, opts && opts.replace, pendingActionData, pendingError);
|
|
1993
1979
|
|
|
1994
1980
|
if (shortCircuited) {
|
|
1995
1981
|
return;
|
|
@@ -2102,7 +2088,7 @@ function createRouter(init) {
|
|
|
2102
2088
|
// errors, etc.
|
|
2103
2089
|
|
|
2104
2090
|
|
|
2105
|
-
async function handleLoaders(request, location, matches, overrideNavigation, submission, replace, pendingActionData, pendingError) {
|
|
2091
|
+
async function handleLoaders(request, location, matches, overrideNavigation, submission, fetcherSubmission, replace, pendingActionData, pendingError) {
|
|
2106
2092
|
// Figure out the right navigation we want to use for data loading
|
|
2107
2093
|
let loadingNavigation = overrideNavigation;
|
|
2108
2094
|
|
|
@@ -2121,7 +2107,7 @@ function createRouter(init) {
|
|
|
2121
2107
|
// we have it on the loading navigation so use that if available
|
|
2122
2108
|
|
|
2123
2109
|
|
|
2124
|
-
let activeSubmission = submission ? submission : loadingNavigation.formMethod && loadingNavigation.formAction && loadingNavigation.formData && loadingNavigation.formEncType ? {
|
|
2110
|
+
let activeSubmission = submission || fetcherSubmission ? submission || fetcherSubmission : loadingNavigation.formMethod && loadingNavigation.formAction && loadingNavigation.formData && loadingNavigation.formEncType ? {
|
|
2125
2111
|
formMethod: loadingNavigation.formMethod,
|
|
2126
2112
|
formAction: loadingNavigation.formAction,
|
|
2127
2113
|
formData: loadingNavigation.formData,
|
|
@@ -2258,7 +2244,7 @@ function createRouter(init) {
|
|
|
2258
2244
|
let {
|
|
2259
2245
|
path,
|
|
2260
2246
|
submission
|
|
2261
|
-
} = normalizeNavigateOptions(href, opts, true);
|
|
2247
|
+
} = normalizeNavigateOptions(href, future, opts, true);
|
|
2262
2248
|
let match = getTargetMatch(matches, path);
|
|
2263
2249
|
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
2264
2250
|
|
|
@@ -2338,6 +2324,7 @@ function createRouter(init) {
|
|
|
2338
2324
|
fetchers: new Map(state.fetchers)
|
|
2339
2325
|
});
|
|
2340
2326
|
return startRedirectNavigation(state, actionResult, {
|
|
2327
|
+
submission,
|
|
2341
2328
|
isFetchActionRedirect: true
|
|
2342
2329
|
});
|
|
2343
2330
|
} // Process any non-redirect errors thrown
|
|
@@ -2628,6 +2615,22 @@ function createRouter(init) {
|
|
|
2628
2615
|
// Preserve this flag across redirects
|
|
2629
2616
|
preventScrollReset: pendingPreventScrollReset
|
|
2630
2617
|
});
|
|
2618
|
+
} else if (isFetchActionRedirect) {
|
|
2619
|
+
// For a fetch action redirect, we kick off a new loading navigation
|
|
2620
|
+
// without the fetcher submission, but we send it along for shouldRevalidate
|
|
2621
|
+
await startNavigation(redirectHistoryAction, redirectLocation, {
|
|
2622
|
+
overrideNavigation: {
|
|
2623
|
+
state: "loading",
|
|
2624
|
+
location: redirectLocation,
|
|
2625
|
+
formMethod: undefined,
|
|
2626
|
+
formAction: undefined,
|
|
2627
|
+
formEncType: undefined,
|
|
2628
|
+
formData: undefined
|
|
2629
|
+
},
|
|
2630
|
+
fetcherSubmission: submission,
|
|
2631
|
+
// Preserve this flag across redirects
|
|
2632
|
+
preventScrollReset: pendingPreventScrollReset
|
|
2633
|
+
});
|
|
2631
2634
|
} else {
|
|
2632
2635
|
// Otherwise, we kick off a new loading navigation, preserving the
|
|
2633
2636
|
// submission info for the duration of this navigation
|
|
@@ -2973,11 +2976,11 @@ function createStaticHandler(routes, opts) {
|
|
|
2973
2976
|
requestContext
|
|
2974
2977
|
} = _temp2 === void 0 ? {} : _temp2;
|
|
2975
2978
|
let url = new URL(request.url);
|
|
2976
|
-
let method = request.method
|
|
2979
|
+
let method = request.method;
|
|
2977
2980
|
let location = createLocation("", createPath(url), null, "default");
|
|
2978
2981
|
let matches = matchRoutes(dataRoutes, location, basename); // SSR supports HEAD requests while SPA doesn't
|
|
2979
2982
|
|
|
2980
|
-
if (!isValidMethod(method) && method !== "
|
|
2983
|
+
if (!isValidMethod(method) && method !== "HEAD") {
|
|
2981
2984
|
let error = getInternalRouterError(405, {
|
|
2982
2985
|
method
|
|
2983
2986
|
});
|
|
@@ -3065,11 +3068,11 @@ function createStaticHandler(routes, opts) {
|
|
|
3065
3068
|
requestContext
|
|
3066
3069
|
} = _temp3 === void 0 ? {} : _temp3;
|
|
3067
3070
|
let url = new URL(request.url);
|
|
3068
|
-
let method = request.method
|
|
3071
|
+
let method = request.method;
|
|
3069
3072
|
let location = createLocation("", createPath(url), null, "default");
|
|
3070
3073
|
let matches = matchRoutes(dataRoutes, location, basename); // SSR supports HEAD requests while SPA doesn't
|
|
3071
3074
|
|
|
3072
|
-
if (!isValidMethod(method) && method !== "
|
|
3075
|
+
if (!isValidMethod(method) && method !== "HEAD" && method !== "OPTIONS") {
|
|
3073
3076
|
throw getInternalRouterError(405, {
|
|
3074
3077
|
method
|
|
3075
3078
|
});
|
|
@@ -3362,7 +3365,7 @@ function isSubmissionNavigation(opts) {
|
|
|
3362
3365
|
// URLSearchParams so they behave identically to links with query params
|
|
3363
3366
|
|
|
3364
3367
|
|
|
3365
|
-
function normalizeNavigateOptions(to, opts, isFetcher) {
|
|
3368
|
+
function normalizeNavigateOptions(to, future, opts, isFetcher) {
|
|
3366
3369
|
if (isFetcher === void 0) {
|
|
3367
3370
|
isFetcher = false;
|
|
3368
3371
|
}
|
|
@@ -3388,8 +3391,9 @@ function normalizeNavigateOptions(to, opts, isFetcher) {
|
|
|
3388
3391
|
let submission;
|
|
3389
3392
|
|
|
3390
3393
|
if (opts.formData) {
|
|
3394
|
+
let formMethod = opts.formMethod || "get";
|
|
3391
3395
|
submission = {
|
|
3392
|
-
formMethod:
|
|
3396
|
+
formMethod: future.v7_normalizeFormMethod ? formMethod.toUpperCase() : formMethod.toLowerCase(),
|
|
3393
3397
|
formAction: stripHashFromPath(path),
|
|
3394
3398
|
formEncType: opts && opts.formEncType || "application/x-www-form-urlencoded",
|
|
3395
3399
|
formData: opts.formData
|
|
@@ -3829,7 +3833,10 @@ function createClientSideRequest(history, location, signal, submission) {
|
|
|
3829
3833
|
formMethod,
|
|
3830
3834
|
formEncType,
|
|
3831
3835
|
formData
|
|
3832
|
-
} = submission;
|
|
3836
|
+
} = submission; // Didn't think we needed this but it turns out unlike other methods, patch
|
|
3837
|
+
// won't be properly normalized to uppercase and results in a 405 error.
|
|
3838
|
+
// See: https://fetch.spec.whatwg.org/#concept-method
|
|
3839
|
+
|
|
3833
3840
|
init.method = formMethod.toUpperCase();
|
|
3834
3841
|
init.body = formEncType === "application/x-www-form-urlencoded" ? convertFormDataToSearchParams(formData) : formData;
|
|
3835
3842
|
} // Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)
|
|
@@ -4118,11 +4125,11 @@ function isQueryRouteResponse(obj) {
|
|
|
4118
4125
|
}
|
|
4119
4126
|
|
|
4120
4127
|
function isValidMethod(method) {
|
|
4121
|
-
return validRequestMethods.has(method);
|
|
4128
|
+
return validRequestMethods.has(method.toLowerCase());
|
|
4122
4129
|
}
|
|
4123
4130
|
|
|
4124
4131
|
function isMutationMethod(method) {
|
|
4125
|
-
return validMutationMethods.has(method);
|
|
4132
|
+
return validMutationMethods.has(method.toLowerCase());
|
|
4126
4133
|
}
|
|
4127
4134
|
|
|
4128
4135
|
async function resolveDeferredResults(currentMatches, matchesToLoad, results, signal, isFetcher, currentLoaderData) {
|