@remix-run/router 1.13.1 → 1.14.0-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
@@ -12,6 +12,13 @@ export interface Router {
12
12
  * Return the basename for the router
13
13
  */
14
14
  get basename(): RouterInit["basename"];
15
+ /**
16
+ * @internal
17
+ * PRIVATE - DO NOT USE
18
+ *
19
+ * Return the future config for the router
20
+ */
21
+ get future(): FutureConfig;
15
22
  /**
16
23
  * @internal
17
24
  * PRIVATE - DO NOT USE
@@ -248,7 +255,9 @@ export type HydrationState = Partial<Pick<RouterState, "loaderData" | "actionDat
248
255
  export interface FutureConfig {
249
256
  v7_fetcherPersist: boolean;
250
257
  v7_normalizeFormMethod: boolean;
258
+ v7_partialHydration: boolean;
251
259
  v7_prependBasename: boolean;
260
+ v7_relativeSplatPath: boolean;
252
261
  }
253
262
  /**
254
263
  * Initialization options for createRouter
@@ -473,6 +482,12 @@ export declare const IDLE_BLOCKER: BlockerUnblocked;
473
482
  */
474
483
  export declare function createRouter(init: RouterInit): Router;
475
484
  export declare const UNSAFE_DEFERRED_SYMBOL: unique symbol;
485
+ /**
486
+ * Future flags to toggle new feature behavior
487
+ */
488
+ export interface StaticHandlerFutureConfig {
489
+ v7_relativeSplatPath: boolean;
490
+ }
476
491
  export interface CreateStaticHandlerOptions {
477
492
  basename?: string;
478
493
  /**
@@ -480,6 +495,7 @@ export interface CreateStaticHandlerOptions {
480
495
  */
481
496
  detectErrorBoundary?: DetectErrorBoundaryFunction;
482
497
  mapRouteProperties?: MapRoutePropertiesFunction;
498
+ future?: Partial<StaticHandlerFutureConfig>;
483
499
  }
484
500
  export declare function createStaticHandler(routes: AgnosticRouteObject[], opts?: CreateStaticHandlerOptions): StaticHandler;
485
501
  /**
package/dist/router.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @remix-run/router v1.13.1
2
+ * @remix-run/router v1.14.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -938,6 +938,18 @@ function getInvalidPathError(char, field, dest, path) {
938
938
  function getPathContributingMatches(matches) {
939
939
  return matches.filter((match, index) => index === 0 || match.route.path && match.route.path.length > 0);
940
940
  }
941
+ // Return the array of pathnames for the current route matches - used to
942
+ // generate the routePathnames input for resolveTo()
943
+ function getResolveToMatches(matches, v7_relativeSplatPath) {
944
+ let pathMatches = getPathContributingMatches(matches);
945
+ // When v7_relativeSplatPath is enabled, use the full pathname for the leaf
946
+ // match so we include splat values for "." links. See:
947
+ // https://github.com/remix-run/react-router/issues/11052#issuecomment-1836589329
948
+ if (v7_relativeSplatPath) {
949
+ return pathMatches.map((match, idx) => idx === matches.length - 1 ? match.pathname : match.pathnameBase);
950
+ }
951
+ return pathMatches.map(match => match.pathnameBase);
952
+ }
941
953
  /**
942
954
  * @private
943
955
  */
@@ -969,7 +981,7 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative) {
969
981
  if (toPathname == null) {
970
982
  from = locationPathname;
971
983
  } else if (isPathRelative) {
972
- let fromSegments = routePathnames[routePathnames.length - 1].replace(/^\//, "").split("/");
984
+ let fromSegments = routePathnames.length === 0 ? [] : routePathnames[routePathnames.length - 1].replace(/^\//, "").split("/");
973
985
  if (toPathname.startsWith("..")) {
974
986
  let toSegments = toPathname.split("/");
975
987
  // With relative="path", each leading .. segment means "go up one URL segment"
@@ -1330,7 +1342,9 @@ function createRouter(init) {
1330
1342
  let future = _extends({
1331
1343
  v7_fetcherPersist: false,
1332
1344
  v7_normalizeFormMethod: false,
1333
- v7_prependBasename: false
1345
+ v7_partialHydration: false,
1346
+ v7_prependBasename: false,
1347
+ v7_relativeSplatPath: false
1334
1348
  }, init.future);
1335
1349
  // Cleanup function for history
1336
1350
  let unlistenHistory = null;
@@ -1366,12 +1380,28 @@ function createRouter(init) {
1366
1380
  [route.id]: error
1367
1381
  };
1368
1382
  }
1369
- let initialized =
1370
- // All initialMatches need to be loaded before we're ready. If we have lazy
1371
- // functions around still then we'll need to run them in initialize()
1372
- !initialMatches.some(m => m.route.lazy) && (
1373
- // And we have to either have no loaders or have been provided hydrationData
1374
- !initialMatches.some(m => m.route.loader) || init.hydrationData != null);
1383
+ let initialized;
1384
+ let hasLazyRoutes = initialMatches.some(m => m.route.lazy);
1385
+ let hasLoaders = initialMatches.some(m => m.route.loader);
1386
+ if (hasLazyRoutes) {
1387
+ // All initialMatches need to be loaded before we're ready. If we have lazy
1388
+ // functions around still then we'll need to run them in initialize()
1389
+ initialized = false;
1390
+ } else if (!hasLoaders) {
1391
+ // If we've got no loaders to run, then we're good to go
1392
+ initialized = true;
1393
+ } else if (future.v7_partialHydration) {
1394
+ // If partial hydration is enabled, we're initialized so long as we were
1395
+ // provided with hydrationData for every route with a loader, and no loaders
1396
+ // were marked for explicit hydration
1397
+ let loaderData = init.hydrationData ? init.hydrationData.loaderData : null;
1398
+ let errors = init.hydrationData ? init.hydrationData.errors : null;
1399
+ initialized = initialMatches.every(m => m.route.loader && m.route.loader.hydrate !== true && (loaderData && loaderData[m.route.id] !== undefined || errors && errors[m.route.id] !== undefined));
1400
+ } else {
1401
+ // Without partial hydration - we're initialized if we were provided any
1402
+ // hydrationData - which is expected to be complete
1403
+ initialized = init.hydrationData != null;
1404
+ }
1375
1405
  let router;
1376
1406
  let state = {
1377
1407
  historyAction: init.history.action,
@@ -1515,7 +1545,9 @@ function createRouter(init) {
1515
1545
  // resolved prior to router creation since we can't go into a fallbackElement
1516
1546
  // UI for SSR'd apps
1517
1547
  if (!state.initialized) {
1518
- startNavigation(Action.Pop, state.location);
1548
+ startNavigation(Action.Pop, state.location, {
1549
+ initialHydration: true
1550
+ });
1519
1551
  }
1520
1552
  return router;
1521
1553
  }
@@ -1690,7 +1722,7 @@ function createRouter(init) {
1690
1722
  init.history.go(to);
1691
1723
  return;
1692
1724
  }
1693
- let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, to, opts == null ? void 0 : opts.fromRouteId, opts == null ? void 0 : opts.relative);
1725
+ let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, to, future.v7_relativeSplatPath, opts == null ? void 0 : opts.fromRouteId, opts == null ? void 0 : opts.relative);
1694
1726
  let {
1695
1727
  path,
1696
1728
  submission,
@@ -1879,7 +1911,7 @@ function createRouter(init) {
1879
1911
  shortCircuited,
1880
1912
  loaderData,
1881
1913
  errors
1882
- } = await handleLoaders(request, location, matches, loadingNavigation, opts && opts.submission, opts && opts.fetcherSubmission, opts && opts.replace, flushSync, pendingActionData, pendingError);
1914
+ } = await handleLoaders(request, location, matches, loadingNavigation, opts && opts.submission, opts && opts.fetcherSubmission, opts && opts.replace, opts && opts.initialHydration === true, flushSync, pendingActionData, pendingError);
1883
1915
  if (shortCircuited) {
1884
1916
  return;
1885
1917
  }
@@ -1923,7 +1955,7 @@ function createRouter(init) {
1923
1955
  })
1924
1956
  };
1925
1957
  } else {
1926
- result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename);
1958
+ result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath);
1927
1959
  if (request.signal.aborted) {
1928
1960
  return {
1929
1961
  shortCircuited: true
@@ -1980,14 +2012,14 @@ function createRouter(init) {
1980
2012
  }
1981
2013
  // Call all applicable loaders for the given matches, handling redirects,
1982
2014
  // errors, etc.
1983
- async function handleLoaders(request, location, matches, overrideNavigation, submission, fetcherSubmission, replace, flushSync, pendingActionData, pendingError) {
2015
+ async function handleLoaders(request, location, matches, overrideNavigation, submission, fetcherSubmission, replace, initialHydration, flushSync, pendingActionData, pendingError) {
1984
2016
  // Figure out the right navigation we want to use for data loading
1985
2017
  let loadingNavigation = overrideNavigation || getLoadingNavigation(location, submission);
1986
2018
  // If this was a redirect from an action we don't have a "submission" but
1987
2019
  // we have it on the loading navigation so use that if available
1988
2020
  let activeSubmission = submission || fetcherSubmission || getSubmissionFromNavigation(loadingNavigation);
1989
2021
  let routesToUse = inFlightDataRoutes || dataRoutes;
1990
- let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionData, pendingError);
2022
+ let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, future.v7_partialHydration && initialHydration === true, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionData, pendingError);
1991
2023
  // Cancel pending deferreds for no-longer-matched routes or routes we're
1992
2024
  // about to reload. Note that if this is an action reload we would have
1993
2025
  // already cancelled all pending deferreds so this would be a no-op
@@ -2016,7 +2048,9 @@ function createRouter(init) {
2016
2048
  // state. If not, we need to switch to our loading state and load data,
2017
2049
  // preserving any new action data or existing action data (in the case of
2018
2050
  // a revalidation interrupting an actionReload)
2019
- if (!isUninterruptedRevalidation) {
2051
+ // If we have partialHydration enabled, then don't update the state for the
2052
+ // initial data load since iot's not a "navigation"
2053
+ if (!isUninterruptedRevalidation && (!future.v7_partialHydration || !initialHydration)) {
2020
2054
  revalidatingFetchers.forEach(rf => {
2021
2055
  let fetcher = state.fetchers.get(rf.key);
2022
2056
  let revalidatingFetcher = getLoadingFetcher(undefined, fetcher ? fetcher.data : undefined);
@@ -2119,7 +2153,7 @@ function createRouter(init) {
2119
2153
  if (fetchControllers.has(key)) abortFetcher(key);
2120
2154
  let flushSync = (opts && opts.unstable_flushSync) === true;
2121
2155
  let routesToUse = inFlightDataRoutes || dataRoutes;
2122
- let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, href, routeId, opts == null ? void 0 : opts.relative);
2156
+ let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, href, future.v7_relativeSplatPath, routeId, opts == null ? void 0 : opts.relative);
2123
2157
  let matches = matchRoutes(routesToUse, normalizedPath, basename);
2124
2158
  if (!matches) {
2125
2159
  setFetcherError(key, routeId, getInternalRouterError(404, {
@@ -2180,7 +2214,7 @@ function createRouter(init) {
2180
2214
  let fetchRequest = createClientSideRequest(init.history, path, abortController.signal, submission);
2181
2215
  fetchControllers.set(key, abortController);
2182
2216
  let originatingLoadId = incrementingLoadId;
2183
- let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, manifest, mapRouteProperties, basename);
2217
+ let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath);
2184
2218
  if (fetchRequest.signal.aborted) {
2185
2219
  // We can delete this so long as we weren't aborted by our own fetcher
2186
2220
  // re-submit which would have put _new_ controller is in fetchControllers
@@ -2231,7 +2265,7 @@ function createRouter(init) {
2231
2265
  fetchReloadIds.set(key, loadId);
2232
2266
  let loadFetcher = getLoadingFetcher(submission, actionResult.data);
2233
2267
  state.fetchers.set(key, loadFetcher);
2234
- let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, {
2268
+ let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, false, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, {
2235
2269
  [match.route.id]: actionResult.data
2236
2270
  }, undefined // No need to send through errors since we short circuit above
2237
2271
  );
@@ -2325,7 +2359,7 @@ function createRouter(init) {
2325
2359
  let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
2326
2360
  fetchControllers.set(key, abortController);
2327
2361
  let originatingLoadId = incrementingLoadId;
2328
- let result = await callLoaderOrAction("loader", fetchRequest, match, matches, manifest, mapRouteProperties, basename);
2362
+ let result = await callLoaderOrAction("loader", fetchRequest, match, matches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath);
2329
2363
  // Deferred isn't supported for fetcher loads, await everything and treat it
2330
2364
  // as a normal load. resolveDeferredData will return undefined if this
2331
2365
  // fetcher gets aborted, so we just leave result untouched and short circuit
@@ -2464,9 +2498,9 @@ function createRouter(init) {
2464
2498
  // Call all navigation loaders and revalidating fetcher loaders in parallel,
2465
2499
  // then slice off the results into separate arrays so we can handle them
2466
2500
  // accordingly
2467
- let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename)), ...fetchersToLoad.map(f => {
2501
+ let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath)), ...fetchersToLoad.map(f => {
2468
2502
  if (f.matches && f.match && f.controller) {
2469
- return callLoaderOrAction("loader", createClientSideRequest(init.history, f.path, f.controller.signal), f.match, f.matches, manifest, mapRouteProperties, basename);
2503
+ return callLoaderOrAction("loader", createClientSideRequest(init.history, f.path, f.controller.signal), f.match, f.matches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath);
2470
2504
  } else {
2471
2505
  let error = {
2472
2506
  type: ResultType.error,
@@ -2735,6 +2769,9 @@ function createRouter(init) {
2735
2769
  get basename() {
2736
2770
  return basename;
2737
2771
  },
2772
+ get future() {
2773
+ return future;
2774
+ },
2738
2775
  get state() {
2739
2776
  return state;
2740
2777
  },
@@ -2788,6 +2825,10 @@ function createStaticHandler(routes, opts) {
2788
2825
  } else {
2789
2826
  mapRouteProperties = defaultMapRouteProperties;
2790
2827
  }
2828
+ // Config driven behavior flags
2829
+ let future = _extends({
2830
+ v7_relativeSplatPath: false
2831
+ }, opts ? opts.future : null);
2791
2832
  let dataRoutes = convertRoutesToDataRoutes(routes, mapRouteProperties, undefined, manifest);
2792
2833
  /**
2793
2834
  * The query() method is intended for document requests, in which we want to
@@ -2997,7 +3038,7 @@ function createStaticHandler(routes, opts) {
2997
3038
  error
2998
3039
  };
2999
3040
  } else {
3000
- result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename, {
3041
+ result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath, {
3001
3042
  isStaticRequest: true,
3002
3043
  isRouteRequest,
3003
3044
  requestContext
@@ -3112,7 +3153,7 @@ function createStaticHandler(routes, opts) {
3112
3153
  activeDeferreds: null
3113
3154
  };
3114
3155
  }
3115
- let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename, {
3156
+ let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath, {
3116
3157
  isStaticRequest: true,
3117
3158
  isRouteRequest,
3118
3159
  requestContext
@@ -3162,7 +3203,7 @@ function getStaticContextFromError(routes, context, error) {
3162
3203
  function isSubmissionNavigation(opts) {
3163
3204
  return opts != null && ("formData" in opts && opts.formData != null || "body" in opts && opts.body !== undefined);
3164
3205
  }
3165
- function normalizeTo(location, matches, basename, prependBasename, to, fromRouteId, relative) {
3206
+ function normalizeTo(location, matches, basename, prependBasename, to, v7_relativeSplatPath, fromRouteId, relative) {
3166
3207
  let contextualMatches;
3167
3208
  let activeRouteMatch;
3168
3209
  if (fromRouteId) {
@@ -3181,7 +3222,7 @@ function normalizeTo(location, matches, basename, prependBasename, to, fromRoute
3181
3222
  activeRouteMatch = matches[matches.length - 1];
3182
3223
  }
3183
3224
  // Resolve the relative path
3184
- let path = resolveTo(to ? to : ".", getPathContributingMatches(contextualMatches).map(m => m.pathnameBase), stripBasename(location.pathname, basename) || location.pathname, relative === "path");
3225
+ let path = resolveTo(to ? to : ".", getResolveToMatches(contextualMatches, v7_relativeSplatPath), stripBasename(location.pathname, basename) || location.pathname, relative === "path");
3185
3226
  // When `to` is not specified we inherit search/hash from the current
3186
3227
  // location, unlike when to="." and we just inherit the path.
3187
3228
  // See https://github.com/remix-run/remix/issues/927
@@ -3338,7 +3379,7 @@ function getLoaderMatchesUntilBoundary(matches, boundaryId) {
3338
3379
  }
3339
3380
  return boundaryMatches;
3340
3381
  }
3341
- function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionData, pendingError) {
3382
+ function getMatchesToLoad(history, state, matches, submission, location, isInitialLoad, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionData, pendingError) {
3342
3383
  let actionResult = pendingError ? Object.values(pendingError)[0] : pendingActionData ? Object.values(pendingActionData)[0] : undefined;
3343
3384
  let currentUrl = history.createURL(state.location);
3344
3385
  let nextUrl = history.createURL(location);
@@ -3346,6 +3387,11 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
3346
3387
  let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;
3347
3388
  let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
3348
3389
  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
+ }
3349
3395
  if (match.route.lazy) {
3350
3396
  // We haven't loaded this route yet so we don't know if it's got a loader!
3351
3397
  return true;
@@ -3382,8 +3428,12 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
3382
3428
  // Pick fetcher.loads that need to be revalidated
3383
3429
  let revalidatingFetchers = [];
3384
3430
  fetchLoadMatches.forEach((f, key) => {
3385
- // Don't revalidate if fetcher won't be present in the subsequent render
3386
- if (!matches.some(m => m.route.id === f.routeId) || deletedFetchers.has(key)) {
3431
+ // Don't revalidate:
3432
+ // - on initial load (shouldn't be any fetchers then anyway)
3433
+ // - if fetcher won't be present in the subsequent render
3434
+ // - no longer matches the URL (v7_fetcherPersist=false)
3435
+ // - was unmounted but persisted due to v7_fetcherPersist=true
3436
+ if (isInitialLoad || !matches.some(m => m.route.id === f.routeId) || deletedFetchers.has(key)) {
3387
3437
  return;
3388
3438
  }
3389
3439
  let fetcherMatches = matchRoutes(routesToUse, f.path, basename);
@@ -3445,6 +3495,19 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
3445
3495
  });
3446
3496
  return [navigationMatches, revalidatingFetchers];
3447
3497
  }
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
+ }
3448
3511
  function isNewLoader(currentLoaderData, currentMatch, match) {
3449
3512
  let isNew =
3450
3513
  // [a] -> [a, b]
@@ -3524,7 +3587,7 @@ async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
3524
3587
  lazy: undefined
3525
3588
  }));
3526
3589
  }
3527
- async function callLoaderOrAction(type, request, match, matches, manifest, mapRouteProperties, basename, opts) {
3590
+ async function callLoaderOrAction(type, request, match, matches, manifest, mapRouteProperties, basename, v7_relativeSplatPath, opts) {
3528
3591
  if (opts === void 0) {
3529
3592
  opts = {};
3530
3593
  }
@@ -3612,7 +3675,7 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
3612
3675
  invariant(location, "Redirects returned/thrown from loaders/actions must have a Location header");
3613
3676
  // Support relative routing in internal redirects
3614
3677
  if (!ABSOLUTE_URL_REGEX.test(location)) {
3615
- location = normalizeTo(new URL(request.url), matches.slice(0, matches.indexOf(match) + 1), basename, true, location);
3678
+ location = normalizeTo(new URL(request.url), matches.slice(0, matches.indexOf(match) + 1), basename, true, location, v7_relativeSplatPath);
3616
3679
  } else if (!opts.isStaticRequest) {
3617
3680
  // Strip off the protocol+origin for same-origin + same-basename absolute
3618
3681
  // redirects. If this is a static request, we can let it go back to the
@@ -3651,13 +3714,20 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
3651
3714
  throw queryRouteResponse;
3652
3715
  }
3653
3716
  let data;
3654
- let contentType = result.headers.get("Content-Type");
3655
- // Check between word boundaries instead of startsWith() due to the last
3656
- // paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type
3657
- if (contentType && /\bapplication\/json\b/.test(contentType)) {
3658
- data = await result.json();
3659
- } else {
3660
- data = await result.text();
3717
+ try {
3718
+ let contentType = result.headers.get("Content-Type");
3719
+ // Check between word boundaries instead of startsWith() due to the last
3720
+ // paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type
3721
+ if (contentType && /\bapplication\/json\b/.test(contentType)) {
3722
+ data = await result.json();
3723
+ } else {
3724
+ data = await result.text();
3725
+ }
3726
+ } catch (e) {
3727
+ return {
3728
+ type: ResultType.error,
3729
+ error: e
3730
+ };
3661
3731
  }
3662
3732
  if (resultType === ResultType.error) {
3663
3733
  return {
@@ -4233,5 +4303,5 @@ function persistAppliedTransitions(_window, transitions) {
4233
4303
  }
4234
4304
  //#endregion
4235
4305
 
4236
- export { AbortedDeferredError, Action, IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, UNSAFE_DEFERRED_SYMBOL, DeferredData as UNSAFE_DeferredData, ErrorResponseImpl as UNSAFE_ErrorResponseImpl, convertRouteMatchToUiMatch as UNSAFE_convertRouteMatchToUiMatch, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, getPathContributingMatches as UNSAFE_getPathContributingMatches, invariant as UNSAFE_invariant, warning as UNSAFE_warning, createBrowserHistory, createHashHistory, createMemoryHistory, createPath, createRouter, createStaticHandler, defer, generatePath, getStaticContextFromError, getToPathname, isDeferredData, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, parsePath, redirect, redirectDocument, resolvePath, resolveTo, stripBasename };
4306
+ export { AbortedDeferredError, Action, IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, UNSAFE_DEFERRED_SYMBOL, DeferredData as UNSAFE_DeferredData, ErrorResponseImpl as UNSAFE_ErrorResponseImpl, convertRouteMatchToUiMatch as UNSAFE_convertRouteMatchToUiMatch, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, getResolveToMatches as UNSAFE_getResolveToMatches, invariant as UNSAFE_invariant, warning as UNSAFE_warning, createBrowserHistory, createHashHistory, createMemoryHistory, createPath, createRouter, createStaticHandler, defer, generatePath, getStaticContextFromError, getToPathname, isDeferredData, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, parsePath, redirect, redirectDocument, resolvePath, resolveTo, stripBasename };
4237
4307
  //# sourceMappingURL=router.js.map