@remix-run/router 1.19.0 → 1.19.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.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { History, Location, Path, To } from "./history";
2
2
  import { Action as HistoryAction } from "./history";
3
- import type { AgnosticDataRouteMatch, AgnosticDataRouteObject, AgnosticRouteObject, DataStrategyFunction, DeferredData, DetectErrorBoundaryFunction, FormEncType, HTMLFormMethod, MapRoutePropertiesFunction, RouteData, Submission, UIMatch, AgnosticPatchRoutesOnMissFunction, DataWithResponseInit } from "./utils";
3
+ import type { AgnosticDataRouteMatch, AgnosticDataRouteObject, AgnosticRouteObject, DataStrategyFunction, DeferredData, DetectErrorBoundaryFunction, FormEncType, HTMLFormMethod, MapRoutePropertiesFunction, RouteData, Submission, UIMatch, AgnosticPatchRoutesOnNavigationFunction, DataWithResponseInit } from "./utils";
4
4
  /**
5
5
  * A Router instance manages all navigation and data loading/mutations
6
6
  */
@@ -285,7 +285,7 @@ export interface RouterInit {
285
285
  future?: Partial<FutureConfig>;
286
286
  hydrationData?: HydrationState;
287
287
  window?: Window;
288
- unstable_patchRoutesOnMiss?: AgnosticPatchRoutesOnMissFunction;
288
+ unstable_patchRoutesOnNavigation?: AgnosticPatchRoutesOnNavigationFunction;
289
289
  unstable_dataStrategy?: DataStrategyFunction;
290
290
  }
