Skip to content

Commit

Permalink
feat: Added react-router v7 support (#785)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
teukuamru and franky47 authored Dec 10, 2024
1 parent 0068f4b commit 650bd65
Show file tree
Hide file tree
Showing 43 changed files with 712 additions and 50 deletions.
16 changes: 11 additions & 5 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,15 @@ jobs:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

e2e-react-router:
name: E2E (react-router)
name: E2E (react-router ${{ matrix.react-router-version }})
runs-on: ubuntu-24.04
needs: [ci-core]
strategy:
fail-fast: false
matrix:
react-router-version:
- 'v6'
- 'v7'
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2
Expand All @@ -168,7 +174,7 @@ jobs:
- name: Install dependencies
run: pnpm install
- name: Run tests
run: pnpm run test ${{ github.event_name == 'workflow_dispatch' && '--force' || '' }} --filter e2e-react-router
run: pnpm run test ${{ github.event_name == 'workflow_dispatch' && '--force' || '' }} --filter e2e-react-router-${{ matrix.react-router-version }}
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
Expand All @@ -177,14 +183,14 @@ jobs:
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882
if: failure()
with:
path: packages/e2e/react-router/cypress/screenshots
name: ci-react-router
path: packages/e2e/react-router/${{ matrix.react-router-version }}/cypress/screenshots
name: ci-react-router-${{ matrix.react-router-version }}
- uses: 47ng/actions-slack-notify@main
name: Notify on Slack
if: always()
with:
status: ${{ job.status }}
jobName: react-router
jobName: react-router-${{ matrix.react-router-version }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

Expand Down
9 changes: 5 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ When running `next dev`, this will:
- Build the library and watch for changes using [`tsup`](https://tsup.egoist.dev/)
- Start the docs app, which will be available at <http://localhost:3000>.
- Start the end-to-end test benches:
- Next.js: http://localhost:3001
- Remix: http://localhost:3002
- React Router: http://localhost:3003
- React SPA: http://localhost:3004
- http://localhost:3001 - Next.js
- http://localhost:3002 - React SPA
- http://localhost:3003 - Remix
- http://localhost:3006 - React Router v6
- http://localhost:3007 - React Router v7

## Testing

Expand Down
2 changes: 2 additions & 0 deletions packages/docs/content/docs/adapters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ export function ReactRouter() {
}
```

**Note**: If you are using react-router v7, please import the `NuqsAdapter{:ts}` from `nuqs/adapters/react-router/v7`

## Testing

<Callout>
Expand Down
32 changes: 1 addition & 31 deletions packages/e2e/react-router/package.json
Original file line number Diff line number Diff line change
@@ -1,35 +1,5 @@
{
"name": "e2e-react-router",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --port 4000",
"build": "tsc -b && vite build",
"preview": "vite preview",
"test": "pnpm run '/^test:/'",
"test:unit": "vitest",
"test:e2e": "echo 'todo: Implement e2e tests'"
},
"dependencies": {
"nuqs": "workspace:*",
"react": "catalog:react19",
"react-dom": "catalog:react19",
"react-router-dom": "^6.28.0"
},
"devDependencies": {
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.0.1",
"@testing-library/user-event": "^14.5.2",
"@types/node": "^22.9.0",
"@types/react": "catalog:react19",
"@types/react-dom": "catalog:react19",
"@vitejs/plugin-react": "^4.3.3",
"globals": "^15.12.0",
"jsdom": "^25.0.1",
"typescript": "^5.6.3",
"vite": "^5.4.11",
"vitest": "^2.1.5"
}
"private": true
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
35 changes: 35 additions & 0 deletions packages/e2e/react-router/v6/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "e2e-react-router-v6",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --port 3006",
"build": "tsc -b && vite build",
"preview": "vite preview",
"test": "pnpm run '/^test:/'",
"test:unit": "vitest",
"test:e2e": "echo 'todo: Implement e2e tests'"
},
"dependencies": {
"nuqs": "workspace:*",
"react": "catalog:react19",
"react-dom": "catalog:react19",
"react-router-dom": "^6.28.0"
},
"devDependencies": {
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.0.1",
"@testing-library/user-event": "^14.5.2",
"@types/node": "^22.9.0",
"@types/react": "catalog:react19",
"@types/react-dom": "catalog:react19",
"@vitejs/plugin-react": "^4.3.3",
"globals": "^15.12.0",
"jsdom": "^25.0.1",
"typescript": "^5.6.3",
"vite": "^5.4.11",
"vitest": "^2.1.5"
}
}
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NuqsAdapter } from 'nuqs/adapters/react-router'
import { NuqsAdapter } from 'nuqs/adapters/react-router/v6'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import App from './App'

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions packages/e2e/react-router/v7/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.DS_Store
/node_modules/

# React Router
/.react-router/
/build/
100 changes: 100 additions & 0 deletions packages/e2e/react-router/v7/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Welcome to React Router!

A modern, production-ready template for building full-stack React applications using React Router.

[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/remix-run/react-router-templates/tree/main/default)

## Features

- 🚀 Server-side rendering
- ⚡️ Hot Module Replacement (HMR)
- 📦 Asset bundling and optimization
- 🔄 Data loading and mutations
- 🔒 TypeScript by default
- 🎉 TailwindCSS for styling
- 📖 [React Router docs](https://reactrouter.com/)

## Getting Started

### Installation

Install the dependencies:

```bash
npm install
```

### Development

Start the development server with HMR:

```bash
npm run dev
```

Your application will be available at `http://localhost:5173`.

## Building for Production

Create a production build:

```bash
npm run build
```

## Deployment

### Docker Deployment

This template includes three Dockerfiles optimized for different package managers:

- `Dockerfile` - for npm
- `Dockerfile.pnpm` - for pnpm
- `Dockerfile.bun` - for bun

To build and run using Docker:

```bash
# For npm
docker build -t my-app .

# For pnpm
docker build -f Dockerfile.pnpm -t my-app .

# For bun
docker build -f Dockerfile.bun -t my-app .

# Run the container
docker run -p 3000:3000 my-app
```

The containerized application can be deployed to any platform that supports Docker, including:

- AWS ECS
- Google Cloud Run
- Azure Container Apps
- Digital Ocean App Platform
- Fly.io
- Railway

### DIY Deployment

If you're familiar with deploying Node applications, the built-in app server is production-ready.

Make sure to deploy the output of `npm run build`

```
├── package.json
├── package-lock.json (or pnpm-lock.yaml, or bun.lockb)
├── build/
│ ├── client/ # Static assets
│ └── server/ # Server-side code
```

## Styling

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.

---

Built with ❤️ using React Router.
66 changes: 66 additions & 0 deletions packages/e2e/react-router/v7/app/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { NuqsAdapter } from 'nuqs/adapters/react-router/v7'
import {
isRouteErrorResponse,
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration
} from 'react-router'

import type { Route } from './+types/root'

export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
</body>
</html>
)
}

export default function App() {
return (
<NuqsAdapter>
<Outlet />
</NuqsAdapter>
)
}

export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
let message = 'Oops!'
let details = 'An unexpected error occurred.'
let stack: string | undefined

if (isRouteErrorResponse(error)) {
message = error.status === 404 ? '404' : 'Error'
details =
error.status === 404
? 'The requested page could not be found.'
: error.statusText || details
} else if (import.meta.env.DEV && error && error instanceof Error) {
details = error.message
stack = error.stack
}

return (
<main className="pt-16 p-4 container mx-auto">
<h1>{message}</h1>
<p>{details}</p>
{stack && (
<pre className="w-full p-4 overflow-x-auto">
<code>{stack}</code>
</pre>
)}
</main>
)
}
3 changes: 3 additions & 0 deletions packages/e2e/react-router/v7/app/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { type RouteConfig, index } from "@react-router/dev/routes";

