@remix-run/router 1.14.0 → 1.14.1

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