Working react-router for default templates (default, tailwind, shadcn); Update Github Action for router='none' 5ac09fcc
Maximilian Leodolter · 2025-08-07 14:28 18 file(s) · +230 −7
.github/workflows/test-cli-options.yml +25 −0
18 18
          - template: "default"
19 19
            rpc: true
20 20
            tanstackQuery: false
21 +
            router: "none"
21 22
            linter: "eslint"
22 23
            test_name: "Default + RPC + No TanStack Query + ESLint"
23 24
          - template: "default"
24 25
            rpc: true
25 26
            tanstackQuery: false
27 +
            router: "none"
26 28
            linter: "biome"
27 29
            test_name: "Default + RPC + No TanStack Query + Biome"
28 30
          - template: "default"
29 31
            rpc: false
30 32
            tanstackQuery: false
33 +
            router: "none"
31 34
            linter: "eslint"
32 35
            test_name: "Default + No RPC + No TanStack Query + ESLint"
33 36
          - template: "default"
34 37
            rpc: false
35 38
            tanstackQuery: false
39 +
            router: "none"
36 40
            linter: "biome"
37 41
            test_name: "Default + No RPC + No TanStack Query + Biome"
38 42
          - template: "default"
39 43
            rpc: true
40 44
            tanstackQuery: true
45 +
            router: "none"
41 46
            linter: "eslint"
42 47
            test_name: "Default + RPC + TanStack Query + ESLint"
43 48
          - template: "default"
44 49
            rpc: true
45 50
            tanstackQuery: true
51 +
            router: "none"
46 52
            linter: "biome"
47 53
            test_name: "Default + RPC + TanStack Query + Biome"
48 54
          - template: "default"
49 55
            rpc: false
50 56
            tanstackQuery: true
57 +
            router: "none"
51 58
            linter: "eslint"
52 59
            test_name: "Default + No RPC + TanStack Query + ESLint"
53 60
          - template: "default"
54 61
            rpc: false
55 62
            tanstackQuery: true
63 +
            router: "none"
56 64
            linter: "biome"
57 65
            test_name: "Default + No RPC + TanStack Query + Biome"
58 66
          
60 68
          - template: "tailwind"
61 69
            rpc: true
62 70
            tanstackQuery: false
71 +
            router: "none"
63 72
            linter: "eslint"
64 73
            test_name: "Tailwind + RPC + No TanStack Query + ESLint"
65 74
          - template: "tailwind"
66 75
            rpc: true
67 76
            tanstackQuery: false
77 +
            router: "none"
68 78
            linter: "biome"
69 79
            test_name: "Tailwind + RPC + No TanStack Query + Biome"
70 80
          - template: "tailwind"
71 81
            rpc: false
72 82
            tanstackQuery: false
83 +
            router: "none"
73 84
            linter: "eslint"
74 85
            test_name: "Tailwind + No RPC + No TanStack Query + ESLint"
75 86
          - template: "tailwind"
76 87
            rpc: false
77 88
            tanstackQuery: false
89 +
            router: "none"
78 90
            linter: "biome"
79 91
            test_name: "Tailwind + No RPC + No TanStack Query + Biome"
80 92
          - template: "tailwind"
81 93
            rpc: true
82 94
            tanstackQuery: true
95 +
            router: "none"
83 96
            linter: "eslint"
84 97
            test_name: "Tailwind + RPC + TanStack Query + ESLint"
85 98
          - template: "tailwind"
86 99
            rpc: true
87 100
            tanstackQuery: true
101 +
            router: "none"
88 102
            linter: "biome"
89 103
            test_name: "Tailwind + RPC + TanStack Query + Biome"
90 104
          - template: "tailwind"
91 105
            rpc: false
92 106
            tanstackQuery: true
107 +
            router: "none"
93 108
            linter: "eslint"
94 109
            test_name: "Tailwind + No RPC + TanStack Query + ESLint"
95 110
          - template: "tailwind"
96 111
            rpc: false
97 112
            tanstackQuery: true
113 +
            router: "none"
98 114
            linter: "biome"
99 115
            test_name: "Tailwind + No RPC + TanStack Query + Biome"
100 116
102 118
          - template: "shadcn"
103 119
            rpc: true
104 120
            tanstackQuery: false
121 +
            router: "none"
105 122
            linter: "eslint"
106 123
            test_name: "Shadcn + RPC + No TanStack Query + ESLint"
