Skip to content

Commit 650bd65

Browse files
teukuamrufranky47
andauthored
feat: Added react-router v7 support (#785)
* chore: install react-router v7 * ref: adding react-router v6 and v7 * build: add react-router v6 v7 in commonConfig, entrypoint, and package.json * doc: update comment path in react-router d.ts related files * doc: add a note for react-router in docs * chore: Fix sherif * test: Split RRv6 & RRv7 e2e test benches * chore: Formatting * chore: Normalise ports * chore: CI name formatting * chore: Use explicit RRv6 adapter in e2e test bench * chore: Add nuqs to RRv7 e2e test bench * doc: Update message in react-router shorthand adapter --------- Co-authored-by: Francois Best <github@francoisbest.com>
1 parent 0068f4b commit 650bd65

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+712
-50
lines changed

.github/workflows/ci-cd.yml

+11-5
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,15 @@ jobs:
155155
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
156156

157157
e2e-react-router:
158-
name: E2E (react-router)
158+
name: E2E (react-router ${{ matrix.react-router-version }})
159159
runs-on: ubuntu-24.04
160160
needs: [ci-core]
161+
strategy:
162+
fail-fast: false
163+
matrix:
164+
react-router-version:
165+
- 'v6'
166+
- 'v7'
161167
steps:
162168
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
163169
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2
@@ -168,7 +174,7 @@ jobs:
168174
- name: Install dependencies
169175
run: pnpm install
170176
- name: Run tests
171-
run: pnpm run test ${{ github.event_name == 'workflow_dispatch' && '--force' || '' }} --filter e2e-react-router
177+
run: pnpm run test ${{ github.event_name == 'workflow_dispatch' && '--force' || '' }} --filter e2e-react-router-${{ matrix.react-router-version }}
172178
env:
173179
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
174180
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
@@ -177,14 +183,14 @@ jobs:
177183
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882
178184
if: failure()
179185
with:
180-
path: packages/e2e/react-router/cypress/screenshots
181-
name: ci-react-router
186+
path: packages/e2e/react-router/${{ matrix.react-router-version }}/cypress/screenshots
187+
name: ci-react-router-${{ matrix.react-router-version }}
182188
- uses: 47ng/actions-slack-notify@main
183189
name: Notify on Slack
184190
if: always()
185191
with:
186192
status: ${{ job.status }}
187-
jobName: react-router
193+
jobName: react-router-${{ matrix.react-router-version }}
188194
env:
189195
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
190196

CONTRIBUTING.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ When running `next dev`, this will:
2121
- Build the library and watch for changes using [`tsup`](https://tsup.egoist.dev/)
2222
- Start the docs app, which will be available at <http://localhost:3000>.
2323
- Start the end-to-end test benches:
24-
- Next.js: http://localhost:3001
25-
- Remix: http://localhost:3002
26-
- React Router: http://localhost:3003
27-
- React SPA: http://localhost:3004
24+
- http://localhost:3001 - Next.js
25+
- http://localhost:3002 - React SPA
26+
- http://localhost:3003 - Remix
27+
- http://localhost:3006 - React Router v6
28+
- http://localhost:3007 - React Router v7
2829

2930
## Testing
3031

packages/docs/content/docs/adapters.mdx

+2
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ export function ReactRouter() {
126126
}
127127
```
128128

129+
**Note**: If you are using react-router v7, please import the `NuqsAdapter{:ts}` from `nuqs/adapters/react-router/v7`
130+
129131
## Testing
130132

131133
<Callout>
+1-31
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,5 @@
11
{
22
"name": "e2e-react-router",
3-
"private": true,
43
"version": "0.0.0",
5-
"type": "module",
6-
"scripts": {
7-
"dev": "vite --port 4000",
8-
"build": "tsc -b && vite build",
9-
"preview": "vite preview",
10-
"test": "pnpm run '/^test:/'",
11-
"test:unit": "vitest",
12-
"test:e2e": "echo 'todo: Implement e2e tests'"
13-
},
14-
"dependencies": {
15-
"nuqs": "workspace:*",
16-
"react": "catalog:react19",
17-
"react-dom": "catalog:react19",
18-
"react-router-dom": "^6.28.0"
19-
},
20-
"devDependencies": {
21-
"@testing-library/dom": "^10.4.0",
22-
"@testing-library/jest-dom": "^6.6.3",
23-
"@testing-library/react": "^16.0.1",
24-
"@testing-library/user-event": "^14.5.2",
25-
"@types/node": "^22.9.0",
26-
"@types/react": "catalog:react19",
27-
"@types/react-dom": "catalog:react19",
28-
"@vitejs/plugin-react": "^4.3.3",
29-
"globals": "^15.12.0",
30-
"jsdom": "^25.0.1",
31-
"typescript": "^5.6.3",
32-
"vite": "^5.4.11",
33-
"vitest": "^2.1.5"
34-
}
4+
"private": true
355
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "e2e-react-router-v6",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite --port 3006",
8+
"build": "tsc -b && vite build",
9+
"preview": "vite preview",
10+
"test": "pnpm run '/^test:/'",
11+
"test:unit": "vitest",
12+
"test:e2e": "echo 'todo: Implement e2e tests'"
13+
},
14+
"dependencies": {
15+
"nuqs": "workspace:*",
16+
"react": "catalog:react19",
17+
"react-dom": "catalog:react19",
18+
"react-router-dom": "^6.28.0"
19+
},
20+
"devDependencies": {
21+
"@testing-library/dom": "^10.4.0",
22+
"@testing-library/jest-dom": "^6.6.3",
23+
"@testing-library/react": "^16.0.1",
24+
"@testing-library/user-event": "^14.5.2",
25+
"@types/node": "^22.9.0",
26+
"@types/react": "catalog:react19",
27+
"@types/react-dom": "catalog:react19",
28+
"@vitejs/plugin-react": "^4.3.3",
29+
"globals": "^15.12.0",
30+
"jsdom": "^25.0.1",
31+
"typescript": "^5.6.3",
32+
"vite": "^5.4.11",
33+
"vitest": "^2.1.5"
34+
}
35+
}
File renamed without changes.

packages/e2e/react-router/src/react-router.tsx packages/e2e/react-router/v6/src/react-router.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NuqsAdapter } from 'nuqs/adapters/react-router'
1+
import { NuqsAdapter } from 'nuqs/adapters/react-router/v6'
22
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
33
import App from './App'
44

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.DS_Store
2+
/node_modules/
3+
4+
# React Router
5+
/.react-router/
6+
/build/
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Welcome to React Router!
2+
3+
A modern, production-ready template for building full-stack React applications using React Router.
4+
5+
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/remix-run/react-router-templates/tree/main/default)
6+
7+
## Features
8+
9+
- 🚀 Server-side rendering
10+
- ⚡️ Hot Module Replacement (HMR)
11+
- 📦 Asset bundling and optimization
12+
- 🔄 Data loading and mutations
13+
- 🔒 TypeScript by default
14+
- 🎉 TailwindCSS for styling
15+
- 📖 [React Router docs](https://reactrouter.com/)
16+
17+
## Getting Started
18+
19+
### Installation
20+
21+
Install the dependencies:
22+
23+
```bash
24+
npm install
25+
```
26+
27+
### Development
28+
29+
Start the development server with HMR:
30+
31+
```bash
32+
npm run dev
33+
```
34+
35+
Your application will be available at `http://localhost:5173`.
36+
37+
## Building for Production
38+
39+
Create a production build:
40+
41+
```bash
42+
npm run build
43+
```
44+
45+
## Deployment
46+
47+
### Docker Deployment
48+
49+
This template includes three Dockerfiles optimized for different package managers:
50+
51+
- `Dockerfile` - for npm
52+
- `Dockerfile.pnpm` - for pnpm
53+
- `Dockerfile.bun` - for bun
54+
55+
To build and run using Docker:
56+
57+
```bash
58+
# For npm
59+
docker build -t my-app .
60+
61+
# For pnpm
62+
docker build -f Dockerfile.pnpm -t my-app .
63+
64+
# For bun
65+
docker build -f Dockerfile.bun -t my-app .
66+
67+
# Run the container
68+
docker run -p 3000:3000 my-app
69+
```
70+
71+
The containerized application can be deployed to any platform that supports Docker, including:
72+
73+
- AWS ECS
74+
- Google Cloud Run
75+
- Azure Container Apps
76+
- Digital Ocean App Platform
77+
- Fly.io
78+
- Railway
79+
80+
### DIY Deployment
81+
82+
If you're familiar with deploying Node applications, the built-in app server is production-ready.
83+
84+
Make sure to deploy the output of `npm run build`
85+
86+
```
87+
├── package.json
88+
├── package-lock.json (or pnpm-lock.yaml, or bun.lockb)
89+
├── build/
90+
│ ├── client/ # Static assets
91+
│ └── server/ # Server-side code
92+
```
93+
94+
## Styling
95+
96+
This template comes with [Tailwind CSS](https://tailwindcss.com/) already configured for a simple default starting experience. You can use whatever CSS framework you prefer.
97+
98+
---
99+
100+
Built with ❤️ using React Router.
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { NuqsAdapter } from 'nuqs/adapters/react-router/v7'
2+
import {
3+
isRouteErrorResponse,
4+
Links,
5+
Meta,
6+
Outlet,
7+
Scripts,
8+
ScrollRestoration
9+
} from 'react-router'
10+
11+
import type { Route } from './+types/root'
12+
13+
export function Layout({ children }: { children: React.ReactNode }) {
14+
return (
15+
<html lang="en">
16+
<head>
17+
<meta charSet="utf-8" />
18+
<meta name="viewport" content="width=device-width, initial-scale=1" />
19+
<Meta />
20+
<Links />
21+
</head>
22+
<body>
23+
{children}
24+
<ScrollRestoration />
25+
<Scripts />
26+
</body>
27+
</html>
28+
)
29+
}
30+
31+
export default function App() {
32+
return (
33+
<NuqsAdapter>
34+
<Outlet />
35+
</NuqsAdapter>
36+
)
37+
}
38+
39+
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
40+
let message = 'Oops!'
41+
let details = 'An unexpected error occurred.'
42+
let stack: string | undefined
43+
44+
if (isRouteErrorResponse(error)) {
45+
message = error.status === 404 ? '404' : 'Error'
46+
details =
47+
error.status === 404
48+
? 'The requested page could not be found.'
49+
: error.statusText || details
50+
} else if (import.meta.env.DEV && error && error instanceof Error) {
51+
details = error.message
52+
stack = error.stack
53+
}
54+
55+
return (
56+
<main className="pt-16 p-4 container mx-auto">
57+
<h1>{message}</h1>
58+
<p>{details}</p>
59+
{stack && (
60+
<pre className="w-full p-4 overflow-x-auto">
61+
<code>{stack}</code>
62+
</pre>
63+
)}
64+
</main>
65+
)
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { type RouteConfig, index } from "@react-router/dev/routes";
2+
3+
export default [index("routes/home.tsx")] satisfies RouteConfig;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { Route } from './+types/home'
2+
3+
export function meta({}: Route.MetaArgs) {
4+
return [
5+
{ title: 'New React Router App' },
6+
{ name: 'description', content: 'Welcome to React Router!' }
7+
]
8+
}
9+
10+
export default function Home() {
11+
return <p>Hello, RRv7</p>
12+
}
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "e2e-react-router-v7",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"build": "react-router build",
7+
"dev": "react-router dev --port 3007",
8+
"start": "react-router-serve ./build/server/index.js",
9+
"typecheck": "react-router typegen && tsc"
10+
},
11+
"dependencies": {
12+
"@react-router/node": "^7.0.2",
13+
"@react-router/serve": "^7.0.2",
14+
"isbot": "^5.1.17",
15+
"nuqs": "workspace:*",
16+
"react": "catalog:react19",
17+
"react-dom": "catalog:react19",
18+
"react-router": "^7.0.2"
19+
},
20+
"devDependencies": {
21+
"@react-router/dev": "^7.0.2",
22+
"@types/node": "^20",
23+
"@types/react": "catalog:react19",
24+
"@types/react-dom": "catalog:react19",
25+
"typescript": "^5.6.3",
26+
"vite": "^5.4.11",
27+
"vite-tsconfig-paths": "^5.1.2"
28+
}
29+
}
16.6 KB
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import type { Config } from "@react-router/dev/config";
2+
3+
export default {
4+
// Config options...
5+
// Server-side render by default, to enable SPA mode set this to `false`
6+
ssr: true,
7+
} satisfies Config;

0 commit comments

Comments
 (0)