@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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix-run/router",
3
- "version": "1.14.0",
3
+ "version": "1.14.1",
4
4
  "description": "Nested/Data-driven/Framework-agnostic Routing",
5
5
  "keywords": [
6
6
  "remix",
package/router.ts CHANGED
@@ -1992,33 +1992,39 @@ export function createRouter(init: RouterInit): Router {
1992
1992
  return;
1993
1993
  }
1994
1994
 
1995
- if (deletedFetchers.has(key)) {
1996
- updateFetcherState(key, getDoneFetcher(undefined));
1997
- return;
1998
- }
1999
-
2000
- if (isRedirectResult(actionResult)) {
2001
- fetchControllers.delete(key);
2002
- if (pendingNavigationLoadId > originatingLoadId) {
2003
- // A new navigation was kicked off after our action started, so that
2004
- // should take precedence over this redirect navigation. We already
2005
- // set isRevalidationRequired so all loaders for the new route should
2006
- // fire unless opted out via shouldRevalidate
1995
+ // When using v7_fetcherPersist, we don't want errors bubbling up to the UI
1996
+ // or redirects processed for unmounted fetchers so we just revert them to
1997
+ // idle
1998
+ if (future.v7_fetcherPersist && deletedFetchers.has(key)) {
1999
+ if (isRedirectResult(actionResult) || isErrorResult(actionResult)) {
2007
2000
  updateFetcherState(key, getDoneFetcher(undefined));
2008
2001
  return;
2009
- } else {
2010
- fetchRedirectIds.add(key);
2011
- updateFetcherState(key, getLoadingFetcher(submission));
2012
- return startRedirectNavigation(state, actionResult, {
2013
- fetcherSubmission: submission,
2014
- });
2015
2002
  }
2016
- }
2003
+ // Let SuccessResult's fall through for revalidation
2004
+ } else {
2005
+ if (isRedirectResult(actionResult)) {
2006
+ fetchControllers.delete(key);
2007
+ if (pendingNavigationLoadId > originatingLoadId) {
2008
+ // A new navigation was kicked off after our action started, so that
2009
+ // should take precedence over this redirect navigation. We already
2010
+ // set isRevalidationRequired so all loaders for the new route should
2011
+ // fire unless opted out via shouldRevalidate
2012
+ updateFetcherState(key, getDoneFetcher(undefined));
2013
+ return;
2014
+ } else {
2015
+ fetchRedirectIds.add(key);
2016
+ updateFetcherState(key, getLoadingFetcher(submission));
2017
+ return startRedirectNavigation(state, actionResult, {
2018
+ fetcherSubmission: submission,
2019
+ });
2020
+ }
2021
+ }
2017
2022
 
2018
- // Process any non-redirect errors thrown
2019
- if (isErrorResult(actionResult)) {
2020
- setFetcherError(key, routeId, actionResult.error);
2021
- return;
2023
+ // Process any non-redirect errors thrown
2024
+ if (isErrorResult(actionResult)) {
2025
+ setFetcherError(key, routeId, actionResult.error);
2026
+ return;
2027
+ }
2022
2028
  }
2023
2029
 
2024
2030
  if (isDeferredResult(actionResult)) {
@@ -2248,6 +2254,8 @@ export function createRouter(init: RouterInit): Router {
2248
2254
  return;
2249
2255
  }
2250
2256
 
2257
+ // We don't want errors bubbling up or redirects followed for unmounted
2258
+ // fetchers, so short circuit here if it was removed from the UI
2251
2259
  if (deletedFetchers.has(key)) {
2252
2260
  updateFetcherState(key, getDoneFetcher(undefined));
2253
2261
  return;
@@ -3647,21 +3655,27 @@ function getMatchesToLoad(
3647
3655
  let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
3648
3656
 
3649
3657
  let navigationMatches = boundaryMatches.filter((match, index) => {
3650
- if (isInitialLoad) {
3651
- // On initial hydration we don't do any shouldRevalidate stuff - we just
3652
- // call the unhydrated loaders
3653
- return isUnhydratedRoute(state, match.route);
3654
- }
3655
-
3656
- if (match.route.lazy) {
3658
+ let { route } = match;
3659
+ if (route.lazy) {
3657
3660
  // We haven't loaded this route yet so we don't know if it's got a loader!
3658
3661
  return true;
3659
3662
  }
3660
3663
 
3661
- if (match.route.loader == null) {
3664
+ if (route.loader == null) {
3662
3665
  return false;
3663
3666
  }
3664
3667
 
3668
+ if (isInitialLoad) {
3669
+ if (route.loader.hydrate) {
3670
+ return true;
3671
+ }
3672
+ return (
3673
+ state.loaderData[route.id] === undefined &&
3674
+ // Don't re-run if the loader ran and threw an error
3675
+ (!state.errors || state.errors[route.id] === undefined)
3676
+ );
3677
+ }
3678
+
3665
3679
  // Always call the loader on new route instances and pending defer cancellations
3666
3680
  if (
3667
3681
  isNewLoader(state.loaderData, state.matches[index], match) ||
@@ -3781,23 +3795,6 @@ function getMatchesToLoad(
3781
3795
  return [navigationMatches, revalidatingFetchers];
3782
3796
  }
3783
3797
 
3784
- // Is this route unhydrated (when v7_partialHydration=true) such that we need
3785
- // to call it's loader on the initial router creation
3786
- function isUnhydratedRoute(state: RouterState, route: AgnosticDataRouteObject) {
3787
- if (!route.loader) {
3788
- return false;
3789
- }
3790
- if (route.loader.hydrate) {
3791
- return true;
3792
- }
3793
- return (
3794
- state.loaderData[route.id] === undefined &&
3795
- (!state.errors ||
3796
- // Loader ran but errored - don't re-run
3797
- state.errors[route.id] === undefined)
3798
- );
3799
- }
3800
-
3801
3798
  function isNewLoader(
3802
3799
  currentLoaderData: RouteData,
3803
3800
  currentMatch: AgnosticDataRouteMatch,
package/utils.ts CHANGED
@@ -1209,37 +1209,16 @@ export function resolveTo(
1209
1209
  // to the current location's pathname and *not* the route pathname.
1210
1210
  if (toPathname == null) {
1211
1211
  from = locationPathname;
1212
- } else if (isPathRelative) {
1213
- let fromSegments =
1214
- routePathnames.length === 0
1215
- ? []
1216
- : routePathnames[routePathnames.length - 1]
1217
- .replace(/^\//, "")
1218
- .split("/");
1219
-
1220
- if (toPathname.startsWith("..")) {
1221
- let toSegments = toPathname.split("/");
1222
-
1223
- // With relative="path", each leading .. segment means "go up one URL segment"
1224
- while (toSegments[0] === "..") {
1225
- toSegments.shift();
1226
- fromSegments.pop();
1227
- }
1228
-
1229
- to.pathname = toSegments.join("/");
1230
- }
1231
-
1232
- from = "/" + fromSegments.join("/");
1233
1212
  } else {
1234
1213
  let routePathnameIndex = routePathnames.length - 1;
1235
1214
 
1236
- if (toPathname.startsWith("..")) {
1215
+ // With relative="route" (the default), each leading .. segment means
1216
+ // "go up one route" instead of "go up one URL segment". This is a key
1217
+ // difference from how <a href> works and a major reason we call this a
1218
+ // "to" value instead of a "href".
1219
+ if (!isPathRelative && toPathname.startsWith("..")) {
1237
1220
  let toSegments = toPathname.split("/");
1238
1221
 
1239
- // With relative="route" (the default), each leading .. segment means
1240
- // "go up one route" instead of "go up one URL segment". This is a key
1241
- // difference from how <a href> works and a major reason we call this a
1242
- // "to" value instead of a "href".
1243
1222
  while (toSegments[0] === "..") {
1244
1223
  toSegments.shift();
1245
1224
  routePathnameIndex -= 1;
@@ -1248,8 +1227,6 @@ export function resolveTo(
1248
1227
  to.pathname = toSegments.join("/");
1249
1228
  }
1250
1229
 
1251
- // If there are more ".." segments than parent routes, resolve relative to
1252
- // the root / URL.
1253
1230
  from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
1254
1231
  }
1255
1232