@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/dist/router.js CHANGED
@@ -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
  *
@@ -980,34 +980,20 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative) {
980
980
  // to the current location's pathname and *not* the route pathname.
981
981
  if (toPathname == null) {
982
982
  from = locationPathname;
983
- } else if (isPathRelative) {
984
- let fromSegments = routePathnames.length === 0 ? [] : routePathnames[routePathnames.length - 1].replace(/^\//, "").split("/");
985
- if (toPathname.startsWith("..")) {
986
- let toSegments = toPathname.split("/");
987
- // With relative="path", each leading .. segment means "go up one URL segment"
988
- while (toSegments[0] === "..") {
989
- toSegments.shift();
990
- fromSegments.pop();
991
- }
992
- to.pathname = toSegments.join("/");
993
- }
994
- from = "/" + fromSegments.join("/");
995
983
  } else {
996
984
  let routePathnameIndex = routePathnames.length - 1;
997
- if (toPathname.startsWith("..")) {
985
+ // With relative="route" (the default), each leading .. segment means
986
+ // "go up one route" instead of "go up one URL segment". This is a key
987
+ // difference from how <a href> works and a major reason we call this a
988
+ // "to" value instead of a "href".
989
+ if (!isPathRelative && toPathname.startsWith("..")) {
998
990
  let toSegments = toPathname.split("/");
999
- // With relative="route" (the default), each leading .. segment means
1000
- // "go up one route" instead of "go up one URL segment". This is a key
1001
- // difference from how <a href> works and a major reason we call this a
1002
- // "to" value instead of a "href".
1003
991
  while (toSegments[0] === "..") {
1004
992
  toSegments.shift();
1005
993
  routePathnameIndex -= 1;
1006
994
  }
1007
995
  to.pathname = toSegments.join("/");
1008
996
  }
1009
- // If there are more ".." segments than parent routes, resolve relative to
1010
- // the root / URL.
1011
997
  from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
1012
998
  }
1013
999
  let path = resolvePath(to, from);
@@ -2223,31 +2209,38 @@ function createRouter(init) {
2223
2209
  }
2224
2210
  return;
2225
2211
  }
2226
- if (deletedFetchers.has(key)) {
2227
- updateFetcherState(key, getDoneFetcher(undefined));
2228
- return;
2229
- }
2230
- if (isRedirectResult(actionResult)) {
2231
- fetchControllers.delete(key);
2232
- if (pendingNavigationLoadId > originatingLoadId) {
2233
- // A new navigation was kicked off after our action started, so that
2234
- // should take precedence over this redirect navigation. We already
2235
- // set isRevalidationRequired so all loaders for the new route should
2236
- // fire unless opted out via shouldRevalidate
2212
+ // When using v7_fetcherPersist, we don't want errors bubbling up to the UI
2213
+ // or redirects processed for unmounted fetchers so we just revert them to
2214
+ // idle
2215
+ if (future.v7_fetcherPersist && deletedFetchers.has(key)) {
2216
+ if (isRedirectResult(actionResult) || isErrorResult(actionResult)) {
2237
2217
  updateFetcherState(key, getDoneFetcher(undefined));
2238
2218
  return;
2239
- } else {
2240
- fetchRedirectIds.add(key);
2241
- updateFetcherState(key, getLoadingFetcher(submission));
2242
- return startRedirectNavigation(state, actionResult, {
2243
- fetcherSubmission: submission
2244
- });
2245
2219
  }
2246
- }
2247
- // Process any non-redirect errors thrown
2248
- if (isErrorResult(actionResult)) {
2249
- setFetcherError(key, routeId, actionResult.error);
2250
- return;
2220
+ // Let SuccessResult's fall through for revalidation
2221
+ } else {
2222
+ if (isRedirectResult(actionResult)) {
2223
+ fetchControllers.delete(key);
2224
+ if (pendingNavigationLoadId > originatingLoadId) {
2225
+ // A new navigation was kicked off after our action started, so that
2226
+ // should take precedence over this redirect navigation. We already
2227
+ // set isRevalidationRequired so all loaders for the new route should
2228
+ // fire unless opted out via shouldRevalidate
2229
+ updateFetcherState(key, getDoneFetcher(undefined));
2230
+ return;
2231
+ } else {
2232
+ fetchRedirectIds.add(key);
2233
+ updateFetcherState(key, getLoadingFetcher(submission));
2234
+ return startRedirectNavigation(state, actionResult, {
2235
+ fetcherSubmission: submission
2236
+ });
2237
+ }
2238
+ }
2239
+ // Process any non-redirect errors thrown
2240
+ if (isErrorResult(actionResult)) {
2241
+ setFetcherError(key, routeId, actionResult.error);
2242
+ return;
2243
+ }
2251
2244
  }
2252
2245
  if (isDeferredResult(actionResult)) {
2253
2246
  throw getInternalRouterError(400, {
@@ -2375,6 +2368,8 @@ function createRouter(init) {
2375
2368
  if (fetchRequest.signal.aborted) {
2376
2369
  return;
2377
2370
  }
2371
+ // We don't want errors bubbling up or redirects followed for unmounted
2372
+ // fetchers, so short circuit here if it was removed from the UI
2378
2373
  if (deletedFetchers.has(key)) {
2379
2374
  updateFetcherState(key, getDoneFetcher(undefined));
2380
2375
  return;
@@ -3387,18 +3382,24 @@ function getMatchesToLoad(history, state, matches, submission, location, isIniti
3387
3382
  let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;
3388
3383
  let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
3389
3384
  let navigationMatches = boundaryMatches.filter((match, index) => {
3390
- if (isInitialLoad) {
3391
- // On initial hydration we don't do any shouldRevalidate stuff - we just
3392
- // call the unhydrated loaders
3393
- return isUnhydratedRoute(state, match.route);
3394
- }
3395
- if (match.route.lazy) {
3385
+ let {
3386
+ route
3387
+ } = match;
3388
+ if (route.lazy) {
3396
3389
  // We haven't loaded this route yet so we don't know if it's got a loader!
3397
3390
  return true;
3398
3391
  }
3399
- if (match.route.loader == null) {
3392
+ if (route.loader == null) {
3400
3393
  return false;
3401
3394
  }
3395
+ if (isInitialLoad) {
3396
+ if (route.loader.hydrate) {
3397
+ return true;
3398
+ }
3399
+ return state.loaderData[route.id] === undefined && (
3400
+ // Don't re-run if the loader ran and threw an error
3401
+ !state.errors || state.errors[route.id] === undefined);
3402
+ }
3402
3403
  // Always call the loader on new route instances and pending defer cancellations
3403
3404
  if (isNewLoader(state.loaderData, state.matches[index], match) || cancelledDeferredRoutes.some(id => id === match.route.id)) {
3404
3405
  return true;
@@ -3495,19 +3496,6 @@ function getMatchesToLoad(history, state, matches, submission, location, isIniti
3495
3496
  });
3496
3497
  return [navigationMatches, revalidatingFetchers];
3497
3498
  }
3498
- // Is this route unhydrated (when v7_partialHydration=true) such that we need
3499
- // to call it's loader on the initial router creation
3500
- function isUnhydratedRoute(state, route) {
3501
- if (!route.loader) {
3502
- return false;
3503
- }
3504
- if (route.loader.hydrate) {
3505
- return true;
3506
- }
3507
- return state.loaderData[route.id] === undefined && (!state.errors ||
3508
- // Loader ran but errored - don't re-run
3509
- state.errors[route.id] === undefined);
3510
- }
3511
3499
  function isNewLoader(currentLoaderData, currentMatch, match) {
3512
3500
  let isNew =
3513
3501
  // [a] -> [a, b]