react-router 7.5.1 → 7.5.3-pre.0

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/development/{chunk-LSOULM7L.mjs → chunk-MKZGATSN.mjs} +114 -38
  3. package/dist/development/dom-export.d.mts +2 -2
  4. package/dist/development/dom-export.d.ts +2 -2
  5. package/dist/development/dom-export.js +99 -64
  6. package/dist/development/dom-export.mjs +17 -41
  7. package/dist/{production/fog-of-war-CyHis97d.d.mts → development/fog-of-war-BLArG-qZ.d.ts} +2 -2
  8. package/dist/development/{fog-of-war-D4x86-Xc.d.ts → fog-of-war-D2zsXvum.d.mts} +2 -2
  9. package/dist/development/index.d.mts +19 -16
  10. package/dist/development/index.d.ts +19 -16
  11. package/dist/development/index.js +115 -38
  12. package/dist/development/index.mjs +6 -4
  13. package/dist/development/lib/types/route-module.d.mts +1 -1
  14. package/dist/development/lib/types/route-module.d.ts +1 -1
  15. package/dist/development/lib/types/route-module.js +1 -1
  16. package/dist/development/lib/types/route-module.mjs +1 -1
  17. package/dist/development/{route-data-OcOrqK13.d.ts → route-data-C12CLHiN.d.mts} +1 -1
  18. package/dist/{production/route-data-OcOrqK13.d.mts → development/route-data-C12CLHiN.d.ts} +1 -1
  19. package/dist/production/{chunk-SAWFLE7G.mjs → chunk-ZGZJR6R3.mjs} +114 -38
  20. package/dist/production/dom-export.d.mts +2 -2
  21. package/dist/production/dom-export.d.ts +2 -2
  22. package/dist/production/dom-export.js +99 -64
  23. package/dist/production/dom-export.mjs +17 -41
  24. package/dist/{development/fog-of-war-CyHis97d.d.mts → production/fog-of-war-BLArG-qZ.d.ts} +2 -2
  25. package/dist/production/{fog-of-war-D4x86-Xc.d.ts → fog-of-war-D2zsXvum.d.mts} +2 -2
  26. package/dist/production/index.d.mts +19 -16
  27. package/dist/production/index.d.ts +19 -16
  28. package/dist/production/index.js +115 -38
  29. package/dist/production/index.mjs +6 -4
  30. package/dist/production/lib/types/route-module.d.mts +1 -1
  31. package/dist/production/lib/types/route-module.d.ts +1 -1
  32. package/dist/production/lib/types/route-module.js +1 -1
  33. package/dist/production/lib/types/route-module.mjs +1 -1
  34. package/dist/production/{route-data-OcOrqK13.d.ts → route-data-C12CLHiN.d.mts} +1 -1
  35. package/dist/{development/route-data-OcOrqK13.d.mts → production/route-data-C12CLHiN.d.ts} +1 -1
  36. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # `react-router`
2
2
 
