@mr.dj2u/knowledge 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/content/checklists/ship-test-loop.md +16 -0
- package/dist/content/checklists/unified-agent-bundle-validation.md +8 -0
- package/dist/content/examples/ship-test-loop.md +13 -0
- package/dist/content/examples/unified-agent-bundle-bootstrap.md +8 -0
- package/dist/content/guides/animation-performance.md +30 -0
- package/dist/content/guides/post-create-onboarding.md +113 -0
- package/dist/content/patterns/api/api-routes.md +314 -0
- package/dist/content/patterns/api/error-handling.md +311 -0
- package/dist/content/patterns/database/drizzle-schema.md +280 -0
- package/dist/content/patterns/database/migrations.md +365 -0
- package/dist/content/patterns/database/query-organization.md +537 -0
- package/dist/content/patterns/database/relations.md +450 -0
- package/dist/content/patterns/deployment/build-configuration.md +452 -0
- package/dist/content/patterns/deployment/ci-cd-patterns.md +448 -0
- package/dist/content/patterns/deployment/environment-config.md +380 -0
- package/dist/content/patterns/deployment/hosting-setup.md +425 -0
- package/dist/content/patterns/project/configuration-patterns.md +459 -0
- package/dist/content/patterns/project/documentation-org.md +506 -0
- package/dist/content/patterns/project/folder-structure.md +398 -0
- package/dist/content/patterns/project/library-exports.md +465 -0
- package/dist/content/patterns/project/monorepo-structure.md +500 -0
- package/dist/content/patterns/routing/dynamic-routes.md +221 -0
- package/dist/content/patterns/routing/file-based-routing.md +186 -0
- package/dist/content/patterns/routing/route-groups.md +429 -0
- package/dist/content/patterns/state/persistence-middleware.md +521 -0
- package/dist/content/patterns/state/selector-hooks.md +538 -0
- package/dist/content/patterns/state/store-organization.md +539 -0
- package/dist/content/patterns/state/zustand-patterns.md +348 -0
- package/dist/content/patterns/styling/component-styling.md +468 -0
- package/dist/content/patterns/styling/responsive-patterns.md +398 -0
- package/dist/content/patterns/styling/theme-configuration.md +426 -0
- package/dist/content/patterns/styling/uniwind-setup.md +412 -0
- package/dist/content/prompts/continue-development.md +27 -0
- package/dist/content/prompts/create-expo-super-stack.md +29 -0
- package/dist/content/prompts/fix-seo.md +29 -0
- package/dist/content/prompts/onboard-new-expo-app.md +11 -0
- package/dist/content/prompts/prepare-deploy.md +29 -0
- package/dist/content/prompts/project-research-plan.md +29 -0
- package/dist/content/prompts/review-expo-project.md +29 -0
- package/dist/content/prompts/run-doctor.md +30 -0
- package/dist/content/prompts/ship-test-loop.md +24 -0
- package/dist/content/reference/create-expo-stack-uniwind.md +29 -0
- package/dist/content/reference/doctor-dogfood.md +42 -0
- package/dist/content/reference/mcp-sdk-transport.md +30 -0
- package/dist/content/reference/package-ci-patterns.md +24 -0
- package/dist/content/reference/reference-repo-evacuation.md +31 -0
- package/dist/content/resource-index.json +67 -0
- package/dist/content/rules/app-folder-architecture.md +13 -0
- package/dist/content/rules/env-hygiene.md +9 -0
- package/dist/content/rules/seo-metadata.md +7 -0
- package/dist/content/rules/ssr-safety.md +9 -0
- package/dist/content/skills/api-routes.md +33 -0
- package/dist/content/skills/continue-development.md +31 -0
- package/dist/content/skills/debugging.md +31 -0
- package/dist/content/skills/deployment.md +32 -0
- package/dist/content/skills/dev-server-management.md +31 -0
- package/dist/content/skills/env-vars.md +32 -0
- package/dist/content/skills/expo-router-architecture.md +33 -0
- package/dist/content/skills/expo-ssr-safety.md +32 -0
- package/dist/content/skills/plugin-creation.md +41 -0
- package/dist/content/skills/production-server-patterns.md +31 -0
- package/dist/content/skills/project-onboarding.md +31 -0
- package/dist/content/skills/research-plan-intake.md +31 -0
- package/dist/content/skills/seo-metadata.md +31 -0
- package/dist/content/skills/super-stack-startup.md +31 -0
- package/dist/content/skills/uniwind-theming.md +32 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +369 -0
- package/dist/index.js.map +1 -0
- package/dist/patterns/index.d.ts +78 -0
- package/dist/patterns/index.d.ts.map +1 -0
- package/dist/patterns/index.js +264 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/prompts/index.d.ts +35 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +270 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/skills/index.d.ts +3 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +2 -0
- package/dist/skills/index.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
# Monorepo Structure
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Monorepo structure patterns establish how to organize multiple apps and shared libraries in a single repository using Turborepo + pnpm workspaces. This enables code sharing, unified tooling, and scalable development across interconnected projects.
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
**Apply monorepo patterns when:**
|
|
10
|
+
- ✅ Building multiple related apps (web, mobile, desktop)
|
|
11
|
+
- ✅ Creating shared component libraries
|
|
12
|
+
- ✅ Managing shared utilities, hooks, types
|
|
13
|
+
- ✅ Scaling team productivity across projects
|
|
14
|
+
- ✅ Centralizing configuration and tooling
|
|
15
|
+
- ✅ Enabling code reuse across packages
|
|
16
|
+
|
|
17
|
+
## Core Concepts
|
|
18
|
+
|
|
19
|
+
**Monorepo Architecture:**
|
|
20
|
+
```
|
|
21
|
+
monorepo/
|
|
22
|
+
├── apps/ # Applications (Expo, Next.js, etc.)
|
|
23
|
+
│ ├── app-name/ # Standalone app with own routes/screens
|
|
24
|
+
│ └── another-app/
|
|
25
|
+
├── packages/ # Shared libraries and utilities
|
|
26
|
+
│ ├── ui/ # Component library
|
|
27
|
+
│ ├── hooks/ # Custom hooks
|
|
28
|
+
│ ├── utils/ # Utilities and helpers
|
|
29
|
+
│ ├── types/ # Shared TypeScript types
|
|
30
|
+
│ ├── config/ # Configuration and constants
|
|
31
|
+
│ └── db/ # Database layer (Drizzle, schemas)
|
|
32
|
+
├── turbo.json # Turborepo configuration
|
|
33
|
+
├── pnpm-workspace.yaml # Workspace definition
|
|
34
|
+
└── package.json # Root package.json
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Key Benefits:**
|
|
38
|
+
- Single source of truth for dependencies
|
|
39
|
+
- Shared TypeScript configuration
|
|
40
|
+
- Unified CI/CD and linting
|
|
41
|
+
- Code deduplication
|
|
42
|
+
- Atomic version updates
|
|
43
|
+
- Optimized build cache
|
|
44
|
+
|
|
45
|
+
## Code Examples
|
|
46
|
+
|
|
47
|
+
### pnpm-workspace.yaml - Workspace Definition
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
# pnpm-workspace.yaml - Define workspace structure
|
|
51
|
+
packages:
|
|
52
|
+
- 'apps/*'
|
|
53
|
+
- 'packages/*'
|
|
54
|
+
|
|
55
|
+
ignore:
|
|
56
|
+
- '**/*.test.ts'
|
|
57
|
+
- 'node_modules'
|
|
58
|
+
- '.next'
|
|
59
|
+
- 'dist'
|
|
60
|
+
- 'build'
|
|
61
|
+
|
|
62
|
+
# Shallow clone (don't install transitive dependencies)
|
|
63
|
+
# Only direct dependencies installed
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### turbo.json - Build Orchestration
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"$schema": "https://turbo.build/schema.json",
|
|
71
|
+
|
|
72
|
+
"globalDotEnv": [".env", ".env.production"],
|
|
73
|
+
|
|
74
|
+
"tasks": {
|
|
75
|
+
"build": {
|
|
76
|
+
"description": "Build package for distribution",
|
|
77
|
+
"outputs": ["dist/**", "build/**"],
|
|
78
|
+
"outputMode": "full",
|
|
79
|
+
"cache": true,
|
|
80
|
+
"dependsOn": ["^build"]
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
"dev": {
|
|
84
|
+
"description": "Start development server",
|
|
85
|
+
"cache": false,
|
|
86
|
+
"persistent": true
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
"test": {
|
|
90
|
+
"description": "Run tests",
|
|
91
|
+
"outputs": ["coverage/**"],
|
|
92
|
+
"cache": true
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
"lint": {
|
|
96
|
+
"description": "Run linting",
|
|
97
|
+
"cache": true
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
"type-check": {
|
|
101
|
+
"description": "Type-check TypeScript",
|
|
102
|
+
"cache": true
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
"format": {
|
|
106
|
+
"description": "Format code",
|
|
107
|
+
"cache": false
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
"ui": "tui",
|
|
112
|
+
"concurrency": 4
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Root package.json - Workspace Configuration
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"name": "core-monorepo",
|
|
121
|
+
"version": "1.0.0",
|
|
122
|
+
"private": true,
|
|
123
|
+
"type": "module",
|
|
124
|
+
|
|
125
|
+
"scripts": {
|
|
126
|
+
"dev": "turbo dev",
|
|
127
|
+
"build": "turbo build",
|
|
128
|
+
"test": "turbo test",
|
|
129
|
+
"lint": "turbo lint",
|
|
130
|
+
"lint:fix": "turbo lint -- --fix",
|
|
131
|
+
"type-check": "turbo type-check",
|
|
132
|
+
"format": "prettier --write \"**/*.{ts,tsx,json,md}\"",
|
|
133
|
+
"clean": "turbo clean && rm -rf node_modules",
|
|
134
|
+
"install": "pnpm install"
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
"devDependencies": {
|
|
138
|
+
"turbo": "^2.0.0",
|
|
139
|
+
"prettier": "^3.0.0",
|
|
140
|
+
"eslint": "^9.0.0",
|
|
141
|
+
"typescript": "^5.9.0"
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
"engines": {
|
|
145
|
+
"node": ">=18.0.0",
|
|
146
|
+
"pnpm": ">=8.0.0"
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
"pnpm": {
|
|
150
|
+
"overrides": {
|
|
151
|
+
"react": "^19.0.0",
|
|
152
|
+
"react-native": "^0.83.0"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### apps/app-name/package.json - App-level Configuration
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"name": "@monorepo/app-name",
|
|
163
|
+
"version": "1.0.0",
|
|
164
|
+
"private": true,
|
|
165
|
+
"type": "module",
|
|
166
|
+
|
|
167
|
+
"scripts": {
|
|
168
|
+
"dev": "expo start",
|
|
169
|
+
"build": "expo build",
|
|
170
|
+
"lint": "eslint .",
|
|
171
|
+
"type-check": "tsc --noEmit"
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
"dependencies": {
|
|
175
|
+
"@monorepo/ui": "workspace:*",
|
|
176
|
+
"@monorepo/hooks": "workspace:*",
|
|
177
|
+
"@monorepo/utils": "workspace:*",
|
|
178
|
+
"@monorepo/db": "workspace:*",
|
|
179
|
+
|
|
180
|
+
"react": "^19.0.0",
|
|
181
|
+
"react-native": "^0.83.0",
|
|
182
|
+
"expo": "^55.0.0",
|
|
183
|
+
"expo-router": "^3.0.0",
|
|
184
|
+
"zustand": "^4.4.0"
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
"devDependencies": {
|
|
188
|
+
"@types/react": "^19.0.0",
|
|
189
|
+
"@types/react-native": "^0.83.0",
|
|
190
|
+
"typescript": "^5.9.0",
|
|
191
|
+
"eslint": "^9.0.0"
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### packages/ui/package.json - Library Configuration
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"name": "@monorepo/ui",
|
|
201
|
+
"version": "1.0.0",
|
|
202
|
+
"description": "Shared UI component library",
|
|
203
|
+
"main": "dist/index.js",
|
|
204
|
+
"types": "dist/index.d.ts",
|
|
205
|
+
|
|
206
|
+
"exports": {
|
|
207
|
+
".": {
|
|
208
|
+
"import": "./dist/index.js",
|
|
209
|
+
"types": "./dist/index.d.ts"
|
|
210
|
+
},
|
|
211
|
+
"./components": {
|
|
212
|
+
"import": "./dist/components/index.js",
|
|
213
|
+
"types": "./dist/components/index.d.ts"
|
|
214
|
+
},
|
|
215
|
+
"./hooks": {
|
|
216
|
+
"import": "./dist/hooks/index.js",
|
|
217
|
+
"types": "./dist/hooks/index.d.ts"
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
"files": ["dist", "src"],
|
|
222
|
+
|
|
223
|
+
"scripts": {
|
|
224
|
+
"build": "tsc --project tsconfig.build.json",
|
|
225
|
+
"dev": "tsc --watch",
|
|
226
|
+
"lint": "eslint src"
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
"dependencies": {
|
|
230
|
+
"@monorepo/utils": "workspace:*",
|
|
231
|
+
"@monorepo/types": "workspace:*",
|
|
232
|
+
|
|
233
|
+
"react": "^19.0.0",
|
|
234
|
+
"react-native": "^0.83.0"
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
"devDependencies": {
|
|
238
|
+
"@types/react": "^19.0.0",
|
|
239
|
+
"@types/react-native": "^0.83.0",
|
|
240
|
+
"typescript": "^5.9.0"
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### packages/db/package.json - Database Layer
|
|
246
|
+
|
|
247
|
+
```json
|
|
248
|
+
{
|
|
249
|
+
"name": "@monorepo/db",
|
|
250
|
+
"version": "1.0.0",
|
|
251
|
+
"main": "dist/index.js",
|
|
252
|
+
"types": "dist/index.d.ts",
|
|
253
|
+
|
|
254
|
+
"exports": {
|
|
255
|
+
".": {
|
|
256
|
+
"import": "./dist/index.js",
|
|
257
|
+
"types": "./dist/index.d.ts"
|
|
258
|
+
},
|
|
259
|
+
"./schemas": {
|
|
260
|
+
"import": "./dist/schemas/index.js",
|
|
261
|
+
"types": "./dist/schemas/index.d.ts"
|
|
262
|
+
},
|
|
263
|
+
"./queries": {
|
|
264
|
+
"import": "./dist/queries/index.js",
|
|
265
|
+
"types": "./dist/queries/index.d.ts"
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
"scripts": {
|
|
270
|
+
"build": "tsc",
|
|
271
|
+
"db:push": "drizzle-kit push:pg",
|
|
272
|
+
"db:pull": "drizzle-kit introspect:pg",
|
|
273
|
+
"db:generate": "drizzle-kit generate:pg"
|
|
274
|
+
},
|
|
275
|
+
|
|
276
|
+
"dependencies": {
|
|
277
|
+
"@monorepo/types": "workspace:*",
|
|
278
|
+
"drizzle-orm": "^0.30.0",
|
|
279
|
+
"postgres": "^3.4.0"
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
"devDependencies": {
|
|
283
|
+
"drizzle-kit": "^0.20.0"
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Monorepo File Structure
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
core-monorepo/
|
|
292
|
+
├── apps/
|
|
293
|
+
│ ├── creatisphere/ # Expo app
|
|
294
|
+
│ │ ├── src/app/
|
|
295
|
+
│ │ ├── src/components/
|
|
296
|
+
│ │ ├── package.json
|
|
297
|
+
│ │ ├── app.json
|
|
298
|
+
│ │ └── tsconfig.json
|
|
299
|
+
│ │
|
|
300
|
+
│ ├── higher/ # Another Expo app
|
|
301
|
+
│ │ ├── src/app/
|
|
302
|
+
│ │ ├── src/components/
|
|
303
|
+
│ │ ├── package.json
|
|
304
|
+
│ │ └── app.json
|
|
305
|
+
│ │
|
|
306
|
+
│ └── website/ # Next.js app (optional)
|
|
307
|
+
│ ├── app/
|
|
308
|
+
│ ├── components/
|
|
309
|
+
│ └── package.json
|
|
310
|
+
│
|
|
311
|
+
├── packages/
|
|
312
|
+
│ ├── ui/
|
|
313
|
+
│ │ ├── src/components/ # Shared components
|
|
314
|
+
│ │ ├── src/index.ts
|
|
315
|
+
│ │ ├── package.json
|
|
316
|
+
│ │ └── tsconfig.json
|
|
317
|
+
│ │
|
|
318
|
+
│ ├── hooks/
|
|
319
|
+
│ │ ├── src/useAuth.ts
|
|
320
|
+
│ │ ├── src/useForm.ts
|
|
321
|
+
│ │ ├── src/index.ts
|
|
322
|
+
│ │ └── package.json
|
|
323
|
+
│ │
|
|
324
|
+
│ ├── utils/
|
|
325
|
+
│ │ ├── src/date.ts
|
|
326
|
+
│ │ ├── src/string.ts
|
|
327
|
+
│ │ ├── src/index.ts
|
|
328
|
+
│ │ └── package.json
|
|
329
|
+
│ │
|
|
330
|
+
│ ├── types/
|
|
331
|
+
│ │ ├── src/user.ts
|
|
332
|
+
│ │ ├── src/index.ts
|
|
333
|
+
│ │ └── package.json
|
|
334
|
+
│ │
|
|
335
|
+
│ ├── config/
|
|
336
|
+
│ │ ├── src/theme.ts
|
|
337
|
+
│ │ ├── src/constants.ts
|
|
338
|
+
│ │ └── package.json
|
|
339
|
+
│ │
|
|
340
|
+
│ └── db/
|
|
341
|
+
│ ├── src/schemas/
|
|
342
|
+
│ ├── src/queries/
|
|
343
|
+
│ ├── src/index.ts
|
|
344
|
+
│ ├── drizzle.config.ts
|
|
345
|
+
│ └── package.json
|
|
346
|
+
│
|
|
347
|
+
├── turbo.json # Turborepo config
|
|
348
|
+
├── pnpm-workspace.yaml # Workspace definition
|
|
349
|
+
├── tsconfig.base.json # Base TypeScript config
|
|
350
|
+
├── package.json # Root package
|
|
351
|
+
├── tsconfig.json
|
|
352
|
+
├── eslint.config.js
|
|
353
|
+
└── prettier.config.json
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### tsconfig.base.json - Shared TypeScript Config
|
|
357
|
+
|
|
358
|
+
```json
|
|
359
|
+
{
|
|
360
|
+
"compilerOptions": {
|
|
361
|
+
"target": "ES2020",
|
|
362
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
363
|
+
"jsx": "react-jsx",
|
|
364
|
+
|
|
365
|
+
"strict": true,
|
|
366
|
+
"noUnusedLocals": true,
|
|
367
|
+
"noUnusedParameters": true,
|
|
368
|
+
"noImplicitReturns": true,
|
|
369
|
+
|
|
370
|
+
"module": "ESNext",
|
|
371
|
+
"moduleResolution": "node",
|
|
372
|
+
"resolveJsonModule": true,
|
|
373
|
+
"allowSyntheticDefaultImports": true,
|
|
374
|
+
|
|
375
|
+
"baseUrl": ".",
|
|
376
|
+
"paths": {
|
|
377
|
+
"@monorepo/ui": ["packages/ui/src"],
|
|
378
|
+
"@monorepo/hooks": ["packages/hooks/src"],
|
|
379
|
+
"@monorepo/utils": ["packages/utils/src"],
|
|
380
|
+
"@monorepo/types": ["packages/types/src"],
|
|
381
|
+
"@monorepo/config": ["packages/config/src"],
|
|
382
|
+
"@monorepo/db": ["packages/db/src"]
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### app tsconfig.json - App-specific Config
|
|
389
|
+
|
|
390
|
+
```json
|
|
391
|
+
{
|
|
392
|
+
"extends": "../../tsconfig.base.json",
|
|
393
|
+
|
|
394
|
+
"compilerOptions": {
|
|
395
|
+
"jsx": "react-jsx",
|
|
396
|
+
"paths": {
|
|
397
|
+
"@/*": ["./src/*"],
|
|
398
|
+
"@/components": ["./src/components"],
|
|
399
|
+
"@/screens": ["./src/screens"],
|
|
400
|
+
"@/store": ["./src/store"],
|
|
401
|
+
"@/utils": ["./src/utils"]
|
|
402
|
+
}
|
|
403
|
+
},
|
|
404
|
+
|
|
405
|
+
"include": ["src", "index.js"],
|
|
406
|
+
"exclude": ["node_modules", "dist"]
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Workspace Dependencies - package.json Pattern
|
|
411
|
+
|
|
412
|
+
```json
|
|
413
|
+
{
|
|
414
|
+
"dependencies": {
|
|
415
|
+
"@monorepo/ui": "workspace:*",
|
|
416
|
+
"@monorepo/hooks": "workspace:*",
|
|
417
|
+
"@monorepo/db": "workspace:*"
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
**Explanation:**
|
|
423
|
+
- `workspace:*` — Reference local package version
|
|
424
|
+
- pnpm resolves to actual package (not npm registry)
|
|
425
|
+
- Always uses local version during development
|
|
426
|
+
- Can be published independently
|
|
427
|
+
|
|
428
|
+
## Monorepo Best Practices
|
|
429
|
+
|
|
430
|
+
### ✅ DO
|
|
431
|
+
|
|
432
|
+
1. **Use workspace: references for local packages**
|
|
433
|
+
```json
|
|
434
|
+
"@monorepo/ui": "workspace:*" // References packages/ui
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
2. **Organize by domain (apps vs. packages)**
|
|
438
|
+
```
|
|
439
|
+
apps/ - Standalone applications
|
|
440
|
+
packages/ - Shared libraries and utilities
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
3. **Share TypeScript configuration**
|
|
444
|
+
```
|
|
445
|
+
tsconfig.base.json - Root config
|
|
446
|
+
tsconfig.json - App overrides
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
4. **Use Turborepo for task orchestration**
|
|
450
|
+
```json
|
|
451
|
+
"build": {
|
|
452
|
+
"dependsOn": ["^build"], // Build deps first
|
|
453
|
+
"cache": true
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
5. **Extract common code to packages**
|
|
458
|
+
```
|
|
459
|
+
- Shared components → packages/ui
|
|
460
|
+
- Custom hooks → packages/hooks
|
|
461
|
+
- Utilities → packages/utils
|
|
462
|
+
- Types → packages/types
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### ❌ DON'T
|
|
466
|
+
|
|
467
|
+
1. **Don't use relative paths for local packages**
|
|
468
|
+
```json
|
|
469
|
+
❌ "../../../packages/ui"
|
|
470
|
+
✅ "@monorepo/ui": "workspace:*"
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
2. **Don't duplicate code across apps**
|
|
474
|
+
```typescript
|
|
475
|
+
❌ Each app has its own useAuth hook
|
|
476
|
+
✅ Shared hook in packages/hooks
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
3. **Don't create overly nested package structure**
|
|
480
|
+
```
|
|
481
|
+
❌ packages/utils/src/helpers/date/formatting.ts
|
|
482
|
+
✅ packages/utils/src/date.ts
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
4. **Don't forget to update root package.json scripts**
|
|
486
|
+
```json
|
|
487
|
+
❌ Only app-level scripts
|
|
488
|
+
✅ Root scripts for "build all", "test all", "lint all"
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
## Related Patterns
|
|
492
|
+
|
|
493
|
+
- [Folder Structure](./folder-structure.md) — Individual app organization
|
|
494
|
+
- [Library Exports](./library-exports.md) — Package.json exports field
|
|
495
|
+
- [Build Configuration](./build-configuration.md) — Metro, Babel, tsconfig
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
*Pattern extracted from production monorepos: core-monorepo (3 apps, 6 packages), mds-dev-suite*
|
|
500
|
+
*Examples: pnpm-workspace.yaml, turbo.json, tsconfig.base.json, workspace:* references*
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Dynamic Routes with Parameters
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Dynamic routes capture URL parameters using bracket syntax `[param].tsx` in Expo Router. Parameters are extracted via `useLocalSearchParams()` hook with full TypeScript support. This enables parameterized pages for lists (detail views, user profiles, etc.) while maintaining type safety.
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
**Use dynamic routes** for:
|
|
10
|
+
- ✅ Detail pages from lists (`/events/123`, `/user/alice`)
|
|
11
|
+
- ✅ Nested hierarchies (`/guides/PLZA/strategies/15`)
|
|
12
|
+
- ✅ Optional parameters with catch-all routes (`[...slug]`)
|
|
13
|
+
- ✅ Single or multiple dynamic segments
|
|
14
|
+
|
|
15
|
+
## Code Example
|
|
16
|
+
|
|
17
|
+
### Single Dynamic Segment
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// File: app/events/[id].tsx
|
|
21
|
+
import { useLocalSearchParams } from 'expo-router';
|
|
22
|
+
import { EventDetailScreen } from '@/components/EventDetailScreen';
|
|
23
|
+
|
|
24
|
+
export default function EventDetailRoute() {
|
|
25
|
+
const { id } = useLocalSearchParams<{ id: string }>();
|
|
26
|
+
|
|
27
|
+
if (!id) {
|
|
28
|
+
return <ErrorScreen message="Event ID is required" />;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return <EventDetailScreen eventId={id} />;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Navigation
|
|
35
|
+
import { router } from 'expo-router';
|
|
36
|
+
router.push(`/events/${eventId}`);
|
|
37
|
+
router.push({
|
|
38
|
+
pathname: '/events/[id]',
|
|
39
|
+
params: { id: eventId },
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**From:** PokePages/src/app/(drawer)/events/[event].tsx
|
|
44
|
+
|
|
45
|
+
### Multiple Dynamic Segments
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// File: app/guides/[region]/[guide].tsx
|
|
49
|
+
import { useLocalSearchParams } from 'expo-router';
|
|
50
|
+
|
|
51
|
+
export default function GuideDetailRoute() {
|
|
52
|
+
const { region, guide } = useLocalSearchParams<{
|
|
53
|
+
region: string;
|
|
54
|
+
guide: string;
|
|
55
|
+
}>();
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<GuideDetailScreen
|
|
59
|
+
region={region}
|
|
60
|
+
guide={guide}
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Usage
|
|
66
|
+
router.push({
|
|
67
|
+
pathname: '/guides/[region]/[guide]',
|
|
68
|
+
params: { region: 'PLZA', guide: 'elite-four' },
|
|
69
|
+
});
|
|
70
|
+
// Results in: /guides/PLZA/elite-four
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**From:** PokePages/src/app/(drawer)/guides/PLZA/strategies/[id].tsx pattern
|
|
74
|
+
|
|
75
|
+
### Catch-All Routes (Variable Segments)
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// File: app/docs/[...slug].tsx
|
|
79
|
+
import { useLocalSearchParams } from 'expo-router';
|
|
80
|
+
|
|
81
|
+
export default function DocsRoute() {
|
|
82
|
+
const { slug } = useLocalSearchParams<{ slug: string[] }>();
|
|
83
|
+
// slug is an array: ['api', 'reference', 'functions']
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<DocsScreen
|
|
87
|
+
path={slug?.join('/') || ''}
|
|
88
|
+
breadcrumbs={slug}
|
|
89
|
+
/>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Navigation
|
|
94
|
+
router.push('/docs/api/reference/functions');
|
|
95
|
+
// slug becomes: ['api', 'reference', 'functions']
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**From:** Expo Router conventions, applicable to content-heavy hierarchies
|
|
99
|
+
|
|
100
|
+
## Configuration
|
|
101
|
+
|
|
102
|
+
### TypeScript Setup for Type-Safe Params
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Define param types for each route
|
|
106
|
+
type EventDetailParams = {
|
|
107
|
+
id: string;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
type GuideDetailParams = {
|
|
111
|
+
region: string;
|
|
112
|
+
guide: string;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// In route file
|
|
116
|
+
const { id } = useLocalSearchParams<EventDetailParams>();
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Query Parameters (Search Strings)
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// Navigation with query params
|
|
123
|
+
router.push({
|
|
124
|
+
pathname: '/search',
|
|
125
|
+
params: {
|
|
126
|
+
q: 'pikachu',
|
|
127
|
+
type: 'pokemon',
|
|
128
|
+
generation: '1'
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Results in: /search?q=pikachu&type=pokemon&generation=1
|
|
133
|
+
|
|
134
|
+
// In route
|
|
135
|
+
const { q, type, generation } = useLocalSearchParams<{
|
|
136
|
+
q?: string;
|
|
137
|
+
type?: string;
|
|
138
|
+
generation?: string;
|
|
139
|
+
}>();
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Best Practices
|
|
143
|
+
|
|
144
|
+
### ✅ DO
|
|
145
|
+
|
|
146
|
+
1. **Type your params** for IDE autocomplete and type checking
|
|
147
|
+
```typescript
|
|
148
|
+
const { id } = useLocalSearchParams<{ id: string }>();
|
|
149
|
+
// TypeScript knows id is string
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
2. **Handle missing params** with validation
|
|
153
|
+
```typescript
|
|
154
|
+
const { id } = useLocalSearchParams<{ id: string }>();
|
|
155
|
+
|
|
156
|
+
if (!id) {
|
|
157
|
+
return <ErrorScreen />;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Safe to use id here
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
3. **Use descriptive param names**
|
|
164
|
+
```
|
|
165
|
+
✅ [userId].tsx
|
|
166
|
+
✅ [eventId].tsx
|
|
167
|
+
❌ [id].tsx (too generic)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
4. **Nest dynamic routes** for logical hierarchies
|
|
171
|
+
```
|
|
172
|
+
guides/
|
|
173
|
+
├── [region]/
|
|
174
|
+
│ ├── [guide].tsx → /guides/:region/:guide
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
5. **Use catch-all for documentation or content hierarchies**
|
|
178
|
+
```
|
|
179
|
+
docs/[...slug].tsx → /docs/api/reference/functions
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### ❌ DON'T
|
|
183
|
+
|
|
184
|
+
1. **Don't mix route parameters and query parameters unnecessarily**
|
|
185
|
+
```typescript
|
|
186
|
+
// ❌ AVOID
|
|
187
|
+
/events/123?id=456&eventId=789
|
|
188
|
+
|
|
189
|
+
// ✅ BETTER - use route params
|
|
190
|
+
/events/123
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
2. **Don't rely on optional params without defaults**
|
|
194
|
+
```typescript
|
|
195
|
+
// ❌ RISKY
|
|
196
|
+
const { id } = useLocalSearchParams<{ id: string }>();
|
|
197
|
+
return <EventDetail id={id} />; // Could be undefined
|
|
198
|
+
|
|
199
|
+
// ✅ SAFE
|
|
200
|
+
const { id } = useLocalSearchParams<{ id?: string }>();
|
|
201
|
+
if (!id) return <ErrorScreen />;
|
|
202
|
+
return <EventDetail id={id} />;
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
3. **Don't create overly deep param nesting** without cause
|
|
206
|
+
```
|
|
207
|
+
❌ /app/[userId]/posts/[postId]/comments/[commentId]/likes/[likeId]
|
|
208
|
+
✅ /posts/[postId] with comment data in store/props
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Related Patterns
|
|
212
|
+
|
|
213
|
+
- [File-Based Routing](./file-based-routing.md) — Route file structure
|
|
214
|
+
- [Route Groups](./route-groups.md) — Organizing routes hierarchically
|
|
215
|
+
- [Navigation Patterns](./navigation-patterns.md) — router.push, Link components
|
|
216
|
+
- [API Routes](./api-routes.md) — Dynamic API endpoints
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
*Pattern extracted from production repositories: PokePages, not-hot-dog, Expo Router documentation*
|
|
221
|
+
*Implementations: PokePages/src\app\(drawer)\events\[event].tsx*
|