export default [index("routes/home.tsx")] satisfies RouteConfig;
12 changes: 12 additions & 0 deletions packages/e2e/react-router/v7/app/routes/home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { Route } from './+types/home'

export function meta({}: Route.MetaArgs) {
return [
{ title: 'New React Router App' },
{ name: 'description', content: 'Welcome to React Router!' }
]
}

export default function Home() {
return <p>Hello, RRv7</p>
}
29 changes: 29 additions & 0 deletions packages/e2e/react-router/v7/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "e2e-react-router-v7",
"private": true,
"type": "module",
"scripts": {
"build": "react-router build",
"dev": "react-router dev --port 3007",
"start": "react-router-serve ./build/server/index.js",
"typecheck": "react-router typegen && tsc"
},
"dependencies": {
"@react-router/node": "^7.0.2",
"@react-router/serve": "^7.0.2",
"isbot": "^5.1.17",
"nuqs": "workspace:*",
"react": "catalog:react19",
"react-dom": "catalog:react19",
"react-router": "^7.0.2"
},
"devDependencies": {
"@react-router/dev": "^7.0.2",
"@types/node": "^20",
"@types/react": "catalog:react19",
"@types/react-dom": "catalog:react19",
"typescript": "^5.6.3",
"vite": "^5.4.11",
"vite-tsconfig-paths": "^5.1.2"
}
}
Binary file added packages/e2e/react-router/v7/public/favicon.ico
Binary file not shown.
7 changes: 7 additions & 0 deletions packages/e2e/react-router/v7/react-router.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Config } from "@react-router/dev/config";

export default {
// Config options...
// Server-side render by default, to enable SPA mode set this to `false`
ssr: true,
} satisfies Config;
Loading

0 comments on commit 650bd65

Please sign in to comment.