Monorepo với Turborepo: Setup cho team frontend từ A đến Z
Hướng dẫn setup Turborepo monorepo cho team frontend — từ cấu trúc thư mục, shared packages, đến CI pipeline tối ưu.
Team frontend lớn dần, 3-4 apps dùng chung UI components, utils, types — mỗi repo một version riêng. Sound familiar? Monorepo là giải pháp, và Turborepo là cách nhanh nhất để setup.
Tại sao Turborepo?
So với Nx (đối thủ chính), Turborepo có ưu điểm:
- Zero config: Không cần học DSL riêng, chỉ cần
turbo.json - Incremental adoption: Thêm vào existing monorepo dễ dàng
- Remote caching: Cache build artifacts trên Vercel (hoặc self-host)
- Task pipeline: Khai báo dependencies giữa tasks, Turbo tự parallelize
Cấu trúc thư mục
my-monorepo/
├── apps/
│ ├── web/ # Next.js main app
│ ├── admin/ # Admin dashboard
│ └── docs/ # Documentation site
├── packages/
│ ├── ui/ # Shared React components
│ ├── config-eslint/ # Shared ESLint config
│ ├── config-ts/ # Shared tsconfig
│ └── utils/ # Shared utilities
├── turbo.json
├── package.json
└── pnpm-workspace.yaml # hoặc npm workspaces
Setup từ đầu
# Tạo mới
npx create-turbo@latest my-monorepo
# Hoặc thêm vào existing repo
npm install -D turbo
File turbo.json:
{
"": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env.*local"],
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},
"dev": {
"cache": false,
"persistent": true
},
"lint": {
"dependsOn": ["^build"]
},
"test": {
"dependsOn": ["build"]
},
"type-check": {
"dependsOn": ["^build"]
}
}
}
Key insight: "dependsOn": ["^build"] nghĩa là "build dependencies trước". Dấu ^ = upstream packages.
Shared UI package
Đây là phần quan trọng nhất — UI components dùng chung:
// packages/ui/package.json
{
"name": "@myorg/ui",
"version": "0.0.0",
"private": true,
"exports": {
"./button": "./src/button.tsx",
"./card": "./src/card.tsx",
"./input": "./src/input.tsx",
"./globals.css": "./src/globals.css"
}
}
// Sử dụng trong apps/web
import { Button } from "@myorg/ui/button";
import { Card } from "@myorg/ui/card";
Tip: Dùng exports field thay vì barrel file (index.ts) để tree-shaking hoạt động tốt hơn.
CI Pipeline tối ưu
Turborepo tỏa sáng nhất ở CI. Với remote caching, build lần 2 gần như instant:
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm turbo build lint test type-check
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
Turbo chỉ chạy tasks cho packages thực sự thay đổi. PR chỉ sửa apps/docs? Chỉ build + test docs, skip web và admin.
Tips từ thực tế
- Internal packages: Set
"private": true, không cần publish lên npm - TypeScript project references: Dùng composite tsconfig để type-check nhanh hơn
- Shared .env: Đặt ở root, mỗi app có
.env.localriêng - Version management: Dùng Changesets nếu cần publish packages
- Docker builds: Dùng
turbo prune --scope=webđể tạo minimal Docker context
Monorepo không phải silver bullet — nó thêm complexity. Nhưng nếu team đang copy-paste code giữa repos hoặc debug version mismatches, Turborepo sẽ tiết kiệm rất nhiều thời gian.
Admin
Bình luận (0)
Đăng nhập để bình luận
Chưa có bình luận nào. Hãy là người đầu tiên!