Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added react-router v7 support #785

Merged
merged 14 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
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"
}
}
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
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
Loading