107 124
          - template: "shadcn"
108 125
            rpc: true
109 126
            tanstackQuery: false
127 +
            router: "none"
110 128
            linter: "biome"
111 129
            test_name: "Shadcn + RPC + No TanStack Query + Biome"
112 130
          - template: "shadcn"
113 131
            rpc: false
114 132
            tanstackQuery: false
133 +
            router: "none"
134 +
            router: "none"
115 135
            linter: "eslint"
116 136
            test_name: "Shadcn + No RPC + No TanStack Query + ESLint"
117 137
          - template: "shadcn"
118 138
            rpc: false
119 139
            tanstackQuery: false
140 +
            router: "none"
120 141
            linter: "biome"
121 142
            test_name: "Shadcn + No RPC + No TanStack Query + Biome"
122 143
          - template: "shadcn"
123 144
            rpc: true
124 145
            tanstackQuery: true
146 +
            router: "none"
125 147
            linter: "eslint"
126 148
            test_name: "Shadcn + RPC + TanStack Query + ESLint"
127 149
          - template: "shadcn"
128 150
            rpc: true
129 151
            tanstackQuery: true
152 +
            router: "none"
130 153
            linter: "biome"
131 154
            test_name: "Shadcn + RPC + TanStack Query + Biome"
132 155
          - template: "shadcn"
133 156
            rpc: false
134 157
            tanstackQuery: true
158 +
            router: "none"
135 159
            linter: "eslint"
136 160
            test_name: "Shadcn + No RPC + TanStack Query + ESLint"
137 161
          - template: "shadcn"
138 162
            rpc: false
139 163
            tanstackQuery: true
164 +
            router: "none"
140 165
            linter: "biome"
141 166
            test_name: "Shadcn + No RPC + TanStack Query + Biome"
142 167
src/installers/react-router.ts +26 −6
26 26
			projectName,
27 27
		});
