diff --git a/.eslintrc b/.eslintrc
deleted file mode 100644
index 2e0c041bd5..0000000000
--- a/.eslintrc
+++ /dev/null
@@ -1,96 +0,0 @@
-{
- "extends": ["react-app"],
- "rules": {
- "import/first": "off",
- "@typescript-eslint/consistent-type-imports": "error"
- },
- "overrides": [
- {
- "files": ["**/__tests__/**"],
- "plugins": ["jest"],
- "extends": ["plugin:jest/recommended"]
- },
- {
- "files": ["integration/**/*.*"],
- "rules": {
- "react-hooks/rules-of-hooks": "off"
- },
- "env": {
- "jest/globals": false
- }
- },
- {
- "files": ["packages/react-router-dev/config/default-rsc-entries/*"],
- "rules": {
- "@typescript-eslint/consistent-type-imports": "off"
- }
- },
- {
- // Only apply JSDoc lint rules to files we auto-generate docs for
- "files": [
- "packages/react-router/lib/components.tsx",
- "packages/react-router/lib/hooks.tsx",
- "packages/react-router/lib/dom/lib.tsx",
- "packages/react-router/lib/dom/ssr/components.tsx",
- "packages/react-router/lib/dom/ssr/server.tsx",
- "packages/react-router/lib/dom-export/hydrated-router.tsx",
- "packages/react-router/lib/dom/server.tsx",
- "packages/react-router/lib/router/utils.ts",
- "packages/react-router/lib/rsc/browser.tsx",
- "packages/react-router/lib/rsc/server.rsc.ts",
- "packages/react-router/lib/rsc/server.ssr.tsx",
- "packages/react-router/lib/rsc/html-stream/browser.ts",
- ],
- "plugins": ["jsdoc"],
- "rules": {
- "jsdoc/check-access": "error",
- "jsdoc/check-alignment": "error",
- "jsdoc/check-param-names": "error",
- "jsdoc/check-property-names": "error",
- "jsdoc/check-tag-names": [
- "error",
- {
- "definedTags": ["additionalExamples", "category", "mode"]
- }
- ],
- "jsdoc/no-defaults": "error",
- "jsdoc/no-multi-asterisks": ["error", { "allowWhitespace": true }],
- "jsdoc/require-description": "error",
- "jsdoc/require-param": ["error", { "enableRootFixer": false }],
- "jsdoc/require-param-description": "error",
- "jsdoc/require-param-name": "error",
- "jsdoc/require-returns": "error",
- "jsdoc/require-returns-check": "error",
- "jsdoc/require-returns-description": "error",
- "jsdoc/sort-tags": [
- "error",
- {
- "tagSequence": [
- {
- "tags": ["description"]
- },
- {
- "tags": ["example"]
- },
- {
- "tags": ["additionalExamples"]
- },
- {
- "tags": [
- "name",
- "public",
- "private",
- "category",
- "mode",
- "param",
- "returns"
- ]
- }
- ]
- }
- ]
- }
- }
- ],
- "reportUnusedDisableDirectives": true
-}
diff --git a/.github/workflows/integration-full.yml b/.github/workflows/integration-full.yml
index 2654a7b667..57913eaf61 100644
--- a/.github/workflows/integration-full.yml
+++ b/.github/workflows/integration-full.yml
@@ -31,7 +31,7 @@ jobs:
uses: ./.github/workflows/shared-integration.yml
with:
os: "ubuntu-latest"
- node_version: "[20.18, 22]"
+ node_version: "[20.19, 22]"
browser: '["chromium", "firefox"]'
integration-windows:
@@ -50,5 +50,5 @@ jobs:
uses: ./.github/workflows/shared-integration.yml
with:
os: "macos-latest"
- node_version: "[20.18, 22]"
+ node_version: "[20.19, 22]"
browser: '["webkit"]'
diff --git a/.github/workflows/integration-pr-windows-macos.yml b/.github/workflows/integration-pr-windows-macos.yml
index 52d737ee5b..9f2a67d441 100644
--- a/.github/workflows/integration-pr-windows-macos.yml
+++ b/.github/workflows/integration-pr-windows-macos.yml
@@ -1,7 +1,7 @@
name: PR (Full)
# PRs touching @react-router/dev will also run on Ubuntu/Firefox, Windows/Edge and
-# OSX/WebKit as well as an Ubuntu/Chromium run on Node 20.18.
+# OSX/WebKit as well as an Ubuntu/Chromium run on Node 20.19.
on:
pull_request:
@@ -22,7 +22,7 @@ jobs:
uses: ./.github/workflows/shared-integration.yml
with:
os: "ubuntu-latest"
- node_version: "[20.18]"
+ node_version: "[20.19]"
browser: '["chromium"]'
integration-firefox:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ca6887c533..6470a361c5 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -26,7 +26,7 @@ jobs:
fail-fast: false
matrix:
node:
- - 20.18
+ - 20.19
- 22
runs-on: ubuntu-latest
diff --git a/.eslintignore b/.prettierignore
similarity index 100%
rename from .eslintignore
rename to .prettierignore
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5ca0f73844..1523003d0f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,143 +13,147 @@ We manage release notes in this file instead of the paginated Github Releases Pa
Table of Contents
- [React Router Releases](#react-router-releases)
+ - [v7.14.0](#v7140)
+ - [Minor Changes](#minor-changes)
+ - [Patch Changes](#patch-changes)
+ - [Unstable Changes](#unstable-changes)
- [v7.13.2](#v7132)
- [What's Changed](#whats-changed)
- [Pass-through Requests (unstable)](#pass-through-requests-unstable)
- [Route handlers/middleware `unstable_url` parameter](#route-handlersmiddleware-unstable_url-parameter)
- - [Patch Changes](#patch-changes)
- - [Unstable Changes](#unstable-changes)
+ - [Patch Changes](#patch-changes-1)
+ - [Unstable Changes](#unstable-changes-1)
- [v7.13.1](#v7131)
- [What's Changed](#whats-changed-1)
- [URL Masking (unstable)](#url-masking-unstable)
- - [Patch Changes](#patch-changes-1)
- - [Unstable Changes](#unstable-changes-1)
- - [v7.13.0](#v7130)
- - [Minor Changes](#minor-changes)
- [Patch Changes](#patch-changes-2)
- - [v7.12.0](#v7120)
- - [Security Notice](#security-notice)
+ - [Unstable Changes](#unstable-changes-2)
+ - [v7.13.0](#v7130)
- [Minor Changes](#minor-changes-1)
- [Patch Changes](#patch-changes-3)
- - [Unstable Changes](#unstable-changes-2)
+ - [v7.12.0](#v7120)
+ - [Security Notice](#security-notice)
+ - [Minor Changes](#minor-changes-2)
+ - [Patch Changes](#patch-changes-4)
+ - [Unstable Changes](#unstable-changes-3)
- [v7.11.0](#v7110)
- [What's Changed](#whats-changed-2)
- [`vite preview` Support](#vite-preview-support)
- [Stabilized Client-side `onError`](#stabilized-client-side-onerror)
- [Call-site Revalidation Opt-out (unstable)](#call-site-revalidation-opt-out-unstable)
- - [Minor Changes](#minor-changes-2)
- - [Patch Changes](#patch-changes-4)
- - [Unstable Changes](#unstable-changes-3)
- - [v7.10.1](#v7101)
+ - [Minor Changes](#minor-changes-3)
- [Patch Changes](#patch-changes-5)
+ - [Unstable Changes](#unstable-changes-4)
+ - [v7.10.1](#v7101)
+ - [Patch Changes](#patch-changes-6)
- [v7.10.0](#v7100)
- [What's Changed](#whats-changed-3)
- [Stabilized `future.v8_splitRouteModules`](#stabilized-futurev8_splitroutemodules)
- [Stabilized `future.v8_viteEnvironmentApi`](#stabilized-futurev8_viteenvironmentapi)
- [Stabilized `fetcher.reset()`](#stabilized-fetcherreset)
- [Stabilized `DataStrategyMatch.shouldCallHandler()`](#stabilized-datastrategymatchshouldcallhandler)
- - [Minor Changes](#minor-changes-3)
- - [Patch Changes](#patch-changes-6)
- - [Unstable Changes](#unstable-changes-4)
- - [v7.9.6](#v796)
- - [Security Notice](#security-notice-1)
+ - [Minor Changes](#minor-changes-4)
- [Patch Changes](#patch-changes-7)
- [Unstable Changes](#unstable-changes-5)
+ - [v7.9.6](#v796)
+ - [Security Notice](#security-notice-1)
+ - [Patch Changes](#patch-changes-8)
+ - [Unstable Changes](#unstable-changes-6)
- [v7.9.5](#v795)
- [What's Changed](#whats-changed-4)
- [Instrumentation (unstable)](#instrumentation-unstable)
- - [Patch Changes](#patch-changes-8)
- - [Unstable Changes](#unstable-changes-6)
+ - [Patch Changes](#patch-changes-9)
+ - [Unstable Changes](#unstable-changes-7)
- [v7.9.4](#v794)
- [Security Notice](#security-notice-2)
- [What's Changed](#whats-changed-5)
- [`useRoute()` (unstable)](#useroute-unstable)
- - [Patch Changes](#patch-changes-9)
- - [Unstable Changes](#unstable-changes-7)
- - [v7.9.3](#v793)
- [Patch Changes](#patch-changes-10)
+ - [Unstable Changes](#unstable-changes-8)
+ - [v7.9.3](#v793)
+ - [Patch Changes](#patch-changes-11)
- [v7.9.2](#v792)
- [What's Changed](#whats-changed-6)
- [RSC Framework Mode (unstable)](#rsc-framework-mode-unstable)
- [Fetcher Reset (unstable)](#fetcher-reset-unstable)
- - [Patch Changes](#patch-changes-11)
- - [Unstable Changes](#unstable-changes-8)
- - [v7.9.1](#v791)
- [Patch Changes](#patch-changes-12)
+ - [Unstable Changes](#unstable-changes-9)
+ - [v7.9.1](#v791)
+ - [Patch Changes](#patch-changes-13)
- [v7.9.0](#v790)
- [Security Notice](#security-notice-3)
- [What's Changed](#whats-changed-7)
- [Stable Middleware and Context APIs](#stable-middleware-and-context-apis)
- - [Minor Changes](#minor-changes-4)
- - [Patch Changes](#patch-changes-13)
- - [Unstable Changes](#unstable-changes-9)
- - [v7.8.2](#v782)
+ - [Minor Changes](#minor-changes-5)
- [Patch Changes](#patch-changes-14)
- [Unstable Changes](#unstable-changes-10)
- - [v7.8.1](#v781)
+ - [v7.8.2](#v782)
- [Patch Changes](#patch-changes-15)
- [Unstable Changes](#unstable-changes-11)
+ - [v7.8.1](#v781)
+ - [Patch Changes](#patch-changes-16)
+ - [Unstable Changes](#unstable-changes-12)
- [v7.8.0](#v780)
- [What's Changed](#whats-changed-8)
- [Consistently named `loaderData` values](#consistently-named-loaderdata-values)
- [Improvements/fixes to the middleware APIs (unstable)](#improvementsfixes-to-the-middleware-apis-unstable)
- - [Minor Changes](#minor-changes-5)
- - [Patch Changes](#patch-changes-16)
- - [Unstable Changes](#unstable-changes-12)
- - [Changes by Package](#changes-by-package)
- - [v7.7.1](#v771)
+ - [Minor Changes](#minor-changes-6)
- [Patch Changes](#patch-changes-17)
- [Unstable Changes](#unstable-changes-13)
+ - [Changes by Package](#changes-by-package)
+ - [v7.7.1](#v771)
+ - [Patch Changes](#patch-changes-18)
+ - [Unstable Changes](#unstable-changes-14)
- [v7.7.0](#v770)
- [What's Changed](#whats-changed-9)
- [Unstable RSC APIs](#unstable-rsc-apis)
- - [Minor Changes](#minor-changes-6)
- - [Patch Changes](#patch-changes-18)
- - [Unstable Changes](#unstable-changes-14)
+ - [Minor Changes](#minor-changes-7)
+ - [Patch Changes](#patch-changes-19)
+ - [Unstable Changes](#unstable-changes-15)
- [Changes by Package](#changes-by-package-1)
- [v7.6.3](#v763)
- - [Patch Changes](#patch-changes-19)
- - [v7.6.2](#v762)
- [Patch Changes](#patch-changes-20)
- - [v7.6.1](#v761)
+ - [v7.6.2](#v762)
- [Patch Changes](#patch-changes-21)
- - [Unstable Changes](#unstable-changes-15)
+ - [v7.6.1](#v761)
+ - [Patch Changes](#patch-changes-22)
+ - [Unstable Changes](#unstable-changes-16)
- [v7.6.0](#v760)
- [What's Changed](#whats-changed-10)
- [`routeDiscovery` Config Option](#routediscovery-config-option)
- [Automatic Types for Future Flags](#automatic-types-for-future-flags)
- - [Minor Changes](#minor-changes-7)
- - [Patch Changes](#patch-changes-22)
- - [Unstable Changes](#unstable-changes-16)
+ - [Minor Changes](#minor-changes-8)
+ - [Patch Changes](#patch-changes-23)
+ - [Unstable Changes](#unstable-changes-17)
- [Changes by Package](#changes-by-package-2)
- [v7.5.3](#v753)
- - [Patch Changes](#patch-changes-23)
+ - [Patch Changes](#patch-changes-24)
- [v7.5.2](#v752)
- [Security Notice](#security-notice-4)
- - [Patch Changes](#patch-changes-24)
- - [v7.5.1](#v751)
- [Patch Changes](#patch-changes-25)
- - [Unstable Changes](#unstable-changes-17)
+ - [v7.5.1](#v751)
+ - [Patch Changes](#patch-changes-26)
+ - [Unstable Changes](#unstable-changes-18)
- [v7.5.0](#v750)
- [What's Changed](#whats-changed-11)
- [`route.lazy` Object API](#routelazy-object-api)
- - [Minor Changes](#minor-changes-8)
- - [Patch Changes](#patch-changes-26)
- - [Unstable Changes](#unstable-changes-18)
+ - [Minor Changes](#minor-changes-9)
+ - [Patch Changes](#patch-changes-27)
+ - [Unstable Changes](#unstable-changes-19)
- [Changes by Package](#changes-by-package-3)
- [v7.4.1](#v741)
- [Security Notice](#security-notice-5)
- - [Patch Changes](#patch-changes-27)
- - [Unstable Changes](#unstable-changes-19)
- - [v7.4.0](#v740)
- - [Minor Changes](#minor-changes-9)
- [Patch Changes](#patch-changes-28)
- [Unstable Changes](#unstable-changes-20)
- - [Changes by Package](#changes-by-package-4)
- - [v7.3.0](#v730)
+ - [v7.4.0](#v740)
- [Minor Changes](#minor-changes-10)
- [Patch Changes](#patch-changes-29)
- [Unstable Changes](#unstable-changes-21)
+ - [Changes by Package](#changes-by-package-4)
+ - [v7.3.0](#v730)
+ - [Minor Changes](#minor-changes-11)
+ - [Patch Changes](#patch-changes-30)
+ - [Unstable Changes](#unstable-changes-22)
- [Client-side `context` (unstable)](#client-side-context-unstable)
- [Middleware (unstable)](#middleware-unstable)
- [Middleware `context` parameter](#middleware-context-parameter)
@@ -160,29 +164,29 @@ We manage release notes in this file instead of the paginated Github Releases Pa
- [Type-safe `href` utility](#type-safe-href-utility)
- [Prerendering with a SPA Fallback](#prerendering-with-a-spa-fallback)
- [Allow a root `loader` in SPA Mode](#allow-a-root-loader-in-spa-mode)
- - [Minor Changes](#minor-changes-11)
- - [Patch Changes](#patch-changes-30)
- - [Unstable Changes](#unstable-changes-22)
+ - [Minor Changes](#minor-changes-12)
+ - [Patch Changes](#patch-changes-31)
+ - [Unstable Changes](#unstable-changes-23)
- [Split Route Modules (unstable)](#split-route-modules-unstable)
- [Changes by Package](#changes-by-package-6)
- [v7.1.5](#v715)
- - [Patch Changes](#patch-changes-31)
- - [v7.1.4](#v714)
- [Patch Changes](#patch-changes-32)
- - [v7.1.3](#v713)
+ - [v7.1.4](#v714)
- [Patch Changes](#patch-changes-33)
- - [v7.1.2](#v712)
+ - [v7.1.3](#v713)
- [Patch Changes](#patch-changes-34)
- - [v7.1.1](#v711)
+ - [v7.1.2](#v712)
- [Patch Changes](#patch-changes-35)
- - [v7.1.0](#v710)
- - [Minor Changes](#minor-changes-12)
+ - [v7.1.1](#v711)
- [Patch Changes](#patch-changes-36)
+ - [v7.1.0](#v710)
+ - [Minor Changes](#minor-changes-13)
+ - [Patch Changes](#patch-changes-37)
- [Changes by Package](#changes-by-package-7)
- [v7.0.2](#v702)
- - [Patch Changes](#patch-changes-37)
- - [v7.0.1](#v701)
- [Patch Changes](#patch-changes-38)
+ - [v7.0.1](#v701)
+ - [Patch Changes](#patch-changes-39)
- [v7.0.0](#v700)
- [Breaking Changes](#breaking-changes)
- [Package Restructuring](#package-restructuring)
@@ -198,208 +202,208 @@ We manage release notes in this file instead of the paginated Github Releases Pa
- [Prerendering](#prerendering)
- [Major Changes (`react-router`)](#major-changes-react-router)
- [Major Changes (`@react-router/*`)](#major-changes-react-router-1)
- - [Minor Changes](#minor-changes-13)
- - [Patch Changes](#patch-changes-39)
+ - [Minor Changes](#minor-changes-14)
+ - [Patch Changes](#patch-changes-40)
- [Changes by Package](#changes-by-package-8)
- [React Router v6 Releases](#react-router-v6-releases)
- [v6.30.3](#v6303)
- [Security Notice](#security-notice-6)
- - [Patch Changes](#patch-changes-40)
+ - [Patch Changes](#patch-changes-41)
- [v6.30.2](#v6302)
- [Security Notice](#security-notice-7)
- - [Patch Changes](#patch-changes-41)
- - [v6.30.1](#v6301)
- [Patch Changes](#patch-changes-42)
- - [v6.30.0](#v6300)
- - [Minor Changes](#minor-changes-14)
+ - [v6.30.1](#v6301)
- [Patch Changes](#patch-changes-43)
- - [v6.29.0](#v6290)
+ - [v6.30.0](#v6300)
- [Minor Changes](#minor-changes-15)
- [Patch Changes](#patch-changes-44)
- - [v6.28.2](#v6282)
+ - [v6.29.0](#v6290)
+ - [Minor Changes](#minor-changes-16)
- [Patch Changes](#patch-changes-45)
- - [v6.28.1](#v6281)
+ - [v6.28.2](#v6282)
- [Patch Changes](#patch-changes-46)
+ - [v6.28.1](#v6281)
+ - [Patch Changes](#patch-changes-47)
- [v6.28.0](#v6280)
- [What's Changed](#whats-changed-13)
- - [Minor Changes](#minor-changes-16)
- - [Patch Changes](#patch-changes-47)
+ - [Minor Changes](#minor-changes-17)
+ - [Patch Changes](#patch-changes-48)
- [v6.27.0](#v6270)
- [What's Changed](#whats-changed-14)
- [Stabilized APIs](#stabilized-apis)
- - [Minor Changes](#minor-changes-17)
- - [Patch Changes](#patch-changes-48)
- - [v6.26.2](#v6262)
+ - [Minor Changes](#minor-changes-18)
- [Patch Changes](#patch-changes-49)
- - [v6.26.1](#v6261)
+ - [v6.26.2](#v6262)
- [Patch Changes](#patch-changes-50)
- - [v6.26.0](#v6260)
- - [Minor Changes](#minor-changes-18)
+ - [v6.26.1](#v6261)
- [Patch Changes](#patch-changes-51)
- - [v6.25.1](#v6251)
+ - [v6.26.0](#v6260)
+ - [Minor Changes](#minor-changes-19)
- [Patch Changes](#patch-changes-52)
+ - [v6.25.1](#v6251)
+ - [Patch Changes](#patch-changes-53)
- [v6.25.0](#v6250)
- [What's Changed](#whats-changed-15)
- [Stabilized `v7_skipActionErrorRevalidation`](#stabilized-v7_skipactionerrorrevalidation)
- - [Minor Changes](#minor-changes-19)
- - [Patch Changes](#patch-changes-53)
- - [v6.24.1](#v6241)
+ - [Minor Changes](#minor-changes-20)
- [Patch Changes](#patch-changes-54)
+ - [v6.24.1](#v6241)
+ - [Patch Changes](#patch-changes-55)
- [v6.24.0](#v6240)
- [What's Changed](#whats-changed-16)
- [Lazy Route Discovery (a.k.a. "Fog of War")](#lazy-route-discovery-aka-fog-of-war)
- - [Minor Changes](#minor-changes-20)
- - [Patch Changes](#patch-changes-55)
- - [v6.23.1](#v6231)
+ - [Minor Changes](#minor-changes-21)
- [Patch Changes](#patch-changes-56)
+ - [v6.23.1](#v6231)
+ - [Patch Changes](#patch-changes-57)
- [v6.23.0](#v6230)
- [What's Changed](#whats-changed-17)
- [Data Strategy (unstable)](#data-strategy-unstable)
- [Skip Action Error Revalidation (unstable)](#skip-action-error-revalidation-unstable)
- - [Minor Changes](#minor-changes-21)
+ - [Minor Changes](#minor-changes-22)
- [v6.22.3](#v6223)
- - [Patch Changes](#patch-changes-57)
- - [v6.22.2](#v6222)
- [Patch Changes](#patch-changes-58)
- - [v6.22.1](#v6221)
+ - [v6.22.2](#v6222)
- [Patch Changes](#patch-changes-59)
+ - [v6.22.1](#v6221)
+ - [Patch Changes](#patch-changes-60)
- [v6.22.0](#v6220)
- [What's Changed](#whats-changed-18)
- [Core Web Vitals Technology Report Flag](#core-web-vitals-technology-report-flag)
- - [Minor Changes](#minor-changes-22)
- - [Patch Changes](#patch-changes-60)
- - [v6.21.3](#v6213)
+ - [Minor Changes](#minor-changes-23)
- [Patch Changes](#patch-changes-61)
- - [v6.21.2](#v6212)
+ - [v6.21.3](#v6213)
- [Patch Changes](#patch-changes-62)
- - [v6.21.1](#v6211)
+ - [v6.21.2](#v6212)
- [Patch Changes](#patch-changes-63)
+ - [v6.21.1](#v6211)
+ - [Patch Changes](#patch-changes-64)
- [v6.21.0](#v6210)
- [What's Changed](#whats-changed-19)
- [`future.v7_relativeSplatPath`](#futurev7_relativesplatpath)
- [Partial Hydration](#partial-hydration)
- - [Minor Changes](#minor-changes-23)
- - [Patch Changes](#patch-changes-64)
- - [v6.20.1](#v6201)
- - [Patch Changes](#patch-changes-65)
- - [v6.20.0](#v6200)
- [Minor Changes](#minor-changes-24)
+ - [Patch Changes](#patch-changes-65)
+ - [v6.20.1](#v6201)
- [Patch Changes](#patch-changes-66)
+ - [v6.20.0](#v6200)
+ - [Minor Changes](#minor-changes-25)
+ - [Patch Changes](#patch-changes-67)
- [v6.19.0](#v6190)
- [What's Changed](#whats-changed-20)
- [`unstable_flushSync` API](#unstable_flushsync-api)
- - [Minor Changes](#minor-changes-25)
- - [Patch Changes](#patch-changes-67)
+ - [Minor Changes](#minor-changes-26)
+ - [Patch Changes](#patch-changes-68)
- [v6.18.0](#v6180)
- [What's Changed](#whats-changed-21)
- [New Fetcher APIs](#new-fetcher-apis)
- [Persistence Future Flag (`future.v7_fetcherPersist`)](#persistence-future-flag-futurev7_fetcherpersist)
- - [Minor Changes](#minor-changes-26)
- - [Patch Changes](#patch-changes-68)
+ - [Minor Changes](#minor-changes-27)
+ - [Patch Changes](#patch-changes-69)
- [v6.17.0](#v6170)
- [What's Changed](#whats-changed-22)
- [View Transitions 🚀](#view-transitions-)
- - [Minor Changes](#minor-changes-27)
- - [Patch Changes](#patch-changes-69)
- - [v6.16.0](#v6160)
- [Minor Changes](#minor-changes-28)
- [Patch Changes](#patch-changes-70)
- - [v6.15.0](#v6150)
+ - [v6.16.0](#v6160)
- [Minor Changes](#minor-changes-29)
- [Patch Changes](#patch-changes-71)
- - [v6.14.2](#v6142)
+ - [v6.15.0](#v6150)
+ - [Minor Changes](#minor-changes-30)
- [Patch Changes](#patch-changes-72)
- - [v6.14.1](#v6141)
+ - [v6.14.2](#v6142)
- [Patch Changes](#patch-changes-73)
+ - [v6.14.1](#v6141)
+ - [Patch Changes](#patch-changes-74)
- [v6.14.0](#v6140)
- [What's Changed](#whats-changed-23)
- [JSON/Text Submissions](#jsontext-submissions)
- - [Minor Changes](#minor-changes-30)
- - [Patch Changes](#patch-changes-74)
+ - [Minor Changes](#minor-changes-31)
+ - [Patch Changes](#patch-changes-75)
- [v6.13.0](#v6130)
- [What's Changed](#whats-changed-24)
- [`future.v7_startTransition`](#futurev7_starttransition)
- - [Minor Changes](#minor-changes-31)
- - [Patch Changes](#patch-changes-75)
- - [v6.12.1](#v6121)
+ - [Minor Changes](#minor-changes-32)
- [Patch Changes](#patch-changes-76)
+ - [v6.12.1](#v6121)
+ - [Patch Changes](#patch-changes-77)
- [v6.12.0](#v6120)
- [What's Changed](#whats-changed-25)
- [`React.startTransition` support](#reactstarttransition-support)
- - [Minor Changes](#minor-changes-32)
- - [Patch Changes](#patch-changes-77)
- - [v6.11.2](#v6112)
+ - [Minor Changes](#minor-changes-33)
- [Patch Changes](#patch-changes-78)
- - [v6.11.1](#v6111)
+ - [v6.11.2](#v6112)
- [Patch Changes](#patch-changes-79)
- - [v6.11.0](#v6110)
- - [Minor Changes](#minor-changes-33)
+ - [v6.11.1](#v6111)
- [Patch Changes](#patch-changes-80)
+ - [v6.11.0](#v6110)
+ - [Minor Changes](#minor-changes-34)
+ - [Patch Changes](#patch-changes-81)
- [v6.10.0](#v6100)
- [What's Changed](#whats-changed-26)
- - [Minor Changes](#minor-changes-34)
+ - [Minor Changes](#minor-changes-35)
- [`future.v7_normalizeFormMethod`](#futurev7_normalizeformmethod)
- - [Patch Changes](#patch-changes-81)
+ - [Patch Changes](#patch-changes-82)
- [v6.9.0](#v690)
- [What's Changed](#whats-changed-27)
- [`Component`/`ErrorBoundary` route properties](#componenterrorboundary-route-properties)
- [Introducing Lazy Route Modules](#introducing-lazy-route-modules)
- - [Minor Changes](#minor-changes-35)
- - [Patch Changes](#patch-changes-82)
- - [v6.8.2](#v682)
+ - [Minor Changes](#minor-changes-36)
- [Patch Changes](#patch-changes-83)
- - [v6.8.1](#v681)
+ - [v6.8.2](#v682)
- [Patch Changes](#patch-changes-84)
- - [v6.8.0](#v680)
- - [Minor Changes](#minor-changes-36)
+ - [v6.8.1](#v681)
- [Patch Changes](#patch-changes-85)
- - [v6.7.0](#v670)
+ - [v6.8.0](#v680)
- [Minor Changes](#minor-changes-37)
- [Patch Changes](#patch-changes-86)
- - [v6.6.2](#v662)
+ - [v6.7.0](#v670)
+ - [Minor Changes](#minor-changes-38)
- [Patch Changes](#patch-changes-87)
- - [v6.6.1](#v661)
+ - [v6.6.2](#v662)
- [Patch Changes](#patch-changes-88)
+ - [v6.6.1](#v661)
+ - [Patch Changes](#patch-changes-89)
- [v6.6.0](#v660)
- [What's Changed](#whats-changed-28)
- - [Minor Changes](#minor-changes-38)
- - [Patch Changes](#patch-changes-89)
- - [v6.5.0](#v650)
- - [What's Changed](#whats-changed-29)
- [Minor Changes](#minor-changes-39)
- [Patch Changes](#patch-changes-90)
- - [v6.4.5](#v645)
+ - [v6.5.0](#v650)
+ - [What's Changed](#whats-changed-29)
+ - [Minor Changes](#minor-changes-40)
- [Patch Changes](#patch-changes-91)
- - [v6.4.4](#v644)
+ - [v6.4.5](#v645)
- [Patch Changes](#patch-changes-92)
- - [v6.4.3](#v643)
+ - [v6.4.4](#v644)
- [Patch Changes](#patch-changes-93)
- - [v6.4.2](#v642)
+ - [v6.4.3](#v643)
- [Patch Changes](#patch-changes-94)
- - [v6.4.1](#v641)
+ - [v6.4.2](#v642)
- [Patch Changes](#patch-changes-95)
+ - [v6.4.1](#v641)
+ - [Patch Changes](#patch-changes-96)
- [v6.4.0](#v640)
- [What's Changed](#whats-changed-30)
- [Remix Data APIs](#remix-data-apis)
- - [Patch Changes](#patch-changes-96)
+ - [Patch Changes](#patch-changes-97)
- [v6.3.0](#v630)
- - [Minor Changes](#minor-changes-40)
+ - [Minor Changes](#minor-changes-41)
- [v6.2.2](#v622)
- - [Patch Changes](#patch-changes-97)
- - [v6.2.1](#v621)
- [Patch Changes](#patch-changes-98)
- - [v6.2.0](#v620)
- - [Minor Changes](#minor-changes-41)
+ - [v6.2.1](#v621)
- [Patch Changes](#patch-changes-99)
- - [v6.1.1](#v611)
- - [Patch Changes](#patch-changes-100)
- - [v6.1.0](#v610)
+ - [v6.2.0](#v620)
- [Minor Changes](#minor-changes-42)
+ - [Patch Changes](#patch-changes-100)
+ - [v6.1.1](#v611)
- [Patch Changes](#patch-changes-101)
- - [v6.0.2](#v602)
+ - [v6.1.0](#v610)
+ - [Minor Changes](#minor-changes-43)
- [Patch Changes](#patch-changes-102)
- - [v6.0.1](#v601)
+ - [v6.0.2](#v602)
- [Patch Changes](#patch-changes-103)
+ - [v6.0.1](#v601)
+ - [Patch Changes](#patch-changes-104)
- [v6.0.0](#v600)
@@ -427,6 +431,85 @@ Date: YYYY-MM-DD
**Full Changelog**: [`v7.X.Y...v7.X.Y`](https://github.com/remix-run/react-router/compare/react-router@7.X.Y...react-router@7.X.Y)
-->
+## v7.14.0
+
+Date: 2026-04-02
+
+### Minor Changes
+
+- Add support for Vite 8 ([#14876](https://github.com/remix-run/react-router/pull/14876))
+
+### Patch Changes
+
+- `react-router` - Remove recursion from vendored `turbo-stream` v2 implementation allowing for encoding/decoding of large payloads ([#14838](https://github.com/remix-run/react-router/pull/14838))
+- `react-router` - Fix `encodeViaTurboStream` memory leak via unremoved `AbortSignal` listener ([#14900](https://github.com/remix-run/react-router/pull/14900))
+- `@react-router/dev` - Support for prerendering multiple server bundles with `v8_viteEnvironmentApi` ([#14921](https://github.com/remix-run/react-router/pull/14921))
+
+### Unstable Changes
+
+⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
+
+- `@react-router/dev` - Pre-rendering and SPA Mode support for RSC Framework Mode ([#14907](https://github.com/remix-run/react-router/pull/14907))
+- `@react-router/dev` - Update `react-router reveal` to support RSC Framework Mode for `entry.client`, `entry.rsc`, `entry.ssr` ([#14904](https://github.com/remix-run/react-router/pull/14904))
+- `react-router` - Support `` in RSC Framework Mode ([#14902](https://github.com/remix-run/react-router/pull/14902))
+- `react-router` - Add support for new route module exports in unstable RSC Framework Mode ([#14901](https://github.com/remix-run/react-router/pull/14901))
+ - ⚠️ This is a breaking change if you have already adopted RSC Framework Mode in it's unstable state - you will need to update your route modules to export the new annotations
+ - The following route module components have their own mutually exclusive server component counterparts:
+
+ | Client Component export | Server Component export |
+ | ----------------------- | ----------------------- |
+ | `default` | `ServerComponent` |
+ | `ErrorBoundary` | `ServerErrorBoundary` |
+ | `Layout` | `ServerLayout` |
+ | `HydrateFallback` | `ServerHydrateFallback` |
+
+ - If you were previously exporting a `ServerComponent`, your `ErrorBoundary`, `Layout`, and `HydrateFallback` were also implicitly server components
+ - If you want to keep those as server components - rename them and prefix them with `Server`
+ - If you were previously importing the implementations of those components from a client module, you can inline them
+
+ ```tsx
+ // Before
+ import { ErrorBoundary as ClientErrorBoundary } from "./client";
+
+ export function ServerComponent() {
+ // ...
+ }
+
+ export function ErrorBoundary() {
+ return ;
+ }
+
+ export function Layout() {
+ // ...
+ }
+
+ export function HydrateFallback() {
+ // ...
+ }
+ ```
+
+ ```tsx
+ // After
+
+ export function ServerComponent() {
+ // ...
+ }
+
+ export function ErrorBoundary() {
+ // previous implementation of ClientErrorBoundary, this is now a client component
+ }
+
+ export function ServerLayout() {
+ // rename previous Layout export to ServerLayout to make it a server component
+ }
+
+ export function ServerHydrateFallback() {
+ // rename previous HydrateFallback export to ServerHydrateFallback to make it a server component
+ }
+ ```
+
+**Full Changelog**: [`v7.13.2...v7.14.0`](https://github.com/remix-run/react-router/compare/react-router@7.13.2...react-router@7.14.0)
+
## v7.13.2
Date: 2026-03-23
diff --git a/contributors.yml b/contributors.yml
index edae2d43bd..e166455453 100644
--- a/contributors.yml
+++ b/contributors.yml
@@ -257,6 +257,7 @@
- lounsbrough
- lpaube
- lqze
+- luchsamapparat
- lukerSpringTree
- m-dad
- m-kawafuji
diff --git a/docs/how-to/react-server-components.md b/docs/how-to/react-server-components.md
index c86eda8753..0841899632 100644
--- a/docs/how-to/react-server-components.md
+++ b/docs/how-to/react-server-components.md
@@ -34,8 +34,8 @@ The quickest way to get started is with one of our templates.
These templates come with React Router RSC APIs already configured, offering you out of the box features such as:
-- Server Component Routes
- Server Side Rendering (SSR)
+- Server Components
- Client Components (via [`"use client"`][use-client-docs] directive)
- Server Functions (via [`"use server"`][use-server-docs] directive)
@@ -171,9 +171,18 @@ export default function Route({
}
```
-### Server Component Routes
+### Route Server Components
+
+If a route exports a `ServerComponent` instead of the typical `default` component export, this will be a server component rather than the usual client component. A default export and `ServerComponent` can not both be exported from the same route module, but you can still export client-only annotations like `clientLoader` and `clientAction` alongside a `ServerComponent`, along with any other component exports such as `ErrorBoundary` or `Layout`.
-If a route exports a `ServerComponent` instead of the typical `default` component export, this component along with other route components (`ErrorBoundary`, `HydrateFallback`, `Layout`) will be server components rather than the usual client components.
+The following route module components have their own mutually exclusive server component counterparts:
+
+| Server Component Export | Client Component |
+| ----------------------- | ----------------- |
+| `ServerComponent` | `default` |
+| `ServerErrorBoundary` | `ErrorBoundary` |
+| `ServerLayout` | `Layout` |
+| `ServerHydrateFallback` | `HydrateFallback` |
```tsx
import type { Route } from "./+types/route";
@@ -188,7 +197,7 @@ export async function loader() {
export function ServerComponent({
loaderData,
-}: Route.ComponentProps) {
+}: Route.ServerComponentProps) {
return (
<>
Server Component Route
diff --git a/eslint.config.ts b/eslint.config.ts
new file mode 100644
index 0000000000..290536b621
--- /dev/null
+++ b/eslint.config.ts
@@ -0,0 +1,280 @@
+import { createRequire } from "node:module";
+import { fixupPluginRules } from "@eslint/compat";
+import { defineConfig } from "eslint/config";
+
+const require = createRequire(import.meta.url);
+const eslintRequire = createRequire(require.resolve("eslint/package.json"));
+
+const globals = eslintRequire("globals");
+const reactAppConfig = require("eslint-config-react-app");
+
+const flowtypePlugin = fixupPluginRules(require("eslint-plugin-flowtype"));
+const importPlugin = fixupPluginRules(require("eslint-plugin-import"));
+const jestPlugin = fixupPluginRules(require("eslint-plugin-jest"));
+const jsdocPlugin = fixupPluginRules(require("eslint-plugin-jsdoc"));
+const jsxA11yPlugin = fixupPluginRules(require("eslint-plugin-jsx-a11y"));
+const reactPlugin = fixupPluginRules(require("eslint-plugin-react"));
+const reactHooksPlugin = fixupPluginRules(require("eslint-plugin-react-hooks"));
+const tsEslintPlugin = fixupPluginRules(
+ require("@typescript-eslint/eslint-plugin"),
+);
+const tsParser = require("@typescript-eslint/parser");
+
+const reactAppTsOverride = reactAppConfig.overrides.find(
+ (config: { files?: string[] }) => config.files?.includes("**/*.ts?(x)"),
+);
+
+if (!reactAppTsOverride) {
+ throw new Error("Could not find the react-app TypeScript override.");
+}
+
+const jestRecommended = jestPlugin.configs["flat/recommended"];
+
+function normalizeGlobals(globalsToNormalize: Record) {
+ return Object.fromEntries(
+ Object.entries(globalsToNormalize).map(([name, value]) => [
+ name.trim(),
+ value,
+ ]),
+ );
+}
+
+function disableGlobals(globalsToDisable: Record) {
+ return Object.fromEntries(
+ Object.keys(globalsToDisable).map((name) => [name, "off"] as const),
+ );
+}
+
+const codeFiles = ["**/*.{js,mjs,cjs,jsx,ts,tsx}"];
+const reactRouterFiles = ["packages/react-router/**/*.{js,mjs,cjs,jsx,ts,tsx}"];
+const browserGlobals = normalizeGlobals(globals.browser);
+const commonJsGlobals = normalizeGlobals(globals.commonjs);
+const nodeGlobals = normalizeGlobals(globals.node);
+const jestGlobals = normalizeGlobals(globals.jest);
+
+export default defineConfig([
+ {
+ ignores: [
+ "fixtures/**",
+ "node_modules/**",
+ "pnpm-lock.yaml",
+ "docs/api/**",
+ "examples/**/dist/**",
+ "worker-configuration.d.ts",
+ "playground/**",
+ "playground-local/**",
+ "integration/helpers/**/dist/**",
+ "integration/helpers/**/build/**",
+ "playwright-report/**",
+ "test-results/**",
+ "build.utils.d.ts",
+ ".wrangler/**",
+ "**/.wrangler/**",
+ ".tmp/**",
+ ".react-router/**",
+ "**/.react-router/**",
+ "packages/**/dist/**",
+ "packages/react-router-dom/server.d.ts",
+ "packages/react-router-dom/server.js",
+ "packages/react-router-dom/server.mjs",
+ "tutorial/dist/**",
+ "public/**",
+ ],
+ },
+ {
+ linterOptions: {
+ reportUnusedDisableDirectives: "warn",
+ },
+ },
+ {
+ files: codeFiles,
+ languageOptions: {
+ parserOptions: {
+ ecmaVersion: "latest",
+ sourceType: "module",
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+ globals: {
+ ...browserGlobals,
+ ...commonJsGlobals,
+ ...nodeGlobals,
+ ...jestGlobals,
+ },
+ },
+ plugins: {
+ flowtype: flowtypePlugin,
+ import: importPlugin,
+ "jsx-a11y": jsxA11yPlugin,
+ react: reactPlugin,
+ "react-hooks": reactHooksPlugin,
+ },
+ settings: {
+ react: {
+ version: "detect",
+ },
+ },
+ rules: {
+ ...reactAppConfig.rules,
+ "import/first": "off",
+ "react/jsx-uses-react": "warn",
+ "react/jsx-uses-vars": "warn",
+ },
+ },
+ {
+ files: ["**/*.{ts,tsx}"],
+ languageOptions: {
+ parser: tsParser,
+ parserOptions: {
+ ecmaVersion: "latest",
+ sourceType: "module",
+ ecmaFeatures: {
+ jsx: true,
+ },
+ warnOnUnsupportedTypeScriptVersion: true,
+ },
+ },
+ plugins: {
+ "@typescript-eslint": tsEslintPlugin,
+ },
+ rules: {
+ ...reactAppTsOverride.rules,
+ "@typescript-eslint/consistent-type-imports": [
+ "error",
+ {
+ disallowTypeAnnotations: false,
+ },
+ ],
+ "import/no-anonymous-default-export": "off",
+ },
+ },
+ {
+ files: ["**/__tests__/**/*.{js,mjs,cjs,jsx,ts,tsx}"],
+ plugins: {
+ jest: jestPlugin,
+ },
+ languageOptions: jestRecommended.languageOptions,
+ rules: jestRecommended.rules,
+ },
+ {
+ files: ["integration/**/*.{js,mjs,cjs,jsx,ts,tsx}"],
+ languageOptions: {
+ globals: disableGlobals(jestGlobals),
+ },
+ rules: {
+ "react-hooks/rules-of-hooks": "off",
+ },
+ },
+ {
+ files: reactRouterFiles,
+ rules: {
+ strict: "off",
+ "import/no-nodejs-modules": "error",
+ "no-restricted-globals": [
+ "error",
+ {
+ name: "__dirname",
+ message: "Node globals are not allowed in this package.",
+ },
+ {
+ name: "__filename",
+ message: "Node globals are not allowed in this package.",
+ },
+ {
+ name: "Buffer",
+ message: "Node globals are not allowed in this package.",
+ },
+ ],
+ },
+ },
+ {
+ files: ["packages/react-router/__tests__/**/*.{js,mjs,cjs,jsx,ts,tsx}"],
+ rules: {
+ "import/no-nodejs-modules": "off",
+ "no-console": "off",
+ "no-restricted-globals": "off",
+ },
+ },
+ {
+ files: [
+ "packages/react-router/lib/server-runtime/**/*.{js,mjs,cjs,jsx,ts,tsx}",
+ ],
+ rules: {
+ "no-restricted-syntax": "off",
+ },
+ },
+ {
+ files: ["packages/react-router-dev/config/default-rsc-entries/*"],
+ rules: {
+ "@typescript-eslint/consistent-type-imports": "off",
+ },
+ },
+ {
+ files: [
+ "packages/react-router/lib/components.tsx",
+ "packages/react-router/lib/hooks.tsx",
+ "packages/react-router/lib/dom/lib.tsx",
+ "packages/react-router/lib/dom/ssr/components.tsx",
+ "packages/react-router/lib/dom/ssr/server.tsx",
+ "packages/react-router/lib/dom-export/hydrated-router.tsx",
+ "packages/react-router/lib/dom/server.tsx",
+ "packages/react-router/lib/router/utils.ts",
+ "packages/react-router/lib/rsc/browser.tsx",
+ "packages/react-router/lib/rsc/server.rsc.ts",
+ "packages/react-router/lib/rsc/server.ssr.tsx",
+ "packages/react-router/lib/rsc/html-stream/browser.ts",
+ ],
+ plugins: {
+ jsdoc: jsdocPlugin,
+ },
+ rules: {
+ "jsdoc/check-access": "error",
+ "jsdoc/check-alignment": "error",
+ "jsdoc/check-param-names": "error",
+ "jsdoc/check-property-names": "error",
+ "jsdoc/check-tag-names": [
+ "error",
+ {
+ definedTags: ["additionalExamples", "category", "mode"],
+ },
+ ],
+ "jsdoc/no-defaults": "error",
+ "jsdoc/no-multi-asterisks": ["error", { allowWhitespace: true }],
+ "jsdoc/require-description": "error",
+ "jsdoc/require-param": ["error", { enableRootFixer: false }],
+ "jsdoc/require-param-description": "error",
+ "jsdoc/require-param-name": "error",
+ "jsdoc/require-returns": "error",
+ "jsdoc/require-returns-check": "error",
+ "jsdoc/require-returns-description": "error",
+ "jsdoc/sort-tags": [
+ "error",
+ {
+ tagSequence: [
+ {
+ tags: ["description"],
+ },
+ {
+ tags: ["example"],
+ },
+ {
+ tags: ["additionalExamples"],
+ },
+ {
+ tags: [
+ "name",
+ "public",
+ "private",
+ "category",
+ "mode",
+ "param",
+ "returns",
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ },
+]);
diff --git a/integration/browser-entry-test.ts b/integration/browser-entry-test.ts
index ad984fd43d..6affea8776 100644
--- a/integration/browser-entry-test.ts
+++ b/integration/browser-entry-test.ts
@@ -56,6 +56,7 @@ test(
// This sets up the Remix modules cache in memory, priming the error case.
await app.goto("/");
await app.clickLink("/burgers");
+ await page.waitForSelector("#cheeseburger");
expect(await page.content()).toContain("cheeseburger");
await page.goBack();
await page.waitForSelector("#pizza");
diff --git a/integration/cli-test.ts b/integration/cli-test.ts
index 7227f73e7e..366dfa71c4 100644
--- a/integration/cli-test.ts
+++ b/integration/cli-test.ts
@@ -138,6 +138,23 @@ test.describe("cli", () => {
expect(existsSync(entryClientFile)).toBeTruthy();
});
+ test("rsc generates entry.{ssr,rsc,client}.tsx in the app directory", async () => {
+ const cwd = await createProject({}, "rsc-vite-framework");
+ let entrySSRFile = path.join(cwd, "app", "entry.ssr.tsx");
+ let entryRSCFile = path.join(cwd, "app", "entry.rsc.tsx");
+ let entryClientFile = path.join(cwd, "app", "entry.client.tsx");
+
+ expect(existsSync(entrySSRFile)).toBeFalsy();
+ expect(existsSync(entryRSCFile)).toBeFalsy();
+ expect(existsSync(entryClientFile)).toBeFalsy();
+
+ run(["reveal"], { cwd });
+
+ expect(existsSync(entrySSRFile)).toBeTruthy();
+ expect(existsSync(entryRSCFile)).toBeTruthy();
+ expect(existsSync(entryClientFile)).toBeTruthy();
+ });
+
test("generates specified entries in the app directory", async () => {
const cwd = await createProject();
diff --git a/integration/client-data-test.ts b/integration/client-data-test.ts
index bceee0d01c..768460e66f 100644
--- a/integration/client-data-test.ts
+++ b/integration/client-data-test.ts
@@ -149,12 +149,31 @@ test.describe("Client Data", () => {
templateName,
files: {
"react-router.config.ts": reactRouterConfig({
- future: { v8_splitRouteModules },
+ future: { v8_splitRouteModules, v8_middleware: true },
}),
"app/root.tsx": js`
import { Form, Outlet, Scripts } from "react-router"
- export default function Root({ loaderData }) {
+ export const middleware = [
+ async ({ request }, next) => {
+ let response = await next();
+
+ if (
+ request.method === "GET" &&
+ response instanceof Response &&
+ response.status === 200 &&
+ request.headers.get("sec-purpose") === "prefetch" &&
+ !response.headers.has("Cache-Control")
+ ) {
+ let cachedResponse = new Response(response.body, response);
+ cachedResponse.headers.set("Cache-Control", "max-age=5");
+ return cachedResponse;
+ }
+ return response;
+ }
+ ];
+
+ export default function Root() {
return (
@@ -606,7 +625,7 @@ test.describe("Client Data", () => {
}
`,
"app/routes/client-loader-critical.bubbled-server-loader-errors-are-persisted-for-hydrating-routes.parent.child.tsx": js`
- import { useRouteError, useLoaderData } from 'react-router'
+ import { useLoaderData } from 'react-router'
export function loader() {
throw new Error('Child Server Error');
}
@@ -1142,9 +1161,9 @@ test.describe("Client Data", () => {
"/client-loader-critical/client-loader-hydrate-is-automatically-implied-when-no-server-loader-exists-without-hydrate-fallback/parent/child",
);
let html = await app.getHtml();
- expect(html).toMatch(
- "💿 Hey developer 👋. You can provide a way better UX than this",
- );
+ // Production builds strip dev-only warning logs, but we should
+ // still render the default root loading shell until hydration runs.
+ expect(html).toMatch("Loading...");
expect(html).not.toMatch("child-data");
await page.waitForSelector("#child-data");
html = await app.getHtml("main");
@@ -1240,24 +1259,13 @@ test.describe("Client Data", () => {
let app = new PlaywrightFixture(appFixture, page);
let logs: string[] = [];
page.on("console", (msg) => {
- if (msg.type() === "timeStamp") return;
-
let text = msg.text();
- if (
- // Chrome logs the 500 as a console error, so skip that since it's not
- // what we are asserting against here
- /500 \(Internal Server Error\)/.test(text) ||
- // Ignore any dev tools messages. This may only happen locally when dev
- // tools is installed and not in CI but either way we don't care
- /Download the React DevTools/.test(text) ||
- (templateName.includes("rsc") &&
- /The element is a no-op when using RSC and can be safely removed./.test(
- text,
- ))
- ) {
- return;
+ // Firefox surfaces React performance track labels on the console
+ // during hydration, so only capture the application log this
+ // assertion actually cares about.
+ if (text === "running parent client loader") {
+ logs.push(text);
}
- logs.push(text);
});
await app.goto(
"/client-loader-critical/bubbled-server-loader-errors-are-persisted-for-hydrating-routes/parent/child",
diff --git a/integration/defer-test.ts b/integration/defer-test.ts
index 6e4f9a65d7..13cb46b82d 100644
--- a/integration/defer-test.ts
+++ b/integration/defer-test.ts
@@ -1,5 +1,5 @@
import { test, expect } from "@playwright/test";
-import type { ConsoleMessage, Page } from "@playwright/test";
+import type { Page } from "@playwright/test";
import { PlaywrightFixture } from "./helpers/playwright-fixture.js";
import type { Fixture, AppFixture } from "./helpers/create-fixture.js";
@@ -32,17 +32,34 @@ declare global {
};
}
+function counterHtml(id: string, val: number) {
+ return `${val}
`;
+}
+
+const deferredHTMLStartString = " {
let fixture: Fixture;
let appFixture: AppFixture;
- test.beforeEach(async ({ context }) => {
- await context.route(/.data/, async (route) => {
- await new Promise((resolve) => setTimeout(resolve, 50));
- route.continue();
- });
- });
-
test.beforeAll(async () => {
fixture = await createFixture({
files: {
@@ -107,7 +124,7 @@ test.describe("non-aborted", () => {
{/* Send arbitrary data so safari renders the initial shell before
the document finishes downloading. */}
- {Array(10000).fill(null).map((_, i)=>YOOOOOOOOOO {i}
)}
+ {Array(1000).fill(null).map((_, i)=>YOOOOOOOOOO {i}
)}