291
291
  /**
package/dist/router.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @remix-run/router v1.19.0
2
+ * @remix-run/router v1.19.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1363,7 +1363,7 @@ function createRouter(init) {
1363
1363
  let inFlightDataRoutes;
1364
1364
  let basename = init.basename || "/";
1365
1365
  let dataStrategyImpl = init.unstable_dataStrategy || defaultDataStrategy;
1366
- let patchRoutesOnMissImpl = init.unstable_patchRoutesOnMiss;
1366
+ let patchRoutesOnNavigationImpl = init.unstable_patchRoutesOnNavigation;
1367
1367
  // Config driven behavior flags
1368
1368
  let future = _extends({
1369
1369
  v7_fetcherPersist: false,
@@ -1377,6 +1377,10 @@ function createRouter(init) {
1377
1377
  let unlistenHistory = null;
1378
1378
  // Externally-provided functions to call on all state changes
1379
1379
  let subscribers = new Set();
1380
+ // FIFO queue of previously discovered routes to prevent re-calling on
1381
+ // subsequent navigations to the same path
1382
+ let discoveredRoutesMaxSize = 1000;
1383
+ let discoveredRoutes = new Set();
1380
1384
  // Externally-provided object to hold scroll restoration locations during routing
1381
1385
  let savedScrollPositions = null;
1382
1386
  // Externally-provided function to get scroll restoration keys
@@ -1392,7 +1396,7 @@ function createRouter(init) {
1392
1396
  let initialScrollRestored = init.hydrationData != null;
1393
1397
  let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);
1394
1398
  let initialErrors = null;
1395
- if (initialMatches == null && !patchRoutesOnMissImpl) {
1399
+ if (initialMatches == null && !patchRoutesOnNavigationImpl) {
1396
1400
  // If we do not match a user-provided-route, fall back to the root
1397
1401
  // to allow the error boundary to take over
1398
1402
  let error = getInternalRouterError(404, {
@@ -1407,7 +1411,7 @@ function createRouter(init) {
1407
1411
  [route.id]: error
1408
1412
  };
1409
1413
  }
1410
- // In SPA apps, if the user provided a patchRoutesOnMiss implementation and
1414
+ // In SPA apps, if the user provided a patchRoutesOnNavigation implementation and
1411
1415
  // our initial match is a splat route, clear them out so we run through lazy
1412
1416
  // discovery on hydration in case there's a more accurate lazy route match.
1413
1417
  // In SSR apps (with `hydrationData`), we expect that the server will send
@@ -1424,7 +1428,7 @@ function createRouter(init) {
1424
1428
  initialized = false;
1425
1429
  initialMatches = [];
1426
1430
  // If partial hydration and fog of war is enabled, we will be running
1427
- // `patchRoutesOnMiss` during hydration so include any partial matches as
1431
+ // `patchRoutesOnNavigation` during hydration so include any partial matches as
1428
1432
  // the initial matches so we can properly render `HydrateFallback`'s
1429
1433
  if (future.v7_partialHydration) {
1430
1434
  let fogOfWar = checkFogOfWar(null, dataRoutes, init.history.location.pathname);
@@ -1541,7 +1545,7 @@ function createRouter(init) {
1541
1545
  // Store blocker functions in a separate Map outside of router state since
1542
1546
  // we don't need to update UI state if they change
1543
1547
  let blockerFunctions = new Map();
1544
- // Map of pending patchRoutesOnMiss() promises (keyed by path/matches) so
1548
+ // Map of pending patchRoutesOnNavigation() promises (keyed by path/matches) so
1545
1549
  // that we only kick them off once for a given combo
1546
1550
  let pendingPatchRoutes = new Map();
1547
1551
  // Flag to ignore the next history update, so we can revert the URL change on
@@ -3082,7 +3086,16 @@ function createRouter(init) {
3082
3086
  return null;
3083
3087
  }
3084
3088
  function checkFogOfWar(matches, routesToUse, pathname) {
3085
- if (patchRoutesOnMissImpl) {
3089
+ if (patchRoutesOnNavigationImpl) {
3090
+ // Don't bother re-calling patchRouteOnMiss for a path we've already
3091
+ // processed. the last execution would have patched the route tree
3092
+ // accordingly so `matches` here are already accurate.
3093
+ if (discoveredRoutes.has(pathname)) {
3094
+ return {
3095
+ active: false,
3096
+ matches
3097
+ };
3098
+ }
3086
3099
  if (!matches) {
3087
3100
  let fogMatches = matchRoutesImpl(routesToUse, pathname, basename, true);
3088
3101
  return {
@@ -3090,11 +3103,10 @@ function createRouter(init) {
3090
3103
  matches: fogMatches || []
3091
3104
  };
3092
3105
  } else {
3093
- let leafRoute = matches[matches.length - 1].route;
3094
- if (leafRoute.path && (leafRoute.path === "*" || leafRoute.path.endsWith("/*"))) {
3095
- // If we matched a splat, it might only be because we haven't yet fetched
3096
- // the children that would match with a higher score, so let's fetch
3097
- // around and find out
3106
+ if (Object.keys(matches[0].params).length > 0) {
3107
+ // If we matched a dynamic param or a splat, it might only be because
3108
+ // we haven't yet discovered other routes that would match with a
3109
+ // higher score. Call patchRoutesOnNavigation just to be sure
3098
3110
  let partialMatches = matchRoutesImpl(routesToUse, pathname, basename, true);
3099
3111
  return {
3100
3112
  active: true,
@@ -3110,12 +3122,11 @@ function createRouter(init) {
3110
3122
  }
3111
3123
  async function discoverRoutes(matches, pathname, signal) {
3112
3124
  let partialMatches = matches;
3113
- let route = partialMatches.length > 0 ? partialMatches[partialMatches.length - 1].route : null;
3114
3125
  while (true) {
3115
3126
  let isNonHMR = inFlightDataRoutes == null;
3116
3127
  let routesToUse = inFlightDataRoutes || dataRoutes;
3117
3128
  try {
3118
- await loadLazyRouteChildren(patchRoutesOnMissImpl, pathname, partialMatches, routesToUse, manifest, mapRouteProperties, pendingPatchRoutes, signal);
3129
+ await loadLazyRouteChildren(patchRoutesOnNavigationImpl, pathname, partialMatches, routesToUse, manifest, mapRouteProperties, pendingPatchRoutes, signal);
3119
3130
  } catch (e) {
3120
3131
  return {
3121
3132
  type: "error",
@@ -3139,51 +3150,31 @@ function createRouter(init) {
3139
3150
  };
3140
3151
  }
3141
3152
  let newMatches = matchRoutes(routesToUse, pathname, basename);
3142
- let matchedSplat = false;
3143
3153
  if (newMatches) {
3144
- let leafRoute = newMatches[newMatches.length - 1].route;
3145
- if (leafRoute.index) {
3146
- // If we found an index route, we can stop
3147
- return {
3148
- type: "success",
3149
- matches: newMatches
3150
- };
3151
- }
3152
- if (leafRoute.path && leafRoute.path.length > 0) {
3153
- if (leafRoute.path === "*") {
3154
- // If we found a splat route, we can't be sure there's not a
3155
- // higher-scoring route down some partial matches trail so we need
3156
- // to check that out
3157
- matchedSplat = true;
3158
- } else {
3159
- // If we found a non-splat route, we can stop
3160
- return {
3161
- type: "success",
3162
- matches: newMatches
3163
- };
3164
- }
3165
- }
3166
- }
3167
- let newPartialMatches = matchRoutesImpl(routesToUse, pathname, basename, true);
3168
- // If we are no longer partially matching anything, this was either a
3169
- // legit splat match above, or it's a 404. Also avoid loops if the
3170
- // second pass results in the same partial matches
3171
- if (!newPartialMatches || partialMatches.map(m => m.route.id).join("-") === newPartialMatches.map(m => m.route.id).join("-")) {
3154
+ addToFifoQueue(pathname, discoveredRoutes);
3172
3155
  return {
3173
3156
  type: "success",
3174
- matches: matchedSplat ? newMatches : null
3157
+ matches: newMatches
3175
3158
  };
3176
3159
  }
3177
- partialMatches = newPartialMatches;
3178
- route = partialMatches[partialMatches.length - 1].route;
3179
- if (route.path === "*") {
3180
- // The splat is still our most accurate partial, so run with it
3160
+ let newPartialMatches = matchRoutesImpl(routesToUse, pathname, basename, true);
3161
+ // Avoid loops if the second pass results in the same partial matches
3162
+ if (!newPartialMatches || partialMatches.length === newPartialMatches.length && partialMatches.every((m, i) => m.route.id === newPartialMatches[i].route.id)) {
3163
+ addToFifoQueue(pathname, discoveredRoutes);
3181
3164
  return {
3182
3165
  type: "success",
3183
- matches: partialMatches
3166
+ matches: null
3184
3167
  };
3185
3168
  }
3169
+ partialMatches = newPartialMatches;
3170
+ }
3171
+ }
3172
+ function addToFifoQueue(path, queue) {
3173
+ if (queue.size >= discoveredRoutesMaxSize) {
3174
+ let first = queue.values().next().value;
3175
+ queue.delete(first);
3186
3176
  }
3177
+ queue.add(path);
3187
3178
  }
3188
3179
  function _internalSetRoutes(newRoutes) {
3189
3180
  manifest = {};
@@ -4012,15 +4003,15 @@ function shouldRevalidateLoader(loaderMatch, arg) {
4012
4003
  return arg.defaultShouldRevalidate;
4013
4004
  }
4014
4005
  /**
4015
- * Idempotent utility to execute patchRoutesOnMiss() to lazily load route
4006
+ * Idempotent utility to execute patchRoutesOnNavigation() to lazily load route
4016
4007
  * definitions and update the routes/routeManifest
4017
4008
  */