28 28
29 -
		const selectedTemplate = nameGenerator("App.tsx", {
30 -
			rpc,
31 -
			shadcn,
32 -
			tailwind,
33 -
			tanstackQuery,
29 +
		const appTsxTemplate = nameGenerator("App.tsx", {
34 30
			reactRouter: true,
35 31
		});
36 32
39 35
			"client",
40 36
			"src",
41 37
			"App.tsx",
42 -
			selectedTemplate,
38 +
			appTsxTemplate,
43 39
		);
44 40
		const appTsxTarget = path.join(projectPath, "client", "src", "App.tsx");
45 41
		fs.copySync(appTsxSrc, appTsxTarget);
42 +
43 +
		const homeTsxTemplate = nameGenerator("Home.tsx", {
44 +
			rpc,
45 +
			shadcn,
46 +
			tailwind,
47 +
			tanstackQuery,
48 +
		});
49 +
50 +
		const homeTsxSrc = path.join(
51 +
			EXTRAS_DIR,
52 +
			"client",
53 +
			"src",
54 +
			"components",
55 +
			"Home.tsx",
56 +
			homeTsxTemplate,
57 +
		);
58 +
		const homeTsxTarget = path.join(
59 +
			projectPath,
60 +
			"client",
61 +
			"src",
62 +
			"components",
63 +
			"Home.tsx",
64 +
		);
65 +
		fs.copySync(homeTsxSrc, homeTsxTarget);
46 66
47 67
		spinner.success("React Router setup completed");
48 68
		return true;
src/lib/install-packages.ts +2 −1
3 3
import path from "node:path";
4 4
import { tanstackQueryInstaller } from "@/installers/tanstack-query";
5 5
import { rpcInstaller } from "@/installers/rpc";
6 +
import { reactRouterInstaller } from "@/installers/react-router";
6 7
7 8
export async function installPackages(
8 9
	options: Required<ProjectOptions>,
22 23
	if (router !== "none") {
23 24
		switch (router) {
24 25
			case "reactrouter": {
25 -
				console.log("Instlling React Router");
26 +
				await reactRouterInstaller(options);
26 27
				break;
27 28
			}
28 29
			case "tanstackrouter": {
src/templates/extras/client/src/App.tsx/App-with-reactrouter-rpc-shadcn-tailwind-tanstackquery.tsx → src/templates/extras/client/src/components/Home.tsx/Home-with-rpc-shadcn-tailwind-tanstackquery.tsx +0 −0

Binary file — no preview.

src/templates/extras/client/src/App.tsx/App-with-reactrouter-rpc-shadcn-tailwind.tsx → src/templates/extras/client/src/components/Home.tsx/Home-with-rpc-shadcn-tailwind.tsx +0 −0

Binary file — no preview.

src/templates/extras/client/src/App.tsx/App-with-reactrouter-rpc-tailwind-tanstackquery.tsx → src/templates/extras/client/src/components/Home.tsx/Home-with-rpc-tailwind-tanstackquery.tsx +0 −0

Binary file — no preview.

src/templates/extras/client/src/App.tsx/App-with-reactrouter-rpc-tailwind.tsx → src/templates/extras/client/src/components/Home.tsx/Home-with-rpc-tailwind.tsx +0 −0

Binary file — no preview.

src/templates/extras/client/src/App.tsx/App-with-reactrouter-rpc-tanstackquery.tsx → src/templates/extras/client/src/components/Home.tsx/Home-with-rpc-tanstackquery.tsx +0 −0

Binary file — no preview.

src/templates/extras/client/src/App.tsx/App-with-reactrouter-rpc.tsx → src/templates/extras/client/src/components/Home.tsx/Home-with-rpc.tsx +0 −0

Binary file — no preview.

src/templates/extras/client/src/App.tsx/App-with-reactrouter-shadcn-tailwind-tanstackquery.tsx → src/templates/extras/client/src/components/Home.tsx/Home-with-shadcn-tailwind-tanstackquery.tsx +0 −0

Binary file — no preview.

src/templates/extras/client/src/App.tsx/App-with-reactrouter-shadcn-tailwind.tsx (deleted) +0 −0

Binary file — no preview.

src/templates/extras/client/src/App.tsx/App-with-reactrouter-tailwind-tanstackquery.tsx → src/templates/extras/client/src/components/Home.tsx/Home-with-tailwind-tanstackquery.tsx +0 −0

Binary file — no preview.

src/templates/extras/client/src/App.tsx/App-with-reactrouter-tailwind.tsx (deleted) +0 −0

Binary file — no preview.

src/templates/extras/client/src/App.tsx/App-with-reactrouter-tanstackquery.tsx → src/templates/extras/client/src/components/Home.tsx/Home-with-tanstackquery.tsx +0 −0

Binary file — no preview.

src/templates/extras/client/src/App.tsx/App-with-reactrouter.tsx +14 −0
1 +
import { BrowserRouter, Routes, Route } from "react-router";
2 +
import Home from "./components/Home";
3 +
4 +
function App() {
5 +
	return (
6 +
		<BrowserRouter>
7 +
			<Routes>
8 +
				<Route path="/" element={<Home />} />
9 +
			</Routes>
10 +
		</BrowserRouter>
11 +
	);
12 +
}
13 +
14 +
export default App;
src/templates/extras/client/src/components/Home.tsx/Home-with-shadcn-tailwind.tsx (added) +53 −0
1 +
import { useState } from "react";
2 +
import beaver from "@/assets/beaver.svg";
3 +
import { ApiResponse } from "shared";
4 +
import { Button } from "@/components/ui/button";
5 +
6 +
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000";
7 +
8 +
function Home() {
9 +
	const [data, setData] = useState<ApiResponse | undefined>();
10 +
11 +
	async function sendRequest() {
12 +
		try {
13 +
			const req = await fetch(`${SERVER_URL}/hello`);
14 +
			const res: ApiResponse = await req.json();
15 +
			setData(res);
16 +
		} catch (error) {
17 +
			console.log(error);
18 +
		}
19 +
	}
20 +
21 +
	return (
22 +
		<div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen">
23 +
			<a href="https://github.com/stevedylandev/bhvr" target="_blank">
24 +
				<img
25 +
					src={beaver}
26 +
					className="w-16 h-16 cursor-pointer"
27 +
					alt="beaver logo"
28 +
				/>
29 +
			</a>
30 +
			<h1 className="text-5xl font-black">bhvr</h1>
31 +
			<h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2>
32 +
			<p>A typesafe fullstack monorepo</p>
33 +
			<div className="flex items-center gap-4">
34 +
				<Button onClick={sendRequest}>Call API</Button>
35 +
				<Button variant="secondary" asChild>
36 +
					<a target="_blank" href="https://bhvr.dev">
37 +
						Docs
38 +
					</a>
39 +
				</Button>
40 +
			</div>
41 +
			{data && (
42 +
				<pre className="bg-gray-100 p-4 rounded-md">
43 +
					<code>
44 +
						Message: {data.message} <br />
45 +
						Success: {data.success.toString()}
46 +
					</code>
47 +
				</pre>
48 +
			)}
49 +
		</div>
50 +
	);
51 +
}
52 +
53 +
export default Home;
src/templates/extras/client/src/components/Home.tsx/Home-with-tailwind.tsx (added) +59 −0
1 +
import { useState } from "react";
2 +
import beaver from "../assets/beaver.svg";
3 +
import { ApiResponse } from "shared";
4 +
5 +
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000";
6 +
7 +
function Home() {
8 +
	const [data, setData] = useState<ApiResponse | undefined>();
9 +
10 +
	async function sendRequest() {
11 +
		try {
12 +
			const req = await fetch(`${SERVER_URL}/hello`);
13 +
			const res: ApiResponse = await req.json();
14 +
			setData(res);
15 +
		} catch (error) {
16 +
			console.log(error);
17 +
		}
18 +
	}
19 +
20 +
	return (
21 +
		<div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen">
22 +
			<a href="https://github.com/stevedylandev/bhvr" target="_blank">
23 +
				<img
24 +
					src={beaver}
25 +
					className="w-16 h-16 cursor-pointer"
26 +
					alt="beaver logo"
27 +
				/>
28 +
			</a>
29 +
			<h1 className="text-5xl font-black">bhvr</h1>
30 +
			<h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2>
31 +
			<p>A typesafe fullstack monorepo</p>
32 +
			<div className="flex items-center gap-4">
33 +
				<button
34 +
					onClick={sendRequest}
35 +
					className="bg-black text-white px-2.5 py-1.5 rounded-md"
36 +
				>
37 +
					Call API
38 +
				</button>
39 +
				<a
40 +
					target="_blank"
41 +
					href="https://bhvr.dev"
42 +
					className="border-1 border-black text-black px-2.5 py-1.5 rounded-md"
43 +
				>
44 +
					Docs
45 +
				</a>
46 +
			</div>
47 +
			{data && (
48 +
				<pre className="bg-gray-100 p-4 rounded-md">
49 +
					<code>
50 +
						Message: {data.message} <br />
51 +
						Success: {data.success.toString()}
52 +
					</code>
53 +
				</pre>
54 +
			)}
55 +
		</div>
56 +
	);
57 +
}
58 +
59 +
export default Home;
src/templates/extras/client/src/components/Home.tsx/Home.tsx (added) +51 −0
1 +
import { useState } from "react";
2 +
import beaver from "../assets/beaver.svg";
3 +
import type { ApiResponse } from "shared";
4 +
import "../App.css";
5 +
6 +
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000";
7 +
8 +
function Home() {
9 +
	const [data, setData] = useState<ApiResponse | undefined>();
10 +
11 +
	async function sendRequest() {
12 +
		try {
13 +
			const req = await fetch(`${SERVER_URL}/hello`);
14 +
			const res: ApiResponse = await req.json();
15 +
			setData(res);
16 +
		} catch (error) {
17 +
			console.log(error);
18 +
		}
19 +
	}
20 +
21 +
	return (
22 +
		<>
23 +
			<div>
24 +
				<a href="https://github.com/stevedylandev/bhvr" target="_blank">
25 +
					<img src={beaver} className="logo" alt="beaver logo" />
26 +
				</a>
27 +
			</div>
28 +
			<h1>bhvr</h1>
29 +
			<h2>Bun + Hono + Vite + React</h2>
30 +
			<p>A typesafe fullstack monorepo</p>
31 +
			<div className="card">
32 +
				<div className="button-container">
33 +
					<button onClick={sendRequest}>Call API</button>
34 +
					<a className="docs-link" target="_blank" href="https://bhvr.dev">
35 +
						Docs
36 +
					</a>
37 +
				</div>
38 +
				{data && (
39 +
					<pre className="response">
40 +
						<code>
41 +
							Message: {data.message} <br />
42 +
							Success: {data.success.toString()}
43 +
						</code>
44 +
					</pre>
45 +
				)}
46 +
			</div>
47 +
		</>
48 +
	);
49 +
}
50 +
51 +
export default Home;