Skip to content

Commit ed4e0bc

Browse files
Add minimal template (#54)
* Add minimal template * Remove autoprefixer * Upgrade to vite 6 * Add isbot, remove cross-env * Add favicon back * Add ErrorBoundsary to root * add simple tailwindcss setup * add tests * Add link to the docs * Minor alignments with default * remove package-lock.json from .gitignore --------- Co-authored-by: Brooks Lybrand <[email protected]>
1 parent 4c5bce7 commit ed4e0bc

15 files changed

+907
-5
lines changed

.tests/test.minimal.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { expect, Page } from "@playwright/test";
2+
import getPort from "get-port";
3+
4+
import { matchLine, testTemplate, urlRegex } from "./utils";
5+
6+
const test = testTemplate("minimal");
7+
8+
test("typecheck", async ({ $ }) => {
9+
await $(`pnpm typecheck`);
10+
});
11+
12+
test("dev", async ({ page, $ }) => {
13+
const port = await getPort();
14+
const dev = $(`pnpm dev --port ${port}`);
15+
16+
const url = await matchLine(dev.stdout, urlRegex.viteDev);
17+
await workflow({ page, url });
18+
expect(dev.buffer.stderr).toBe("");
19+
});
20+
21+
test("build + start", async ({ page, $ }) => {
22+
await $(`pnpm build`);
23+
24+
const port = await getPort();
25+
const start = $(`pnpm start`, { env: { PORT: String(port) } });
26+
27+
const url = await matchLine(start.stdout, urlRegex.reactRouterServe);
28+
await workflow({ page, url });
29+
expect(start.buffer.stderr).toBe("");
30+
});
31+
32+
async function workflow({ page, url }: { page: Page; url: string }) {
33+
await page.goto(url);
34+
await page.getByRole("heading", { name: "Hello, React Router" }).waitFor();
35+
await page.getByRole("link", { name: "React Router Docs" }).waitFor();
36+
expect(page.errors).toStrictEqual([]);
37+
}

minimal/.gitignore

Lines changed: 6 additions & 0 deletions
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/

minimal/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Welcome to React Router!
2+
3+
A minimal template for experimenting with React Router v7.
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/minimal)
6+
7+
> ![NOTE]
8+
> This template should not be used for production apps and is intended more for experimentation and demo applications. Please see the [default](https://github.com/remix-run/react-router-templates/tree/main/default) template for a more full-featured template.
9+
10+
## Getting Started
11+
12+
### Installation
13+
14+
Install the dependencies:
15+
16+
```bash
17+
npm install
18+
```
19+
20+
### Development
21+
22+
Start the development server with HMR:
23+
24+
```bash
25+
npm run dev
26+
```
27+
28+
Your application will be available at `http://localhost:5173`.
29+
30+
---
31+
32+
Built with ❤️ using React Router.

minimal/app/app.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;

minimal/app/root.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import {
2+
isRouteErrorResponse,
3+
Links,
4+
Meta,
5+
Outlet,
6+
Scripts,
7+
ScrollRestoration,
8+
} from "react-router";
9+
10+
import type { Route } from "./+types/root";
11+
import "./app.css";
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 <Outlet />;
33+
}
34+
35+
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
36+
let message = "Oops!";
37+
let details = "An unexpected error occurred.";
38+
let stack: string | undefined;
39+
40+
if (isRouteErrorResponse(error)) {
41+
message = error.status === 404 ? "404" : "Error";
42+
details =
43+
error.status === 404
44+
? "The requested page could not be found."
45+
: error.statusText || details;
46+
} else if (import.meta.env.DEV && error && error instanceof Error) {
47+
details = error.message;
48+
stack = error.stack;
49+
}
50+
51+
return (
52+
<main className="pt-16 p-4 container mx-auto">
53+
<h1>{message}</h1>
54+
<p>{details}</p>
55+
{stack && (
56+
<pre className="w-full p-4 overflow-x-auto">
57+
<code>{stack}</code>
58+
</pre>
59+
)}
60+
</main>
61+
);
62+
}

minimal/app/routes.ts

Lines changed: 3 additions & 0 deletions
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;

minimal/app/routes/home.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { Route } from "./+types/home";
2+
3+
export function loader() {
4+
return { name: "React Router" };
5+
}
6+
7+
export default function Home({ loaderData }: Route.ComponentProps) {
8+
return (
9+
<div className="text-center p-4">
10+
<h1 className="text-2xl">Hello, {loaderData.name}</h1>
11+
<a
12+
className="block mt-2 text-blue-500 underline hover:text-blue-600"
13+
href="https://reactrouter.com/docs"
14+
>
15+
React Router Docs
16+
</a>
17+
</div>
18+
);
19+
}

minimal/package.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"private": true,
3+
"type": "module",
4+
"scripts": {
5+
"build": "react-router build",
6+
"dev": "react-router dev",
7+
"start": "react-router-serve ./build/server/index.js",
8+
"typecheck": "react-router typegen && tsc"
9+
},
10+
"dependencies": {
11+
"@react-router/node": "*",
12+
"@react-router/serve": "*",
13+
"isbot": "^5.1.17",
14+
"react": "^19.0.0",
15+
"react-dom": "^19.0.0",
16+
"react-router": "*"
17+
},
18+
"devDependencies": {
19+
"@react-router/dev": "*",
20+
"@types/node": "^20",
21+
"@types/react": "^19.0.1",
22+
"@types/react-dom": "^19.0.1",
23+
"tailwindcss": "^3.4.17",
24+
"typescript": "^5.7.2",
25+
"vite": "^6.0.11",
26+
"vite-tsconfig-paths": "^5.1.4"
27+
}
28+
}

minimal/public/favicon.ico

14.7 KB
Binary file not shown.

minimal/react-router.config.ts

Lines changed: 7 additions & 0 deletions
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;

minimal/tailwind.config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/** @type {import('tailwindcss').Config} */
2+
export default {
3+
content: ["./app/**/*.{ts,tsx}"],
4+
theme: {
5+
extend: {},
6+
},
7+
plugins: [],
8+
};

minimal/tsconfig.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"include": [
3+
"**/*",
4+
"**/.server/**/*",
5+
"**/.client/**/*",
6+
".react-router/types/**/*"
7+
],
8+
"compilerOptions": {
9+
"lib": ["DOM", "DOM.Iterable", "ES2022"],
10+
"types": ["node", "vite/client"],
11+
"target": "ES2022",
12+
"module": "ES2022",
13+
"moduleResolution": "bundler",
14+
"jsx": "react-jsx",
15+
"rootDirs": [".", "./.react-router/types"],
16+
"baseUrl": ".",
17+
"paths": {
18+
"~/*": ["./app/*"]
19+
},
20+
"esModuleInterop": true,
21+
"verbatimModuleSyntax": true,
22+
"noEmit": true,
23+
"resolveJsonModule": true,
24+
"skipLibCheck": true,
25+
"strict": true
26+
}
27+
}

minimal/vite.config.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { reactRouter } from "@react-router/dev/vite";
2+
import tailwindcss from "tailwindcss";
3+
import { defineConfig } from "vite";
4+
import tsconfigPaths from "vite-tsconfig-paths";
5+
6+
export default defineConfig({
7+
css: {
8+
postcss: {
9+
plugins: [tailwindcss],
10+
},
11+
},
12+
plugins: [reactRouter(), tsconfigPaths()],
13+
});

0 commit comments

Comments
 (0)