3
+ ## 7.5.3-pre.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Fix bug where bubbled action errors would result in `loaderData` being cleared at the handling `ErrorBoundary` route ([#13476](https://github.com/remix-run/react-router/pull/13476))
8
+ - Handle redirects from `clientLoader.hydrate` initial load executions ([#13477](https://github.com/remix-run/react-router/pull/13477))
9
+
10
+ ## 7.5.2
11
+
12
+ ### Patch Changes
13
+
14
+ - Update Single Fetch to also handle the 204 redirects used in `?_data` requests in Remix v2 ([#13364](https://github.com/remix-run/react-router/pull/13364))
15
+
16
+ - This allows applications to return a redirect on `.data` requests from outside the scope of React Router (i.e., an `express`/`hono` middleware)
17
+ - ⚠️ Please note that doing so relies on implementation details that are subject to change without a SemVer major release
18
+ - This is primarily done to ease upgrading to Single Fetch for existing Remix v2 applications, but the recommended way to handle this is redirecting from a route middleware
19
+
20
+ - Adjust approach for Prerendering/SPA Mode via headers ([#13453](https://github.com/remix-run/react-router/pull/13453))
21
+
3
22
  ## 7.5.1
4
23
 
5
24
  ### Patch Changes
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v7.5.1
2
+ * react-router v7.5.3-pre.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1590,7 +1590,11 @@ function createRouter(init) {
1590
1590
  }
1591
1591
  return {
1592
1592
  matches,
1593
- pendingActionResult: [boundaryMatch.route.id, result]
1593
+ pendingActionResult: [
1594
+ boundaryMatch.route.id,
1595
+ result,
1596
+ actionMatch.route.id
1597
+ ]
1594
1598
  };
1595
1599
  }
1596
1600
  return {
@@ -4361,7 +4365,9 @@ function processRouteLoaderData(matches, results, pendingActionResult, isStaticH
4361
4365
  });
4362
4366
  if (pendingError !== void 0 && pendingActionResult) {
4363
4367
  errors = { [pendingActionResult[0]]: pendingError };
4364
- loaderData[pendingActionResult[0]] = void 0;
4368
+ if (pendingActionResult[2]) {
4369
+ loaderData[pendingActionResult[2]] = void 0;
4370
+ }
4365
4371
  }
4366
4372
  return {
4367
4373
  loaderData,
@@ -6312,6 +6318,7 @@ async function createRequestInit(request) {
6312
6318
 
6313
6319
  // lib/dom/ssr/single-fetch.tsx
6314
6320
  var SingleFetchRedirectSymbol = Symbol("SingleFetchRedirect");
6321
+ var SINGLE_FETCH_REDIRECT_STATUS = 202;
6315
6322
  var NO_BODY_STATUS_CODES = /* @__PURE__ */ new Set([100, 101, 204, 205]);
6316
6323
  function StreamTransfer({
6317
6324
  context,
@@ -6379,10 +6386,19 @@ function StreamTransfer({
6379
6386
  )));
6380
6387
  }
6381
6388
  }
6382
- function getSingleFetchDataStrategy(getRouter, getRouteInfo, ssr, basename) {
6389
+ function getTurboStreamSingleFetchDataStrategy(getRouter, manifest, routeModules, ssr, basename) {
6383
6390
  let dataStrategy = getSingleFetchDataStrategyImpl(
6384
6391
  getRouter,
6385
- getRouteInfo,
6392
+ (match) => {
6393
+ let manifestRoute = manifest.routes[match.route.id];
6394
+ invariant2(manifestRoute, "Route not found in manifest");
6395
+ let routeModule = routeModules[match.route.id];
6396
+ return {
6397
+ hasLoader: manifestRoute.hasLoader,
6398
+ hasClientLoader: manifestRoute.hasClientLoader,
6399
+ hasShouldRevalidate: Boolean(routeModule?.shouldRevalidate)
6400
+ };
6401
+ },
6386
6402
  fetchAndDecodeViaTurboStream,
6387
6403
  ssr,
6388
6404
  basename
@@ -6397,7 +6413,7 @@ function getSingleFetchDataStrategyImpl(getRouter, getRouteInfo, fetchAndDecode,
6397
6413
  return singleFetchActionStrategy(args, fetchAndDecode, basename);
6398
6414
  }
6399
6415
  let foundRevalidatingServerLoader = matches.some((m) => {
6400
- let { hasLoader, hasClientLoader } = getRouteInfo(m.route.id);
6416
+ let { hasLoader, hasClientLoader } = getRouteInfo(m);
6401
6417
  return m.unstable_shouldCallHandler() && hasLoader && !hasClientLoader;
6402
6418
  });
6403
6419
  if (!ssr && !foundRevalidatingServerLoader) {
@@ -6449,7 +6465,7 @@ async function nonSsrStrategy(args, getRouteInfo, fetchAndDecode, basename) {
6449
6465
  matchesToLoad.map(
6450
6466
  (m) => m.resolve(async (handler) => {
6451
6467
  try {
6452
- let { hasClientLoader } = getRouteInfo(m.route.id);
6468
+ let { hasClientLoader } = getRouteInfo(m);
6453
6469
  let routeId = m.route.id;
6454
6470
  let result = hasClientLoader ? await handler(async () => {
6455
6471
  let { data: data2 } = await fetchAndDecode(args, basename, [routeId]);
@@ -6475,7 +6491,7 @@ async function singleFetchLoaderNavigationStrategy(args, router, getRouteInfo, f
6475
6491
  async (m, i) => m.resolve(async (handler) => {
6476
6492
  routeDfds[i].resolve();
6477
6493
  let routeId = m.route.id;
6478
- let { hasLoader, hasClientLoader, hasShouldRevalidate } = getRouteInfo(routeId);
6494
+ let { hasLoader, hasClientLoader, hasShouldRevalidate } = getRouteInfo(m);
6479
6495
  let defaultShouldRevalidate = !m.unstable_shouldRevalidateArgs || m.unstable_shouldRevalidateArgs.actionStatus == null || m.unstable_shouldRevalidateArgs.actionStatus < 400;
6480
6496
  let shouldCall = m.unstable_shouldCallHandler(defaultShouldRevalidate);
6481
6497
  if (!shouldCall) {
@@ -6515,8 +6531,9 @@ async function singleFetchLoaderNavigationStrategy(args, router, getRouteInfo, f
6515
6531
  )
6516
6532
  );
6517
6533
  await Promise.all(routeDfds.map((d) => d.promise));
6518
- if ((!router.state.initialized || routesParams.size === 0) && !window.__reactRouterHdrActive) {
6519
- singleFetchDfd.resolve({});
6534
+ let isInitialLoad = !router.state.initialized && router.state.navigation.state === "idle";
6535
+ if ((isInitialLoad || routesParams.size === 0) && !window.__reactRouterHdrActive) {
6536
+ singleFetchDfd.resolve({ routes: {} });
6520
6537
  } else {
6521
6538
  let targetRoutes = ssr && foundOptOutRoute && routesParams.size > 0 ? [...routesParams.keys()] : void 0;
6522
6539
  try {
@@ -6584,6 +6601,20 @@ async function fetchAndDecodeViaTurboStream(args, basename, targetRoutes) {
6584
6601
  if (res.status === 404 && !res.headers.has("X-Remix-Response")) {
6585
6602
  throw new ErrorResponseImpl(404, "Not Found", true);
6586
6603
  }
6604
+ if (res.status === 204 && res.headers.has("X-Remix-Redirect")) {
6605
+ return {
6606
+ status: SINGLE_FETCH_REDIRECT_STATUS,
6607
+ data: {
6608
+ redirect: {
6609
+ redirect: res.headers.get("X-Remix-Redirect"),
6610
+ status: Number(res.headers.get("X-Remix-Status") || "302"),
6611
+ revalidate: res.headers.get("X-Remix-Revalidate") === "true",
6612
+ reload: res.headers.get("X-Remix-Reload-Document") === "true",
6613
+ replace: res.headers.get("X-Remix-Replace") === "true"
6614
+ }
6615
+ }
6616
+ };
6617
+ }
6587
6618
  if (NO_BODY_STATUS_CODES.has(res.status)) {
6588
6619
  let routes = {};
6589
6620
  if (targetRoutes && request.method !== "GET") {
@@ -7034,8 +7065,9 @@ function createClientRoutes(manifest, routeModulesCache, initialState, ssr, isSp
7034
7065
  }
7035
7066
  };
7036
7067
  dataRoute.loader.hydrate = shouldHydrateRouteLoader(
7037
- route,
7038
- routeModule,
7068
+ route.id,
7069
+ routeModule.clientLoader,
7070
+ route.hasLoader,
7039
7071
  isSpaMode
7040
7072
  );
7041
7073
  dataRoute.action = ({ request, params, context }, singleFetch) => {
@@ -7233,8 +7265,8 @@ function getRouteModuleComponent(routeModule) {
7233
7265
  return routeModule.default;
7234
7266
  }
7235
7267
  }
7236
- function shouldHydrateRouteLoader(route, routeModule, isSpaMode) {
7237
- return isSpaMode && route.id !== "root" || routeModule.clientLoader != null && (routeModule.clientLoader.hydrate === true || route.hasLoader !== true);
7268
+ function shouldHydrateRouteLoader(routeId, clientLoader, hasLoader, isSpaMode) {
7269
+ return isSpaMode && routeId !== "root" || clientLoader != null && (clientLoader.hydrate === true || hasLoader !== true);
7238
7270
  }
7239
7271
 
7240
7272
  // lib/dom/ssr/fog-of-war.ts
@@ -7916,7 +7948,7 @@ function mergeRefs(...refs) {
7916
7948
  var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
7917
7949
  try {
7918
7950
  if (isBrowser) {
7919
- window.__reactRouterVersion = "7.5.1";
7951
+ window.__reactRouterVersion = "7.5.3-pre.0";
7920
7952
  }
7921
7953
  } catch (e) {
7922
7954
  }
@@ -9019,7 +9051,12 @@ function ServerRouter({
9019
9051
  let routeId = match.route.id;
9020
9052
  let route = routeModules[routeId];
9021
9053
  let manifestRoute = context.manifest.routes[routeId];
9022
- if (route && manifestRoute && shouldHydrateRouteLoader(manifestRoute, route, context.isSpaMode) && (route.HydrateFallback || !manifestRoute.hasLoader)) {
9054
+ if (route && manifestRoute && shouldHydrateRouteLoader(
9055
+ routeId,
9056
+ route.clientLoader,
9057
+ manifestRoute.hasLoader,
9058
+ context.isSpaMode
9059
+ ) && (route.HydrateFallback || !manifestRoute.hasLoader)) {
9023
9060
  delete context.staticHandlerContext.loaderData[routeId];
9024
9061
  }
9025
9062
  }
@@ -9488,6 +9525,26 @@ function invariant3(value, message) {
9488
9525
  }
9489
9526
  }
9490
9527
 
9528
+ // lib/server-runtime/dev.ts
9529
+ var globalDevServerHooksKey = "__reactRouterDevServerHooks";
9530
+ function setDevServerHooks(devServerHooks) {
9531
+ globalThis[globalDevServerHooksKey] = devServerHooks;
9532
+ }
9533
+ function getDevServerHooks() {
9534
+ return globalThis[globalDevServerHooksKey];
9535
+ }
9536
+ function getBuildTimeHeader(request, headerName) {
9537
+ if (typeof process !== "undefined") {
9538
+ try {
9539
+ if (process.env?.IS_RR_BUILD_REQUEST === "yes") {
9540
+ return request.headers.get(headerName);
9541
+ }
9542
+ } catch (e) {
9543
+ }
9544
+ }
9545
+ return null;
9546
+ }
9547
+
9491
9548
  // lib/server-runtime/routes.ts
9492
9549
  function groupRoutesByParentId2(manifest) {
9493
9550
  let routes = {};
@@ -9519,10 +9576,11 @@ function createStaticHandlerDataRoutes(manifest, future, parentId = "", routesBy
9519
9576
  // Need to use RR's version in the param typed here to permit the optional
9520
9577
  // context even though we know it'll always be provided in remix
9521
9578
  loader: route.module.loader ? async (args) => {
9522
- if (args.request.headers.has("X-React-Router-Prerender-Data")) {
9523
- const preRenderedData = args.request.headers.get(
9524
- "X-React-Router-Prerender-Data"
9525
- );
9579
+ let preRenderedData = getBuildTimeHeader(
9580
+ args.request,
9581
+ "X-React-Router-Prerender-Data"
9582
+ );
9583
+ if (preRenderedData != null) {
9526
9584
  let encoded = preRenderedData ? decodeURI(preRenderedData) : preRenderedData;
9527
9585
  invariant3(encoded, "Missing prerendered data for route");
9528
9586
  let uint8array = new TextEncoder().encode(encoded);
@@ -9597,15 +9655,6 @@ function createServerHandoffString(serverHandoff) {
9597
9655
  return escapeHtml2(JSON.stringify(serverHandoff));
9598
9656
  }
9599
9657
 
9600
- // lib/server-runtime/dev.ts
9601
- var globalDevServerHooksKey = "__reactRouterDevServerHooks";
9602
- function setDevServerHooks(devServerHooks) {
9603
- globalThis[globalDevServerHooksKey] = devServerHooks;
9604
- }
9605
- function getDevServerHooks() {
9606
- return globalThis[globalDevServerHooksKey];
9607
- }
9608
-
9609
9658
  // lib/server-runtime/single-fetch.ts
9610
9659
  import { encode } from "turbo-stream";
9611
9660
 
@@ -9676,7 +9725,6 @@ function prependCookies(parentHeaders, childHeaders) {
9676
9725
  }
9677
9726
 
9678
9727
  // lib/server-runtime/single-fetch.ts
9679
- var SINGLE_FETCH_REDIRECT_STATUS = 202;
9680
9728
  var SERVER_NO_BODY_STATUS_CODES = /* @__PURE__ */ new Set([
9681
9729
  ...NO_BODY_STATUS_CODES,
9682
9730
  304
@@ -10015,9 +10063,10 @@ Error: ${e instanceof Error ? e.toString() : e}`
10015
10063
  if (stripBasename(normalizedPath, normalizedBasename) !== "/" && normalizedPath.endsWith("/")) {
10016
10064
  normalizedPath = normalizedPath.slice(0, -1);
10017
10065
  }
10066
+ let isSpaMode = getBuildTimeHeader(request, "X-React-Router-SPA-Mode") === "yes";
10018
10067
  if (!_build.ssr) {
10019
10068
  if (_build.prerender.length === 0) {
10020
- request.headers.set("X-React-Router-SPA-Mode", "yes");
10069
+ isSpaMode = true;
10021
10070
  } else if (!_build.prerender.includes(normalizedPath) && !_build.prerender.includes(normalizedPath + "/")) {
10022
10071
  if (url.pathname.endsWith(".data")) {
10023
10072
  errorHandler(
@@ -10037,7 +10086,7 @@ Error: ${e instanceof Error ? e.toString() : e}`
10037
10086
  statusText: "Not Found"
10038
10087
  });
10039
10088
  } else {
10040
- request.headers.set("X-React-Router-SPA-Mode", "yes");
10089
+ isSpaMode = true;
10041
10090
  }
10042
10091
  }
10043
10092
  }
@@ -10106,7 +10155,7 @@ Error: ${e instanceof Error ? e.toString() : e}`
10106
10155
  );
10107
10156
  }
10108
10157
  }
10109
- } else if (!request.headers.has("X-React-Router-SPA-Mode") && matches && matches[matches.length - 1].route.module.default == null && matches[matches.length - 1].route.module.ErrorBoundary == null) {
10158
+ } else if (!isSpaMode && matches && matches[matches.length - 1].route.module.default == null && matches[matches.length - 1].route.module.ErrorBoundary == null) {
10110
10159
  response = await handleResourceRequest(
10111
10160
  serverMode,
10112
10161
  _build,
@@ -10131,6 +10180,7 @@ Error: ${e instanceof Error ? e.toString() : e}`
10131
10180
  request,
10132
10181
  loadContext,
10133
10182
  handleError,
10183
+ isSpaMode,
10134
10184
  criticalCss
10135
10185
  );
10136
10186
  }
@@ -10206,8 +10256,7 @@ async function handleSingleFetchRequest(serverMode, build, staticHandler, reques
10206
10256
  );
10207
10257
  return response;
10208
10258
  }
10209
- async function handleDocumentRequest(serverMode, build, staticHandler, request, loadContext, handleError, criticalCss) {
10210
- let isSpaMode = request.headers.has("X-React-Router-SPA-Mode");
10259
+ async function handleDocumentRequest(serverMode, build, staticHandler, request, loadContext, handleError, isSpaMode, criticalCss) {
10211
10260
  try {
10212
10261
  let response = await staticHandler.query(request, {
10213
10262
  requestContext: loadContext,
@@ -10480,7 +10529,7 @@ function createSessionStorage({
10480
10529
  function warnOnceAboutSigningSessionCookie(cookie) {
10481
10530
  warnOnce(
10482
10531
  cookie.isSigned,
10483
- `The "${cookie.name}" cookie is not signed, but session cookies should be signed to prevent tampering on the client before they are sent back to the server. See https://remix.run/utils/cookies#signing-cookies for more information.`
10532
+ `The "${cookie.name}" cookie is not signed, but session cookies should be signed to prevent tampering on the client before they are sent back to the server. See https://reactrouter.com/explanation/sessions-and-cookies#signing-cookies for more information.`
10484
10533
  );
10485
10534
  }
10486
10535
 
@@ -10597,6 +10646,32 @@ function deserializeErrors2(errors) {
10597
10646
  return serialized;
10598
10647
  }
10599
10648
 
10649
+ // lib/dom/ssr/hydration.tsx
10650
+ function getHydrationData(state, routes, getRouteInfo, location, basename, isSpaMode) {
10651
+ let hydrationData = {
10652
+ ...state,
10653
+ loaderData: { ...state.loaderData }
10654
+ };
10655
+ let initialMatches = matchRoutes(routes, location, basename);
10656
+ if (initialMatches) {
10657
+ for (let match of initialMatches) {
10658
+ let routeId = match.route.id;
10659
+ let routeInfo = getRouteInfo(routeId);
10660
+ if (shouldHydrateRouteLoader(
10661
+ routeId,
10662
+ routeInfo.clientLoader,
10663
+ routeInfo.hasLoader,
10664
+ isSpaMode
10665
+ ) && (routeInfo.hasHydrateFallback || !routeInfo.hasLoader)) {
10666
+ delete hydrationData.loaderData[routeId];
10667
+ } else if (!routeInfo.hasLoader) {
10668
+ hydrationData.loaderData[routeId] = null;
10669
+ }
10670
+ }
10671
+ }
10672
+ return hydrationData;
10673
+ }
10674
+
10600
10675
  export {
10601
10676
  Action,
10602
10677
  createBrowserHistory,
@@ -10663,7 +10738,7 @@ export {
10663
10738
  renderMatches,
10664
10739
  createSearchParams,
10665
10740
  SingleFetchRedirectSymbol,
10666
- getSingleFetchDataStrategy,
10741
+ getTurboStreamSingleFetchDataStrategy,
10667
10742
  decodeViaTurboStream,
10668
10743
  RemixErrorBoundary,
10669
10744
  createClientRoutesWithHMRRevalidationOptOut,
@@ -10712,5 +10787,6 @@ export {
10712
10787
  createCookieSessionStorage,
10713
10788
  createMemorySessionStorage,
10714
10789
  href,
10715
- deserializeErrors2 as deserializeErrors
10790
+ deserializeErrors2 as deserializeErrors,
10791
+ getHydrationData
10716
10792
  };
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
- import { R as RouterProviderProps$1 } from './fog-of-war-CyHis97d.mjs';
3
- import { R as RouterInit } from './route-data-OcOrqK13.mjs';
2
+ import { R as RouterProviderProps$1 } from './fog-of-war-D2zsXvum.mjs';
3
+ import { R as RouterInit } from './route-data-C12CLHiN.mjs';
4
4
 
5
5
  type RouterProviderProps = Omit<RouterProviderProps$1, "flushSync">;
6
6
  declare function RouterProvider(props: Omit<RouterProviderProps, "flushSync">): React.JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
- import { R as RouterProviderProps$1 } from './fog-of-war-D4x86-Xc.js';
3
- import { R as RouterInit } from './route-data-OcOrqK13.js';
2
+ import { R as RouterProviderProps$1 } from './fog-of-war-BLArG-qZ.js';
3
+ import { R as RouterInit } from './route-data-C12CLHiN.js';
4
4
 
5
5
  type RouterProviderProps = Omit<RouterProviderProps$1, "flushSync">;
6
6
  declare function RouterProvider(props: Omit<RouterProviderProps, "flushSync">): React.JSX.Element;