Complete monorepo toolchain setup (tasks 1.1-1.7)
- Turborepo + pnpm workspaces with catalog for shared dependency versions - TypeScript strict config (base + per-package extends) - Tailwind CSS v4 via @tailwindcss/vite plugin - ESLint + Prettier shared config - Planner app scaffolded with React Router 7 (port 3001) - Journal app scaffolded with React Router 7 (port 3000) - Both apps build and start successfully via turbo Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
48547fdc82
commit
30d40de7cf
28 changed files with 4096 additions and 13 deletions
7
.prettierrc
Normal file
7
.prettierrc
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": false,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"printWidth": 100,
|
||||||
|
"tabWidth": 2
|
||||||
|
}
|
||||||
27
apps/journal/app/root.tsx
Normal file
27
apps/journal/app/root.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router";
|
||||||
|
import type { LinksFunction } from "react-router";
|
||||||
|
import stylesheet from "@trails-cool/ui/styles.css?url";
|
||||||
|
|
||||||
|
export const links: LinksFunction = () => [{ rel: "stylesheet", href: stylesheet }];
|
||||||
|
|
||||||
|
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 className="min-h-screen bg-gray-50">
|
||||||
|
{children}
|
||||||
|
<ScrollRestoration />
|
||||||
|
<Scripts />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return <Outlet />;
|
||||||
|
}
|
||||||
3
apps/journal/app/routes.ts
Normal file
3
apps/journal/app/routes.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { type RouteConfig, index } from "@react-router/dev/routes";
|
||||||
|
|
||||||
|
export default [index("routes/home.tsx")] satisfies RouteConfig;
|
||||||
17
apps/journal/app/routes/home.tsx
Normal file
17
apps/journal/app/routes/home.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import type { Route } from "./+types/home";
|
||||||
|
|
||||||
|
export function meta({}: Route.MetaArgs) {
|
||||||
|
return [
|
||||||
|
{ title: "trails.cool" },
|
||||||
|
{ name: "description", content: "Your outdoor activity journal" },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<div className="mx-auto max-w-4xl px-4 py-16">
|
||||||
|
<h1 className="text-4xl font-bold text-gray-900">trails.cool</h1>
|
||||||
|
<p className="mt-4 text-lg text-gray-600">Your outdoor activity journal</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -4,14 +4,31 @@
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "echo 'TODO: setup journal dev'",
|
"dev": "react-router dev",
|
||||||
"build": "echo 'TODO: setup journal build'"
|
"build": "react-router build",
|
||||||
|
"start": "react-router-serve ./build/server/index.js",
|
||||||
|
"typecheck": "react-router typegen && tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@trails-cool/ui": "workspace:*",
|
"@trails-cool/ui": "workspace:*",
|
||||||
"@trails-cool/types": "workspace:*",
|
"@trails-cool/types": "workspace:*",
|
||||||
"@trails-cool/map": "workspace:*",
|
"@trails-cool/map": "workspace:*",
|
||||||
"@trails-cool/gpx": "workspace:*",
|
"@trails-cool/gpx": "workspace:*",
|
||||||
"@trails-cool/i18n": "workspace:*"
|
"@trails-cool/i18n": "workspace:*",
|
||||||
|
"react": "catalog:",
|
||||||
|
"react-dom": "catalog:",
|
||||||
|
"react-router": "catalog:",
|
||||||
|
"@react-router/node": "catalog:",
|
||||||
|
"@react-router/serve": "catalog:",
|
||||||
|
"isbot": "^5.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@react-router/dev": "catalog:",
|
||||||
|
"@tailwindcss/vite": "catalog:",
|
||||||
|
"@types/react": "catalog:",
|
||||||
|
"@types/react-dom": "catalog:",
|
||||||
|
"tailwindcss": "catalog:",
|
||||||
|
"typescript": "catalog:",
|
||||||
|
"vite": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
apps/journal/react-router.config.ts
Normal file
5
apps/journal/react-router.config.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import type { Config } from "@react-router/dev/config";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
ssr: true,
|
||||||
|
} satisfies Config;
|
||||||
13
apps/journal/tsconfig.json
Normal file
13
apps/journal/tsconfig.json
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".react-router/types/**/*"
|
||||||
|
],
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDirs": [".", "./.react-router/types"],
|
||||||
|
"outDir": "build",
|
||||||
|
"types": ["vite/client"]
|
||||||
|
}
|
||||||
|
}
|
||||||
10
apps/journal/vite.config.ts
Normal file
10
apps/journal/vite.config.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { reactRouter } from "@react-router/dev/vite";
|
||||||
|
import tailwindcss from "@tailwindcss/vite";
|
||||||
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [tailwindcss(), reactRouter()],
|
||||||
|
server: {
|
||||||
|
port: 3000,
|
||||||
|
},
|
||||||
|
});
|
||||||
27
apps/planner/app/root.tsx
Normal file
27
apps/planner/app/root.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router";
|
||||||
|
import type { LinksFunction } from "react-router";
|
||||||
|
import stylesheet from "@trails-cool/ui/styles.css?url";
|
||||||
|
|
||||||
|
export const links: LinksFunction = () => [{ rel: "stylesheet", href: stylesheet }];
|
||||||
|
|
||||||
|
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 className="h-screen w-screen overflow-hidden bg-white">
|
||||||
|
{children}
|
||||||
|
<ScrollRestoration />
|
||||||
|
<Scripts />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return <Outlet />;
|
||||||
|
}
|
||||||
3
apps/planner/app/routes.ts
Normal file
3
apps/planner/app/routes.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { type RouteConfig, index } from "@react-router/dev/routes";
|
||||||
|
|
||||||
|
export default [index("routes/home.tsx")] satisfies RouteConfig;
|
||||||
19
apps/planner/app/routes/home.tsx
Normal file
19
apps/planner/app/routes/home.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import type { Route } from "./+types/home";
|
||||||
|
|
||||||
|
export function meta({}: Route.MetaArgs) {
|
||||||
|
return [
|
||||||
|
{ title: "trails.cool Planner" },
|
||||||
|
{ name: "description", content: "Collaborative route planning" },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<div className="flex h-full items-center justify-center">
|
||||||
|
<div className="text-center">
|
||||||
|
<h1 className="text-4xl font-bold text-gray-900">trails.cool Planner</h1>
|
||||||
|
<p className="mt-4 text-lg text-gray-600">Collaborative route planning</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -4,14 +4,31 @@
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "echo 'TODO: setup planner dev'",
|
"dev": "react-router dev",
|
||||||
"build": "echo 'TODO: setup planner build'"
|
"build": "react-router build",
|
||||||
|
"start": "react-router-serve ./build/server/index.js",
|
||||||
|
"typecheck": "react-router typegen && tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@trails-cool/ui": "workspace:*",
|
"@trails-cool/ui": "workspace:*",
|
||||||
"@trails-cool/types": "workspace:*",
|
"@trails-cool/types": "workspace:*",
|
||||||
"@trails-cool/map": "workspace:*",
|
"@trails-cool/map": "workspace:*",
|
||||||
"@trails-cool/gpx": "workspace:*",
|
"@trails-cool/gpx": "workspace:*",
|
||||||
"@trails-cool/i18n": "workspace:*"
|
"@trails-cool/i18n": "workspace:*",
|
||||||
|
"react": "catalog:",
|
||||||
|
"react-dom": "catalog:",
|
||||||
|
"react-router": "catalog:",
|
||||||
|
"@react-router/node": "catalog:",
|
||||||
|
"@react-router/serve": "catalog:",
|
||||||
|
"isbot": "^5.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@react-router/dev": "catalog:",
|
||||||
|
"@tailwindcss/vite": "catalog:",
|
||||||
|
"@types/react": "catalog:",
|
||||||
|
"@types/react-dom": "catalog:",
|
||||||
|
"tailwindcss": "catalog:",
|
||||||
|
"typescript": "catalog:",
|
||||||
|
"vite": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
apps/planner/react-router.config.ts
Normal file
5
apps/planner/react-router.config.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import type { Config } from "@react-router/dev/config";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
ssr: true,
|
||||||
|
} satisfies Config;
|
||||||
13
apps/planner/tsconfig.json
Normal file
13
apps/planner/tsconfig.json
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".react-router/types/**/*"
|
||||||
|
],
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDirs": [".", "./.react-router/types"],
|
||||||
|
"outDir": "build",
|
||||||
|
"types": ["vite/client"]
|
||||||
|
}
|
||||||
|
}
|
||||||
10
apps/planner/vite.config.ts
Normal file
10
apps/planner/vite.config.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { reactRouter } from "@react-router/dev/vite";
|
||||||
|
import tailwindcss from "@tailwindcss/vite";
|
||||||
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [tailwindcss(), reactRouter()],
|
||||||
|
server: {
|
||||||
|
port: 3001,
|
||||||
|
},
|
||||||
|
});
|
||||||
10
eslint.config.js
Normal file
10
eslint.config.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import js from "@eslint/js";
|
||||||
|
import tseslint from "typescript-eslint";
|
||||||
|
import prettier from "eslint-config-prettier";
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
{ ignores: ["**/build/", "**/dist/", "**/.react-router/", "**/node_modules/"] },
|
||||||
|
js.configs.recommended,
|
||||||
|
...tseslint.configs.recommended,
|
||||||
|
prettier,
|
||||||
|
);
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
## 1. Monorepo Toolchain Setup
|
## 1. Monorepo Toolchain Setup
|
||||||
|
|
||||||
- [ ] 1.1 Install pnpm and Turborepo, configure workspaces
|
- [x] 1.1 Install pnpm and Turborepo, configure workspaces
|
||||||
- [ ] 1.2 Set up TypeScript config (base tsconfig, per-package extends)
|
- [x] 1.2 Set up TypeScript config (base tsconfig, per-package extends)
|
||||||
- [ ] 1.3 Set up Tailwind CSS (shared config, content paths for monorepo)
|
- [x] 1.3 Set up Tailwind CSS (shared config, content paths for monorepo)
|
||||||
- [ ] 1.4 Set up ESLint and Prettier (shared config)
|
- [x] 1.4 Set up ESLint and Prettier (shared config)
|
||||||
- [ ] 1.5 Scaffold Planner app with React Router 7 (`apps/planner`)
|
- [x] 1.5 Scaffold Planner app with React Router 7 (`apps/planner`)
|
||||||
- [ ] 1.6 Scaffold Journal app with React Router 7 (`apps/journal`)
|
- [x] 1.6 Scaffold Journal app with React Router 7 (`apps/journal`)
|
||||||
- [ ] 1.7 Verify `turbo dev` starts both apps and `turbo build` succeeds
|
- [x] 1.7 Verify `turbo dev` starts both apps and `turbo build` succeeds
|
||||||
|
|
||||||
## 2. Shared Packages
|
## 2. Shared Packages
|
||||||
|
|
||||||
|
|
|
||||||
19
package.json
19
package.json
|
|
@ -13,5 +13,24 @@
|
||||||
"lint": "turbo lint",
|
"lint": "turbo lint",
|
||||||
"test": "turbo test",
|
"test": "turbo test",
|
||||||
"typecheck": "turbo typecheck"
|
"typecheck": "turbo typecheck"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^10.0.1",
|
||||||
|
"@react-router/dev": "^7.13.1",
|
||||||
|
"@react-router/node": "^7.13.1",
|
||||||
|
"@react-router/serve": "^7.13.1",
|
||||||
|
"@tailwindcss/vite": "^4.2.2",
|
||||||
|
"@types/react": "^19.2.14",
|
||||||
|
"@types/react-dom": "^19.2.3",
|
||||||
|
"eslint": "^10.1.0",
|
||||||
|
"eslint-config-prettier": "^10.1.8",
|
||||||
|
"prettier": "^3.8.1",
|
||||||
|
"react": "^19.2.4",
|
||||||
|
"react-dom": "^19.2.4",
|
||||||
|
"react-router": "^7.13.1",
|
||||||
|
"tailwindcss": "^4.2.2",
|
||||||
|
"turbo": "^2.8.20",
|
||||||
|
"typescript-eslint": "^8.57.1",
|
||||||
|
"vite": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
8
packages/gpx/tsconfig.json
Normal file
8
packages/gpx/tsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
8
packages/i18n/tsconfig.json
Normal file
8
packages/i18n/tsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
8
packages/map/tsconfig.json
Normal file
8
packages/map/tsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
8
packages/types/tsconfig.json
Normal file
8
packages/types/tsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,10 @@
|
||||||
"name": "@trails-cool/ui",
|
"name": "@trails-cool/ui",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": "./src/index.ts",
|
||||||
|
"./styles.css": "./src/styles.css"
|
||||||
|
},
|
||||||
"main": "./src/index.ts",
|
"main": "./src/index.ts",
|
||||||
"types": "./src/index.ts"
|
"types": "./src/index.ts"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
packages/ui/src/styles.css
Normal file
1
packages/ui/src/styles.css
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
@import "tailwindcss";
|
||||||
8
packages/ui/tsconfig.json
Normal file
8
packages/ui/tsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
3782
pnpm-lock.yaml
generated
Normal file
3782
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,3 +1,17 @@
|
||||||
packages:
|
packages:
|
||||||
- "apps/*"
|
- "apps/*"
|
||||||
- "packages/*"
|
- "packages/*"
|
||||||
|
|
||||||
|
catalog:
|
||||||
|
react: ^19.1.0
|
||||||
|
react-dom: ^19.1.0
|
||||||
|
react-router: ^7.6.1
|
||||||
|
"@react-router/dev": ^7.6.1
|
||||||
|
"@react-router/node": ^7.6.1
|
||||||
|
"@react-router/serve": ^7.6.1
|
||||||
|
"@types/react": ^19.1.4
|
||||||
|
"@types/react-dom": ^19.1.5
|
||||||
|
tailwindcss: ^4.1.7
|
||||||
|
"@tailwindcss/vite": ^4.1.7
|
||||||
|
typescript: ^5.8.3
|
||||||
|
vite: ^6.0.0
|
||||||
|
|
|
||||||
20
tsconfig.base.json
Normal file
20
tsconfig.base.json
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"noUncheckedIndexedAccess": true
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "build", "dist"]
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue