Files
asepharyana-hub-guide/skills/monorepo/SKILL.md
T
asepharyana 5780d94ccf feat(hub-guide): language-agnostic auto-trigger across all skills
- Add principle 27: 'Language-Agnostic Auto-Trigger' to engineering-principles
- Remove hardcoded English-only keyword lists from all 26 skill descriptions
- Replace with concept-based detection: triggers from code context, project files,
  and file types regardless of spoken language
- Update detect-project.sh hook output with language-agnostic message
2026-07-25 12:59:43 +07:00

170 lines
4.8 KiB
Markdown

---
name: monorepo
description: Monorepo best practices — tooling, workspace configuration, shared dependencies, CI/CD, and dependency management. Use when working in monorepos (pnpm workspaces, moon, turborepo, Nx), managing shared packages. Triggers from project files and configuration, not just keyword matching."
---
# Monorepo Best Practices
## Tool Selection
| Tool | Best For | Why |
|------|----------|-----|
| **pnpm workspaces** | Package management | Strict, fast, disk-efficient |
| **moon** | Monorepo orchestration | Task orchestration + caching |
| **turborepo** | Task orchestration | Simple caching, good for JS/TS |
| **Nx** | Full monorepo framework | Generators, dependency graph, affected commands |
| **Git submodules** | Multi-repo coordination | Separate repos imported together (this repo's pattern) |
## Workspace Structure (pnpm + moon)
```
├── apps/
│ ├── hub/ # Next.js app (submodule)
│ └── scraper/ # Rust API (submodule)
├── packages/ # Shared libraries (when not submodules)
├── infra/ # Shared infra config
├── pnpm-workspace.yaml
├── moon.yml
└── package.json
```
### pnpm-workspace.yaml
```yaml
packages:
- 'apps/*'
- 'packages/*'
```
### moon.yml (root)
```yaml
$schema: 'https://moonrepo.dev/schemas/project.json'
language: 'typescript'
type: 'application'
```
## Shared Dependencies
```bash
# Install a shared dependency
pnpm add -w typescript
# Install in a specific package
pnpm add --filter @scope/package zod
# Run in all packages
pnpm -r run build
```
**Rules:**
- **One version of a dependency across the monorepo** — use `pnpm overrides` or `resolution`.
- **Root `devDependencies`** for shared tooling (TypeScript, Biome, ESLint).
- **Explicit `dependencies`** — never rely on hoisting.
- **Lock file** (`pnpm-lock.yaml`) committed — immutable installs.
## Git Submodules (this repo's pattern)
```
asepharyana-hub/
├── apps/
│ ├── hub/ → asepharyana/asepharyana-hub-hub
│ └── scraper/ → asepharyana/asepharyana-hub-scraper
```
### Submodule Workflow
```bash
# Init after clone
git submodule update --init --recursive
# Update all submodules to latest
git submodule foreach git pull origin main
# Update one submodule
cd apps/hub && git checkout main && git pull
cd ../.. && git add apps/hub && git commit -m "chore(deps): update hub submodule"
git push
```
**State indicators:**
- `(HEAD)` — detached at committed pointer (normal state).
- `(main)` — on a branch (you've done `cd apps/name && git checkout main`).
- Dirty — uncommitted changes inside submodule.
### When to Use Submodules vs Workspaces
| Need | Use |
|------|-----|
| Independent repos, separate deploy | Submodules |
| Shared code within one repo | Workspaces |
| Tightly coupled, always deploy together | Workspaces |
| Loosely coupled, different teams | Submodules |
## CI/CD for Monorepos
### Selective Builds
```yaml
# Only run relevant workflows based on changed paths
on:
push:
branches: [main]
paths:
- 'apps/hub/**'
- 'infra/docker/hub.Dockerfile'
```
### Affected Commands (Nx/Turborepo/Moon)
```bash
moon ci # Runs affected tasks based on changes
npx nx affected:test # Nx style
turbo run build # Turborepo — leverages cache
```
### Caching
- **moon/turborepo** cache task outputs by file hash + env.
- **pnpm** caches node_modules.
- **Docker layer caching** — Registry-based caching for Docker builds.
## Shared Configuration
### TypeScript
```jsonc
// tsconfig.base.json at root — extended by all packages
{
"compilerOptions": {
"strict": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"moduleResolution": "bundler"
}
}
```
### ESLint / Biome
```jsonc
// biome.json at root — shared config for all packages
{
"formatter": { "indentStyle": "tab", "lineWidth": 120 },
"linter": { "rules": { "recommended": true } }
}
```
## Dependency Management
- **Dependabot / Renovate** — automate dependency updates.
- **`pnpm dedupe`** — deduplicate after updates.
- **Check for duplicates** — `pnpm ls -r` or `pnpm why <package>`.
- **When to upgrade:**
- Patch: auto-merge.
- Minor: update weekly.
- Major: scheduled migration, document breaking changes.
## Anti-patterns
- ❌ Different dependency versions across packages — inconsistent builds
- ❌ Hoisting assumptions — code works in dev but not in CI because of missing deps
- ❌ Monolithic `package.json` — each package declares its own dependencies
- ❌ No `.npmrc` with `shamefully-hoist=true` — defeats pnpm's strictness
- ❌ Circular dependencies between packages — extract shared code
- ❌ Every change rebuilds everything — use affected commands and caching
- ❌ Submodule pointer drift — always commit after updating submodules