@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 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 ([`bc6fefa1`](https://github.com/remix-run/react-router/commit/bc6fefa19019ce9f5250c8b5af9b8c5d3390e9d1))
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, Submission, } from "./utils";
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";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @remix-run/router v1.4.0
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; // Cleanup function for history
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
- return router;
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.toLowerCase();
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 !== "head") {
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.toLowerCase();
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 !== "head" && method !== "options") {
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: opts.formMethod || "get",
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) {