@remix-run/router 1.14.0-pre.1 → 1.14.1-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,12 +1,14 @@
1
1
  # `@remix-run/router`
2
2
 
3
- ## 1.14.0-pre.1
3
+ ## 1.14.1-pre.0
4
4
 
5
5
  ### Patch Changes
6
6
 
7
- - [REMOVE] Refactor internals for partial hydration ([#11094](https://github.com/remix-run/react-router/pull/11094))
7
+ - Fix bug with `route.lazy` not working correctly on initial SPA load when `v7_partialHydration` is specified ([#11121](https://github.com/remix-run/react-router/pull/11121))
8
+ - Fix bug preventing revalidation from occurring for persisted fetchers unmounted during the `submitting` phase ([#11102](https://github.com/remix-run/react-router/pull/11102))
9
+ - De-dup relative path logic in `resolveTo` ([#11097](https://github.com/remix-run/react-router/pull/11097))
8
10
 
9
- ## 1.14.0-pre.0
11
+ ## 1.14.0
10
12
 
11
13
  ### Minor Changes
12
14
 
@@ -155,7 +157,7 @@
155
157
  <BrowserRouter>
156
158
  <Routes>
157
159
  <Route path="dashboard">
158
- <Route path="*" element={<Dashboard />} />
160
+ <Route index path="*" element={<Dashboard />} />
159
161
  </Route>
160
162
  </Routes>
161
163
  </BrowserRouter>
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @remix-run/router v1.14.0-pre.1
2
+ * @remix-run/router v1.14.1-pre.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1237,37 +1237,21 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative) {
1237
1237
  // to the current location's pathname and *not* the route pathname.
1238
1238
  if (toPathname == null) {
1239
1239
  from = locationPathname;
1240
- } else if (isPathRelative) {
1241
- let fromSegments = routePathnames.length === 0 ? [] : routePathnames[routePathnames.length - 1].replace(/^\//, "").split("/");
1242
- if (toPathname.startsWith("..")) {
1243
- let toSegments = toPathname.split("/");
1244
-
1245
- // With relative="path", each leading .. segment means "go up one URL segment"
1246
- while (toSegments[0] === "..") {
1247
- toSegments.shift();
1248
- fromSegments.pop();
1249
- }
1250
- to.pathname = toSegments.join("/");
1251
- }
1252
- from = "/" + fromSegments.join("/");
1253
1240
  } else {
1254
1241
  let routePathnameIndex = routePathnames.length - 1;
1255
- if (toPathname.startsWith("..")) {
1256
- let toSegments = toPathname.split("/");
1257
1242
 
1258
- // With relative="route" (the default), each leading .. segment means
1259
- // "go up one route" instead of "go up one URL segment". This is a key
1260
- // difference from how <a href> works and a major reason we call this a
1261
- // "to" value instead of a "href".
1243
+ // With relative="route" (the default), each leading .. segment means
1244
+ // "go up one route" instead of "go up one URL segment". This is a key
1245
+ // difference from how <a href> works and a major reason we call this a
1246
+ // "to" value instead of a "href".
1247
+ if (!isPathRelative && toPathname.startsWith("..")) {
1248
+ let toSegments = toPathname.split("/");
1262
1249
  while (toSegments[0] === "..") {
1263
1250
  toSegments.shift();
1264
1251
  routePathnameIndex -= 1;
1265
1252
  }
1266
1253
  to.pathname = toSegments.join("/");
1267
1254
  }
1268
-
1269
- // If there are more ".." segments than parent routes, resolve relative to
1270
- // the root / URL.
1271
1255
  from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
1272
1256
  }
1273
1257
  let path = resolvePath(to, from);
@@ -2644,32 +2628,40 @@ function createRouter(init) {
2644
2628
  }
2645
2629
  return;
2646
2630
  }
2647
- if (deletedFetchers.has(key)) {
2648
- updateFetcherState(key, getDoneFetcher(undefined));
2649
- return;
2650
- }
2651
- if (isRedirectResult(actionResult)) {
2652
- fetchControllers.delete(key);
2653
- if (pendingNavigationLoadId > originatingLoadId) {
2654
- // A new navigation was kicked off after our action started, so that
2655
- // should take precedence over this redirect navigation. We already
2656
- // set isRevalidationRequired so all loaders for the new route should
2657
- // fire unless opted out via shouldRevalidate
2631
+
2632
+ // When using v7_fetcherPersist, we don't want errors bubbling up to the UI
2633
+ // or redirects processed for unmounted fetchers so we just revert them to
2634
+ // idle
2635
+ if (future.v7_fetcherPersist && deletedFetchers.has(key)) {
2636
+ if (isRedirectResult(actionResult) || isErrorResult(actionResult)) {
2658
2637
  updateFetcherState(key, getDoneFetcher(undefined));
2659
2638
  return;
2660
- } else {
2661
- fetchRedirectIds.add(key);
2662
- updateFetcherState(key, getLoadingFetcher(submission));
2663
- return startRedirectNavigation(state, actionResult, {
2664
- fetcherSubmission: submission
2665
- });
2666
2639
  }
2667
- }
2640
+ // Let SuccessResult's fall through for revalidation
2641
+ } else {
2642
+ if (isRedirectResult(actionResult)) {
2643
+ fetchControllers.delete(key);
2644
+ if (pendingNavigationLoadId > originatingLoadId) {
2645
+ // A new navigation was kicked off after our action started, so that
2646
+ // should take precedence over this redirect navigation. We already
2647
+ // set isRevalidationRequired so all loaders for the new route should
2648
+ // fire unless opted out via shouldRevalidate
2649
+ updateFetcherState(key, getDoneFetcher(undefined));
2650
+ return;
2651
+ } else {
2652
+ fetchRedirectIds.add(key);
2653
+ updateFetcherState(key, getLoadingFetcher(submission));
2654
+ return startRedirectNavigation(state, actionResult, {
2655
+ fetcherSubmission: submission
2656
+ });
2657
+ }
2658
+ }
2668
2659
 
2669
- // Process any non-redirect errors thrown
2670
- if (isErrorResult(actionResult)) {
2671
- setFetcherError(key, routeId, actionResult.error);
2672
- return;
2660
+ // Process any non-redirect errors thrown
2661
+ if (isErrorResult(actionResult)) {
2662
+ setFetcherError(key, routeId, actionResult.error);
2663
+ return;
2664
+ }
2673
2665
  }
2674
2666
  if (isDeferredResult(actionResult)) {
2675
2667
  throw getInternalRouterError(400, {
@@ -2806,6 +2798,9 @@ function createRouter(init) {
2806
2798
  if (fetchRequest.signal.aborted) {
2807
2799
  return;
2808
2800
  }
2801
+
2802
+ // We don't want errors bubbling up or redirects followed for unmounted
2803
+ // fetchers, so short circuit here if it was removed from the UI
2809
2804
  if (deletedFetchers.has(key)) {
2810
2805
  updateFetcherState(key, getDoneFetcher(undefined));
2811
2806
  return;
@@ -3864,18 +3859,24 @@ function getMatchesToLoad(history, state, matches, submission, location, isIniti
3864
3859
  let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;
3865
3860
  let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
3866
3861
  let navigationMatches = boundaryMatches.filter((match, index) => {
3867
- if (isInitialLoad) {
3868
- // On initial hydration we don't do any shouldRevalidate stuff - we just
3869
- // call the unhydrated loaders
3870
- return isUnhydratedRoute(state, match.route);
3871
- }
3872
- if (match.route.lazy) {
3862
+ let {
3863
+ route
3864
+ } = match;
3865
+ if (route.lazy) {
3873
3866
  // We haven't loaded this route yet so we don't know if it's got a loader!
3874
3867
  return true;
3875
3868
  }
3876
- if (match.route.loader == null) {
3869
+ if (route.loader == null) {
3877
3870
  return false;
3878
3871
  }
3872
+ if (isInitialLoad) {
3873
+ if (route.loader.hydrate) {
3874
+ return true;
3875
+ }
3876
+ return state.loaderData[route.id] === undefined && (
3877
+ // Don't re-run if the loader ran and threw an error
3878
+ !state.errors || state.errors[route.id] === undefined);
3879
+ }
3879
3880
 
3880
3881
  // Always call the loader on new route instances and pending defer cancellations
3881
3882
  if (isNewLoader(state.loaderData, state.matches[index], match) || cancelledDeferredRoutes.some(id => id === match.route.id)) {
@@ -3977,20 +3978,6 @@ function getMatchesToLoad(history, state, matches, submission, location, isIniti
3977
3978
  });
3978
3979
  return [navigationMatches, revalidatingFetchers];
3979
3980
  }
3980
-
3981
- // Is this route unhydrated (when v7_partialHydration=true) such that we need
3982
- // to call it's loader on the initial router creation
3983
- function isUnhydratedRoute(state, route) {
3984
- if (!route.loader) {
3985
- return false;
3986
- }
3987
- if (route.loader.hydrate) {
3988
- return true;
3989
- }
3990
- return state.loaderData[route.id] === undefined && (!state.errors ||
3991
- // Loader ran but errored - don't re-run
3992
- state.errors[route.id] === undefined);
3993
- }
3994
3981
  function isNewLoader(currentLoaderData, currentMatch, match) {
3995
3982
  let isNew =
3996
3983
  // [a] -> [a, b]