@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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # `@remix-run/router`
2
2
 
3
+ ## 1.3.3-pre.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Correctly perform a "hard" redirect for same-origin absolute URLs outside of the router basename ([#10076](https://github.com/remix-run/react-router/pull/10076))
8
+
9
+ ## 1.3.3-pre.0
10
+
11
+ ### Patch Changes
12
+
13
+ - Change `invariant` to an `UNSAFE_` export since it's only intended for internal use ([#10066](https://github.com/remix-run/react-router/pull/10066))
14
+ - Ensure status code and headers are maintained for `defer` loader responses in `createStaticHandler`'s `query()` method ([#10077](https://github.com/remix-run/react-router/pull/10077))
15
+ - Add internal API for custom HMR implementations ([#9996](https://github.com/remix-run/react-router/pull/9996))
16
+
3
17
  ## 1.3.2
4
18
 
5
19
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export type { ActionFunction, ActionFunctionArgs, AgnosticDataIndexRouteObject, AgnosticDataNonIndexRouteObject, AgnosticDataRouteMatch, AgnosticDataRouteObject, AgnosticIndexRouteObject, AgnosticNonIndexRouteObject, AgnosticRouteMatch, AgnosticRouteObject, TrackedPromise, FormEncType, FormMethod, JsonFunction, LoaderFunction, LoaderFunctionArgs, ParamParseKey, Params, PathMatch, PathPattern, RedirectFunction, ShouldRevalidateFunction, Submission, } from "./utils";
2
2
  export { AbortedDeferredError, ErrorResponse, defer, generatePath, getToPathname, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, redirect, resolvePath, resolveTo, stripBasename, warning, } from "./utils";
3
3
  export type { BrowserHistory, BrowserHistoryOptions, HashHistory, HashHistoryOptions, History, InitialEntry, Location, MemoryHistory, MemoryHistoryOptions, Path, To, } from "./history";
4
- export { Action, createBrowserHistory, createPath, createHashHistory, createMemoryHistory, invariant, parsePath, } from "./history";
4
+ export { Action, createBrowserHistory, createPath, createHashHistory, createMemoryHistory, parsePath, } from "./history";
5
5
  export * from "./router";
6
6
  /** @internal */
7
7
  export { DeferredData as UNSAFE_DeferredData, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, getPathContributingMatches as UNSAFE_getPathContributingMatches, } from "./utils";
8
+ export { invariant as UNSAFE_invariant } from "./history";
@@ -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
  *
@@ -1489,7 +1489,8 @@ const isServer = !isBrowser; //#endregion
1489
1489
 
1490
1490
  function createRouter(init) {
1491
1491
  invariant(init.routes.length > 0, "You must provide a non-empty routes array to createRouter");
1492
- let dataRoutes = convertRoutesToDataRoutes(init.routes); // Cleanup function for history
1492
+ let dataRoutes = convertRoutesToDataRoutes(init.routes);
1493
+ let inFlightDataRoutes; // Cleanup function for history
1493
1494
 
1494
1495
  let unlistenHistory = null; // Externally-provided functions to call on all state changes
1495
1496
 
@@ -1725,6 +1726,12 @@ function createRouter(init) {
1725
1726
 
1726
1727
 
1727
1728
  let preventScrollReset = pendingPreventScrollReset === true || state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && ((_location$state2 = location.state) == null ? void 0 : _location$state2._isRedirect) !== true;
1729
+
1730
+ if (inFlightDataRoutes) {
1731
+ dataRoutes = inFlightDataRoutes;
1732
+ inFlightDataRoutes = undefined;
1733
+ }
1734
+
1728
1735
  updateState(_extends({}, newState, {
1729
1736
  // matches, errors, fetchers go through as-is
1730
1737
  actionData,
@@ -1880,8 +1887,9 @@ function createRouter(init) {
1880
1887
 
1881
1888
  saveScrollPosition(state.location, state.matches);
1882
1889
  pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
1890
+ let routesToUse = inFlightDataRoutes || dataRoutes;
1883
1891
  let loadingNavigation = opts && opts.overrideNavigation;
1884
- let matches = matchRoutes(dataRoutes, location, init.basename); // Short circuit with a 404 on the root error boundary if we match nothing
1892
+ let matches = matchRoutes(routesToUse, location, init.basename); // Short circuit with a 404 on the root error boundary if we match nothing
1885
1893
 
1886
1894
  if (!matches) {
1887
1895
  let error = getInternalRouterError(404, {
@@ -1890,7 +1898,7 @@ function createRouter(init) {
1890
1898
  let {
1891
1899
  matches: notFoundMatches,
1892
1900
  route
1893
- } = getShortCircuitMatches(dataRoutes); // Cancel all pending deferred on 404s since we don't keep any routes
1901
+ } = getShortCircuitMatches(routesToUse); // Cancel all pending deferred on 404s since we don't keep any routes
1894
1902
 
1895
1903
  cancelActiveDeferreds();
1896
1904
  completeNavigation(location, {
@@ -2095,7 +2103,8 @@ function createRouter(init) {
2095
2103
  formData: loadingNavigation.formData,
2096
2104
  formEncType: loadingNavigation.formEncType
2097
2105
  } : undefined;
2098
- 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
2106
+ let routesToUse = inFlightDataRoutes || dataRoutes;
2107
+ 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
2099
2108
  // about to reload. Note that if this is an action reload we would have
2100
2109
  // already cancelled all pending deferreds so this would be a no-op
2101
2110
 
@@ -2212,7 +2221,8 @@ function createRouter(init) {
2212
2221
  }
2213
2222
 
2214
2223
  if (fetchControllers.has(key)) abortFetcher(key);
2215
- let matches = matchRoutes(dataRoutes, href, init.basename);
2224
+ let routesToUse = inFlightDataRoutes || dataRoutes;
2225
+ let matches = matchRoutes(routesToUse, href, init.basename);
2216
2226
 
2217
2227
  if (!matches) {
2218
2228
  setFetcherError(key, routeId, getInternalRouterError(404, {
@@ -2237,9 +2247,7 @@ function createRouter(init) {
2237
2247
 
2238
2248
  fetchLoadMatches.set(key, {
2239
2249
  routeId,
2240
- path,
2241
- match,
2242
- matches
2250
+ path
2243
2251
  });
2244
2252
  handleFetcherLoader(key, routeId, path, match, matches, submission);
2245
2253
  } // Call the action for the matched fetcher.submit(), and then handle redirects,
@@ -2326,7 +2334,8 @@ function createRouter(init) {
2326
2334
 
2327
2335
  let nextLocation = state.navigation.location || state.location;
2328
2336
  let revalidationRequest = createClientSideRequest(init.history, nextLocation, abortController.signal);
2329
- let matches = state.navigation.state !== "idle" ? matchRoutes(dataRoutes, state.navigation.location, init.basename) : state.matches;
2337
+ let routesToUse = inFlightDataRoutes || dataRoutes;
2338
+ let matches = state.navigation.state !== "idle" ? matchRoutes(routesToUse, state.navigation.location, init.basename) : state.matches;
2330
2339
  invariant(matches, "Didn't find any matches after fetcher action");
2331
2340
  let loadId = ++incrementingLoadId;
2332
2341
  fetchReloadIds.set(key, loadId);
@@ -2339,10 +2348,10 @@ function createRouter(init) {
2339
2348
  });
2340
2349
 
2341
2350
  state.fetchers.set(key, loadFetcher);
2342
- let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, {
2351
+ let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, init.basename, {
2343
2352
  [match.route.id]: actionResult.data
2344
- }, undefined, // No need to send through errors since we short circuit above
2345
- fetchLoadMatches); // Put all revalidating fetchers into the loading state, except for the
2353
+ }, undefined // No need to send through errors since we short circuit above
2354
+ ); // Put all revalidating fetchers into the loading state, except for the
2346
2355
  // current fetcher which we want to keep in it's current loading state which
2347
2356
  // contains it's action submission info + action data
2348
2357
 
@@ -2548,9 +2557,10 @@ function createRouter(init) {
2548
2557
  invariant(redirectLocation, "Expected a location on the redirect navigation"); // Check if this an absolute external redirect that goes to a new origin
2549
2558
 
2550
2559
  if (ABSOLUTE_URL_REGEX.test(redirect.location) && isBrowser && typeof ((_window = window) == null ? void 0 : _window.location) !== "undefined") {
2551
- let newOrigin = init.history.createURL(redirect.location).origin;
2560
+ let url = init.history.createURL(redirect.location);
2561
+ let isDifferentBasename = stripBasename(url.pathname, init.basename || "/") == null;
2552
2562
 
2553
- if (window.location.origin !== newOrigin) {
2563
+ if (window.location.origin !== url.origin || isDifferentBasename) {
2554
2564
  if (replace) {
2555
2565
  window.location.replace(redirect.location);
2556
2566
  } else {
@@ -2616,7 +2626,19 @@ function createRouter(init) {
2616
2626
  // Call all navigation loaders and revalidating fetcher loaders in parallel,
2617
2627
  // then slice off the results into separate arrays so we can handle them
2618
2628
  // accordingly
2619
- 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))]);
2629
+ let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, router.basename)), ...fetchersToLoad.map(f => {
2630
+ if (f.matches && f.match) {
2631
+ return callLoaderOrAction("loader", createClientSideRequest(init.history, f.path, request.signal), f.match, f.matches, router.basename);
2632
+ } else {
2633
+ let error = {
2634
+ type: ResultType.error,
2635
+ error: getInternalRouterError(404, {
2636
+ pathname: f.path
2637
+ })
2638
+ };
2639
+ return error;
2640
+ }
2641
+ })]);
2620
2642
  let loaderResults = results.slice(0, matchesToLoad.length);
2621
2643
  let fetcherResults = results.slice(matchesToLoad.length);
2622
2644
  await Promise.all([resolveDeferredResults(currentMatches, matchesToLoad, loaderResults, request.signal, false, state.loaderData), resolveDeferredResults(currentMatches, fetchersToLoad.map(f => f.match), fetcherResults, request.signal, true)]);
@@ -2851,6 +2873,10 @@ function createRouter(init) {
2851
2873
  return null;
2852
2874
  }
2853
2875
 
2876
+ function _internalSetRoutes(newRoutes) {
2877
+ inFlightDataRoutes = newRoutes;
2878
+ }
2879
+
2854
2880
  router = {
2855
2881
  get basename() {
2856
2882
  return init.basename;
@@ -2880,7 +2906,10 @@ function createRouter(init) {
2880
2906
  getBlocker,
2881
2907
  deleteBlocker,
2882
2908
  _internalFetchControllers: fetchControllers,
2883
- _internalActiveDeferreds: activeDeferreds
2909
+ _internalActiveDeferreds: activeDeferreds,
2910
+ // TODO: Remove setRoutes, it's temporary to avoid dealing with
2911
+ // updating the tree while validating the update algorithm.
2912
+ _internalSetRoutes
2884
2913
  };
2885
2914
  return router;
2886
2915
  } //#endregion
@@ -3381,7 +3410,7 @@ function getLoaderMatchesUntilBoundary(matches, boundaryId) {
3381
3410
  return boundaryMatches;
3382
3411
  }
3383
3412
 
3384
- function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches) {
3413
+ function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, pendingActionData, pendingError) {
3385
3414
  let actionResult = pendingError ? Object.values(pendingError)[0] : pendingActionData ? Object.values(pendingActionData)[0] : undefined;
3386
3415
  let currentUrl = history.createURL(state.location);
3387
3416
  let nextUrl = history.createURL(location);
@@ -3420,36 +3449,56 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
3420
3449
  }); // Pick fetcher.loads that need to be revalidated
3421
3450
 
3422
3451
  let revalidatingFetchers = [];
3423
- fetchLoadMatches && fetchLoadMatches.forEach((f, key) => {
3452
+ fetchLoadMatches.forEach((f, key) => {
3453
+ // Don't revalidate if fetcher won't be present in the subsequent render
3424
3454
  if (!matches.some(m => m.route.id === f.routeId)) {
3425
- // This fetcher is not going to be present in the subsequent render so
3426
- // there's no need to revalidate it
3427
3455
  return;
3428
- } else if (cancelledFetcherLoads.includes(key)) {
3429
- // This fetcher was cancelled from a prior action submission - force reload
3456
+ }
3457
+
3458
+ let fetcherMatches = matchRoutes(routesToUse, f.path, basename); // If the fetcher path no longer matches, push it in with null matches so
3459
+ // we can trigger a 404 in callLoadersAndMaybeResolveData
3460
+
3461
+ if (!fetcherMatches) {
3430
3462
  revalidatingFetchers.push(_extends({
3431
3463
  key
3432
- }, f));
3433
- } else {
3434
- // Revalidating fetchers are decoupled from the route matches since they
3435
- // hit a static href, so they _always_ check shouldRevalidate and the
3436
- // default is strictly if a revalidation is explicitly required (action
3437
- // submissions, useRevalidator, X-Remix-Revalidate).
3438
- let shouldRevalidate = shouldRevalidateLoader(f.match, _extends({
3439
- currentUrl,
3440
- currentParams: state.matches[state.matches.length - 1].params,
3441
- nextUrl,
3442
- nextParams: matches[matches.length - 1].params
3443
- }, submission, {
3444
- actionResult,
3445
- defaultShouldRevalidate
3464
+ }, f, {
3465
+ matches: null,
3466
+ match: null
3446
3467
  }));
3468
+ return;
3469
+ }
3447
3470
 
3448
- if (shouldRevalidate) {
3449
- revalidatingFetchers.push(_extends({
3450
- key
3451
- }, f));
3452
- }
3471
+ let fetcherMatch = getTargetMatch(fetcherMatches, f.path);
3472
+
3473
+ if (cancelledFetcherLoads.includes(key)) {
3474
+ revalidatingFetchers.push(_extends({
3475
+ key,
3476
+ matches: fetcherMatches,
3477
+ match: fetcherMatch
3478
+ }, f));
3479
+ return;
3480
+ } // Revalidating fetchers are decoupled from the route matches since they
3481
+ // hit a static href, so they _always_ check shouldRevalidate and the
3482
+ // default is strictly if a revalidation is explicitly required (action
3483
+ // submissions, useRevalidator, X-Remix-Revalidate).
3484
+
3485
+
3486
+ let shouldRevalidate = shouldRevalidateLoader(fetcherMatch, _extends({
3487
+ currentUrl,
3488
+ currentParams: state.matches[state.matches.length - 1].params,
3489
+ nextUrl,
3490
+ nextParams: matches[matches.length - 1].params
3491
+ }, submission, {
3492
+ actionResult,
3493
+ defaultShouldRevalidate
3494
+ }));
3495
+
3496
+ if (shouldRevalidate) {
3497
+ revalidatingFetchers.push(_extends({
3498
+ key,
3499
+ matches: fetcherMatches,
3500
+ match: fetcherMatch
3501
+ }, f));
3453
3502
  }
3454
3503
  });
3455
3504
  return [navigationMatches, revalidatingFetchers];
@@ -3546,13 +3595,14 @@ async function callLoaderOrAction(type, request, match, matches, basename, isSta
3546
3595
 
3547
3596
  location = createPath(resolvedLocation);
3548
3597
  } else if (!isStaticRequest) {
3549
- // Strip off the protocol+origin for same-origin absolute redirects.
3550
- // If this is a static reques, we can let it go back to the browser
3551
- // as-is
3598
+ // Strip off the protocol+origin for same-origin + same-basename absolute
3599
+ // redirects. If this is a static request, we can let it go back to the
3600
+ // browser as-is
3552
3601
  let currentUrl = new URL(request.url);
3553
3602
  let url = location.startsWith("//") ? new URL(currentUrl.protocol + location) : new URL(location);
3603
+ let isSameBasename = stripBasename(url.pathname, basename) != null;
3554
3604
 
3555
- if (url.origin === currentUrl.origin) {
3605
+ if (url.origin === currentUrl.origin && isSameBasename) {
3556
3606
  location = url.pathname + url.search + url.hash;
3557
3607
  }
3558
3608
  } // Don't process redirects in the router during static requests requests.
@@ -3619,9 +3669,13 @@ async function callLoaderOrAction(type, request, match, matches, basename, isSta
3619
3669
  }
3620
3670
 
3621
3671
  if (result instanceof DeferredData) {
3672
+ var _result$init, _result$init2;
3673
+
3622
3674
  return {
3623
3675
  type: ResultType.deferred,
3624
- deferredData: result
3676
+ deferredData: result,
3677
+ statusCode: (_result$init = result.init) == null ? void 0 : _result$init.status,
3678
+ headers: ((_result$init2 = result.init) == null ? void 0 : _result$init2.headers) && new Headers(result.init.headers)
3625
3679
  };
3626
3680
  }
3627
3681
 
@@ -3758,7 +3812,7 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingError,
3758
3812
  let result = fetcherResults[index]; // Process fetcher non-redirect errors
3759
3813
 
3760
3814
  if (isErrorResult(result)) {
3761
- let boundaryMatch = findNearestBoundary(state.matches, match.route.id);
3815
+ let boundaryMatch = findNearestBoundary(state.matches, match == null ? void 0 : match.route.id);
3762
3816
 
3763
3817
  if (!(errors && errors[boundaryMatch.route.id])) {
3764
3818
  errors = _extends({}, errors, {
@@ -3805,7 +3859,9 @@ function mergeLoaderData(loaderData, newLoaderData, matches, errors) {
3805
3859
  if (newLoaderData[id] !== undefined) {
3806
3860
  mergedLoaderData[id] = newLoaderData[id];
3807
3861
  }
3808
- } else if (loaderData[id] !== undefined) {
3862
+ } else if (loaderData[id] !== undefined && match.route.loader) {
3863
+ // Preserve existing keys not included in newLoaderData and where a loader
3864
+ // wasn't removed by HMR
3809
3865
  mergedLoaderData[id] = loaderData[id];
3810
3866
  }
3811
3867
 
@@ -3942,7 +3998,14 @@ function isMutationMethod(method) {
3942
3998
  async function resolveDeferredResults(currentMatches, matchesToLoad, results, signal, isFetcher, currentLoaderData) {
3943
3999
  for (let index = 0; index < results.length; index++) {
3944
4000
  let result = results[index];
3945
- let match = matchesToLoad[index];
4001
+ let match = matchesToLoad[index]; // If we don't have a match, then we can have a deferred result to do
4002
+ // anything with. This is for revalidating fetchers where the route was
4003
+ // removed during HMR
4004
+
4005
+ if (!match) {
4006
+ continue;
4007
+ }
4008
+
3946
4009
  let currentMatch = currentMatches.find(m => m.route.id === match.route.id);
3947
4010
  let isRevalidatingLoader = currentMatch != null && !isNewRouteInstance(currentMatch, match) && (currentLoaderData && currentLoaderData[match.route.id]) !== undefined;
3948
4011
 
@@ -4035,6 +4098,7 @@ exports.UNSAFE_DEFERRED_SYMBOL = UNSAFE_DEFERRED_SYMBOL;
4035
4098
  exports.UNSAFE_DeferredData = DeferredData;
4036
4099
  exports.UNSAFE_convertRoutesToDataRoutes = convertRoutesToDataRoutes;
4037
4100
  exports.UNSAFE_getPathContributingMatches = getPathContributingMatches;
4101
+ exports.UNSAFE_invariant = invariant;
4038
4102
  exports.createBrowserHistory = createBrowserHistory;
4039
4103
  exports.createHashHistory = createHashHistory;
4040
4104
  exports.createMemoryHistory = createMemoryHistory;
@@ -4045,7 +4109,6 @@ exports.defer = defer;
4045
4109
  exports.generatePath = generatePath;
4046
4110
  exports.getStaticContextFromError = getStaticContextFromError;
4047
4111
  exports.getToPathname = getToPathname;
4048
- exports.invariant = invariant;
4049
4112
  exports.isRouteErrorResponse = isRouteErrorResponse;
4050
4113
  exports.joinPaths = joinPaths;
4051
4114
  exports.json = json;