@remix-run/router 1.3.2 → 1.3.3-pre.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
@@ -147,6 +147,14 @@ export interface Router {
147
147
  * @param key The identifier for the blocker
148
148
  */
149
149
  deleteBlocker(key: string): void;
150
+ /**
151
+ * @internal
152
+ * PRIVATE - DO NOT USE
153
+ *
154
+ * HMR needs to pass in-flight route updates to React Router
155
+ * TODO: Replace this with granular route update APIs (addRoute, updateRoute, deleteRoute)
156
+ */
157
+ _internalSetRoutes(routes: AgnosticRouteObject[]): void;
150
158
  /**
151
159
  * @internal
152
160
  * PRIVATE - DO NOT USE
package/dist/router.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @remix-run/router v1.3.2
2
+ * @remix-run/router v1.3.3-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1441,7 +1441,8 @@ const isServer = !isBrowser; //#endregion
1441
1441
 
1442
1442
  function createRouter(init) {
1443
1443
  invariant(init.routes.length > 0, "You must provide a non-empty routes array to createRouter");
1444
- let dataRoutes = convertRoutesToDataRoutes(init.routes); // Cleanup function for history
1444
+ let dataRoutes = convertRoutesToDataRoutes(init.routes);
1445
+ let inFlightDataRoutes; // Cleanup function for history
1445
1446
 
1446
1447
  let unlistenHistory = null; // Externally-provided functions to call on all state changes
1447
1448
 
@@ -1677,6 +1678,12 @@ function createRouter(init) {
1677
1678
 
1678
1679
 
1679
1680
  let preventScrollReset = pendingPreventScrollReset === true || state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && ((_location$state2 = location.state) == null ? void 0 : _location$state2._isRedirect) !== true;
1681
+
1682
+ if (inFlightDataRoutes) {
1683
+ dataRoutes = inFlightDataRoutes;
1684
+ inFlightDataRoutes = undefined;
1685
+ }
1686
+
1680
1687
  updateState(_extends({}, newState, {
1681
1688
  actionData,
1682
1689
  loaderData,
@@ -1831,8 +1838,9 @@ function createRouter(init) {
1831
1838
 
1832
1839
  saveScrollPosition(state.location, state.matches);
1833
1840
  pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
1841
+ let routesToUse = inFlightDataRoutes || dataRoutes;
1834
1842
  let loadingNavigation = opts && opts.overrideNavigation;
1835
- let matches = matchRoutes(dataRoutes, location, init.basename); // Short circuit with a 404 on the root error boundary if we match nothing
1843
+ let matches = matchRoutes(routesToUse, location, init.basename); // Short circuit with a 404 on the root error boundary if we match nothing
1836
1844
 
1837
1845
  if (!matches) {
1838
1846
  let error = getInternalRouterError(404, {
@@ -1841,7 +1849,7 @@ function createRouter(init) {
1841
1849
  let {
1842
1850
  matches: notFoundMatches,
1843
1851
  route
1844
- } = getShortCircuitMatches(dataRoutes); // Cancel all pending deferred on 404s since we don't keep any routes
1852
+ } = getShortCircuitMatches(routesToUse); // Cancel all pending deferred on 404s since we don't keep any routes
1845
1853
 
1846
1854
  cancelActiveDeferreds();
1847
1855
  completeNavigation(location, {
@@ -2046,7 +2054,8 @@ function createRouter(init) {
2046
2054
  formData: loadingNavigation.formData,
2047
2055
  formEncType: loadingNavigation.formEncType
2048
2056
  } : undefined;
2049
- let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches); // Cancel pending deferreds for no-longer-matched routes or routes we're
2057
+ let routesToUse = inFlightDataRoutes || dataRoutes;
2058
+ let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, init.basename, pendingActionData, pendingError); // Cancel pending deferreds for no-longer-matched routes or routes we're
2050
2059
  // about to reload. Note that if this is an action reload we would have
2051
2060
  // already cancelled all pending deferreds so this would be a no-op
2052
2061
 
@@ -2163,7 +2172,8 @@ function createRouter(init) {
2163
2172
  }
2164
2173
 
2165
2174
  if (fetchControllers.has(key)) abortFetcher(key);
2166
- let matches = matchRoutes(dataRoutes, href, init.basename);
2175
+ let routesToUse = inFlightDataRoutes || dataRoutes;
2176
+ let matches = matchRoutes(routesToUse, href, init.basename);
2167
2177
 
2168
2178
  if (!matches) {
2169
2179
  setFetcherError(key, routeId, getInternalRouterError(404, {
@@ -2188,9 +2198,7 @@ function createRouter(init) {
2188
2198
 
2189
2199
  fetchLoadMatches.set(key, {
2190
2200
  routeId,
2191
- path,
2192
- match,
2193
- matches
2201
+ path
2194
2202
  });
2195
2203
  handleFetcherLoader(key, routeId, path, match, matches, submission);
2196
2204
  } // Call the action for the matched fetcher.submit(), and then handle redirects,
@@ -2277,7 +2285,8 @@ function createRouter(init) {
2277
2285
 
2278
2286
  let nextLocation = state.navigation.location || state.location;
2279
2287
  let revalidationRequest = createClientSideRequest(init.history, nextLocation, abortController.signal);
2280
- let matches = state.navigation.state !== "idle" ? matchRoutes(dataRoutes, state.navigation.location, init.basename) : state.matches;
2288
+ let routesToUse = inFlightDataRoutes || dataRoutes;
2289
+ let matches = state.navigation.state !== "idle" ? matchRoutes(routesToUse, state.navigation.location, init.basename) : state.matches;
2281
2290
  invariant(matches, "Didn't find any matches after fetcher action");
2282
2291
  let loadId = ++incrementingLoadId;
2283
2292
  fetchReloadIds.set(key, loadId);
@@ -2290,10 +2299,10 @@ function createRouter(init) {
2290
2299
  });
2291
2300
 
2292
2301
  state.fetchers.set(key, loadFetcher);
2293
- let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, {
2302
+ let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, init.basename, {
2294
2303
  [match.route.id]: actionResult.data
2295
- }, undefined, // No need to send through errors since we short circuit above
2296
- fetchLoadMatches); // Put all revalidating fetchers into the loading state, except for the
2304
+ }, undefined // No need to send through errors since we short circuit above
2305
+ ); // Put all revalidating fetchers into the loading state, except for the
2297
2306
  // current fetcher which we want to keep in it's current loading state which
2298
2307
  // contains it's action submission info + action data
2299
2308
 
@@ -2499,9 +2508,10 @@ function createRouter(init) {
2499
2508
  invariant(redirectLocation, "Expected a location on the redirect navigation"); // Check if this an absolute external redirect that goes to a new origin
2500
2509
 
2501
2510
  if (ABSOLUTE_URL_REGEX.test(redirect.location) && isBrowser && typeof ((_window = window) == null ? void 0 : _window.location) !== "undefined") {
2502
- let newOrigin = init.history.createURL(redirect.location).origin;
2511
+ let url = init.history.createURL(redirect.location);
2512
+ let isDifferentBasename = stripBasename(url.pathname, init.basename || "/") == null;
2503
2513
 
2504
- if (window.location.origin !== newOrigin) {
2514
+ if (window.location.origin !== url.origin || isDifferentBasename) {
2505
2515
  if (replace) {
2506
2516
  window.location.replace(redirect.location);
2507
2517
  } else {
@@ -2567,7 +2577,19 @@ function createRouter(init) {
2567
2577
  // Call all navigation loaders and revalidating fetcher loaders in parallel,
2568
2578
  // then slice off the results into separate arrays so we can handle them
2569
2579
  // accordingly
2570
- let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, router.basename)), ...fetchersToLoad.map(f => callLoaderOrAction("loader", createClientSideRequest(init.history, f.path, request.signal), f.match, f.matches, router.basename))]);
2580
+ let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, router.basename)), ...fetchersToLoad.map(f => {
2581
+ if (f.matches && f.match) {
2582
+ return callLoaderOrAction("loader", createClientSideRequest(init.history, f.path, request.signal), f.match, f.matches, router.basename);
2583
+ } else {
2584
+ let error = {
2585
+ type: ResultType.error,
2586
+ error: getInternalRouterError(404, {
2587
+ pathname: f.path
2588
+ })
2589
+ };
2590
+ return error;
2591
+ }
2592
+ })]);
2571
2593
  let loaderResults = results.slice(0, matchesToLoad.length);
2572
2594
  let fetcherResults = results.slice(matchesToLoad.length);
2573
2595
  await Promise.all([resolveDeferredResults(currentMatches, matchesToLoad, loaderResults, request.signal, false, state.loaderData), resolveDeferredResults(currentMatches, fetchersToLoad.map(f => f.match), fetcherResults, request.signal, true)]);
@@ -2802,6 +2824,10 @@ function createRouter(init) {
2802
2824
  return null;
2803
2825
  }
2804
2826
 
2827
+ function _internalSetRoutes(newRoutes) {
2828
+ inFlightDataRoutes = newRoutes;
2829
+ }
2830
+
2805
2831
  router = {
2806
2832
  get basename() {
2807
2833
  return init.basename;
@@ -2831,7 +2857,10 @@ function createRouter(init) {
2831
2857
  getBlocker,
2832
2858
  deleteBlocker,
2833
2859
  _internalFetchControllers: fetchControllers,
2834
- _internalActiveDeferreds: activeDeferreds
2860
+ _internalActiveDeferreds: activeDeferreds,
2861
+ // TODO: Remove setRoutes, it's temporary to avoid dealing with
2862
+ // updating the tree while validating the update algorithm.
2863
+ _internalSetRoutes
2835
2864
  };
2836
2865
  return router;
2837
2866
  } //#endregion
@@ -3332,7 +3361,7 @@ function getLoaderMatchesUntilBoundary(matches, boundaryId) {
3332
3361
  return boundaryMatches;
3333
3362
  }
3334
3363
 
3335
- function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches) {
3364
+ function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, pendingActionData, pendingError) {
3336
3365
  let actionResult = pendingError ? Object.values(pendingError)[0] : pendingActionData ? Object.values(pendingActionData)[0] : undefined;
3337
3366
  let currentUrl = history.createURL(state.location);
3338
3367
  let nextUrl = history.createURL(location);
@@ -3371,36 +3400,56 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
3371
3400
  }); // Pick fetcher.loads that need to be revalidated
3372
3401
 
3373
3402
  let revalidatingFetchers = [];
3374
- fetchLoadMatches && fetchLoadMatches.forEach((f, key) => {
3403
+ fetchLoadMatches.forEach((f, key) => {
3404
+ // Don't revalidate if fetcher won't be present in the subsequent render
3375
3405
  if (!matches.some(m => m.route.id === f.routeId)) {
3376
- // This fetcher is not going to be present in the subsequent render so
3377
- // there's no need to revalidate it
3378
3406
  return;
3379
- } else if (cancelledFetcherLoads.includes(key)) {
3380
- // This fetcher was cancelled from a prior action submission - force reload
3407
+ }
3408
+
3409
+ let fetcherMatches = matchRoutes(routesToUse, f.path, basename); // If the fetcher path no longer matches, push it in with null matches so
3410
+ // we can trigger a 404 in callLoadersAndMaybeResolveData
3411
+
3412
+ if (!fetcherMatches) {
3381
3413
  revalidatingFetchers.push(_extends({
3382
3414
  key
3383
- }, f));
3384
- } else {
3385
- // Revalidating fetchers are decoupled from the route matches since they
3386
- // hit a static href, so they _always_ check shouldRevalidate and the
3387
- // default is strictly if a revalidation is explicitly required (action
3388
- // submissions, useRevalidator, X-Remix-Revalidate).
3389
- let shouldRevalidate = shouldRevalidateLoader(f.match, _extends({
3390
- currentUrl,
3391
- currentParams: state.matches[state.matches.length - 1].params,
3392
- nextUrl,
3393
- nextParams: matches[matches.length - 1].params
3394
- }, submission, {
3395
- actionResult,
3396
- defaultShouldRevalidate
3415
+ }, f, {
3416
+ matches: null,
3417
+ match: null
3397
3418
  }));
3419
+ return;
3420
+ }
3398
3421
 
3399
- if (shouldRevalidate) {
3400
- revalidatingFetchers.push(_extends({
3401
- key
3402
- }, f));
3403
- }
3422
+ let fetcherMatch = getTargetMatch(fetcherMatches, f.path);
3423
+
3424
+ if (cancelledFetcherLoads.includes(key)) {
3425
+ revalidatingFetchers.push(_extends({
3426
+ key,
3427
+ matches: fetcherMatches,
3428
+ match: fetcherMatch
3429
+ }, f));
3430
+ return;
3431
+ } // Revalidating fetchers are decoupled from the route matches since they
3432
+ // hit a static href, so they _always_ check shouldRevalidate and the
3433
+ // default is strictly if a revalidation is explicitly required (action
3434
+ // submissions, useRevalidator, X-Remix-Revalidate).
3435
+
3436
+
3437
+ let shouldRevalidate = shouldRevalidateLoader(fetcherMatch, _extends({
3438
+ currentUrl,
3439
+ currentParams: state.matches[state.matches.length - 1].params,
3440
+ nextUrl,
3441
+ nextParams: matches[matches.length - 1].params
3442
+ }, submission, {
3443
+ actionResult,
3444
+ defaultShouldRevalidate
3445
+ }));
3446
+
3447
+ if (shouldRevalidate) {
3448
+ revalidatingFetchers.push(_extends({
3449
+ key,
3450
+ matches: fetcherMatches,
3451
+ match: fetcherMatch
3452
+ }, f));
3404
3453
  }
3405
3454
  });
3406
3455
  return [navigationMatches, revalidatingFetchers];
@@ -3497,13 +3546,14 @@ async function callLoaderOrAction(type, request, match, matches, basename, isSta
3497
3546
 
3498
3547
  location = createPath(resolvedLocation);
3499
3548
  } else if (!isStaticRequest) {
3500
- // Strip off the protocol+origin for same-origin absolute redirects.
3501
- // If this is a static reques, we can let it go back to the browser
3502
- // as-is
3549
+ // Strip off the protocol+origin for same-origin + same-basename absolute
3550
+ // redirects. If this is a static request, we can let it go back to the
3551
+ // browser as-is
3503
3552
  let currentUrl = new URL(request.url);
3504
3553
  let url = location.startsWith("//") ? new URL(currentUrl.protocol + location) : new URL(location);
3554
+ let isSameBasename = stripBasename(url.pathname, basename) != null;
3505
3555
 
3506
- if (url.origin === currentUrl.origin) {
3556
+ if (url.origin === currentUrl.origin && isSameBasename) {
3507
3557
  location = url.pathname + url.search + url.hash;
3508
3558
  }
3509
3559
  } // Don't process redirects in the router during static requests requests.
@@ -3570,9 +3620,13 @@ async function callLoaderOrAction(type, request, match, matches, basename, isSta
3570
3620
  }
3571
3621
 
3572
3622
  if (result instanceof DeferredData) {
3623
+ var _result$init, _result$init2;
3624
+
3573
3625
  return {
3574
3626
  type: ResultType.deferred,
3575
- deferredData: result
3627
+ deferredData: result,
3628
+ statusCode: (_result$init = result.init) == null ? void 0 : _result$init.status,
3629
+ headers: ((_result$init2 = result.init) == null ? void 0 : _result$init2.headers) && new Headers(result.init.headers)
3576
3630
  };
3577
3631
  }
3578
3632
 
@@ -3709,7 +3763,7 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingError,
3709
3763
  let result = fetcherResults[index]; // Process fetcher non-redirect errors
3710
3764
 
3711
3765
  if (isErrorResult(result)) {
3712
- let boundaryMatch = findNearestBoundary(state.matches, match.route.id);
3766
+ let boundaryMatch = findNearestBoundary(state.matches, match == null ? void 0 : match.route.id);
3713
3767
 
3714
3768
  if (!(errors && errors[boundaryMatch.route.id])) {
3715
3769
  errors = _extends({}, errors, {
@@ -3756,7 +3810,9 @@ function mergeLoaderData(loaderData, newLoaderData, matches, errors) {
3756
3810
  if (newLoaderData[id] !== undefined) {
3757
3811
  mergedLoaderData[id] = newLoaderData[id];
3758
3812
  }
3759
- } else if (loaderData[id] !== undefined) {
3813
+ } else if (loaderData[id] !== undefined && match.route.loader) {
3814
+ // Preserve existing keys not included in newLoaderData and where a loader
3815
+ // wasn't removed by HMR
3760
3816
  mergedLoaderData[id] = loaderData[id];
3761
3817
  }
3762
3818
 
@@ -3893,7 +3949,14 @@ function isMutationMethod(method) {
3893
3949
  async function resolveDeferredResults(currentMatches, matchesToLoad, results, signal, isFetcher, currentLoaderData) {
3894
3950
  for (let index = 0; index < results.length; index++) {
3895
3951
  let result = results[index];
3896
- let match = matchesToLoad[index];
3952
+ let match = matchesToLoad[index]; // If we don't have a match, then we can have a deferred result to do
3953
+ // anything with. This is for revalidating fetchers where the route was
3954
+ // removed during HMR
3955
+
3956
+ if (!match) {
3957
+ continue;
3958
+ }
3959
+
3897
3960
  let currentMatch = currentMatches.find(m => m.route.id === match.route.id);
3898
3961
  let isRevalidatingLoader = currentMatch != null && !isNewRouteInstance(currentMatch, match) && (currentLoaderData && currentLoaderData[match.route.id]) !== undefined;
3899
3962
 
@@ -3977,5 +4040,5 @@ function getTargetMatch(matches, location) {
3977
4040
  return pathMatches[pathMatches.length - 1];
3978
4041
  } //#endregion
3979
4042
 
3980
- export { AbortedDeferredError, Action, ErrorResponse, IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, UNSAFE_DEFERRED_SYMBOL, DeferredData as UNSAFE_DeferredData, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, getPathContributingMatches as UNSAFE_getPathContributingMatches, createBrowserHistory, createHashHistory, createMemoryHistory, createPath, createRouter, createStaticHandler, defer, generatePath, getStaticContextFromError, getToPathname, invariant, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, parsePath, redirect, resolvePath, resolveTo, stripBasename, warning };
4043
+ export { AbortedDeferredError, Action, ErrorResponse, IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, UNSAFE_DEFERRED_SYMBOL, DeferredData as UNSAFE_DeferredData, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, getPathContributingMatches as UNSAFE_getPathContributingMatches, invariant as UNSAFE_invariant, createBrowserHistory, createHashHistory, createMemoryHistory, createPath, createRouter, createStaticHandler, defer, generatePath, getStaticContextFromError, getToPathname, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, parsePath, redirect, resolvePath, resolveTo, stripBasename, warning };
3981
4044
  //# sourceMappingURL=router.js.map