4018
- async function loadLazyRouteChildren(patchRoutesOnMissImpl, path, matches, routes, manifest, mapRouteProperties, pendingRouteChildren, signal) {
4009
+ async function loadLazyRouteChildren(patchRoutesOnNavigationImpl, path, matches, routes, manifest, mapRouteProperties, pendingRouteChildren, signal) {
4019
4010
  let key = [path, ...matches.map(m => m.route.id)].join("-");
4020
4011
  try {
4021
4012
  let pending = pendingRouteChildren.get(key);
4022
4013
  if (!pending) {
4023
- pending = patchRoutesOnMissImpl({
4014
+ pending = patchRoutesOnNavigationImpl({
4024
4015
  path,
4025
4016
  matches,
4026
4017
  patch: (routeId, children) => {
@@ -4607,7 +4598,7 @@ function getInternalRouterError(status, _temp5) {
4607
4598
  if (status === 400) {
4608
4599
  statusText = "Bad Request";
4609
4600
  if (type === "route-discovery") {
4610
- errorMessage = "Unable to match URL \"" + pathname + "\" - the `unstable_patchRoutesOnMiss()` " + ("function threw the following error:\n" + message);
4601
+ errorMessage = "Unable to match URL \"" + pathname + "\" - the `unstable_patchRoutesOnNavigation()` " + ("function threw the following error:\n" + message);
4611
4602
  } else if (method && pathname && routeId) {
4612
4603
  errorMessage = "You made a " + method + " request to \"" + pathname + "\" but " + ("did not provide a `loader` for route \"" + routeId + "\", ") + "so there is no way to handle the request.";
4613
4604
  } else if (type === "defer-action") {