🎯 empfohlene Sammlungen
Balanced sample collections from various categories for you to explore
Turbo Monorepo Beispiele
Turbo Monorepo Build-System Beispiele inklusive Workspace-Konfiguration, Task-Orchestrierung, und Caching-Strategien
💻 Turbo Monorepo Basic Setup json
🟢 simple
⭐⭐
Vollständige Turbo Monorepo-Konfiguration mit mehreren Anwendungen und Paketen
⏱️ 20 min
🏷️ turbo, monorepo, setup
Prerequisites:
Node.js, pnpm/yarn/npm, TypeScript
// Turbo Monorepo Basic Setup
// 1. Installation
// npm install turbo --save-dev
// or: pnpm add -D turbo
// or: yarn add -D turbo
// 2. package.json (Root)
{
"name": "my-turbo-monorepo",
"private": true,
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint",
"test": "turbo run test",
"clean": "turbo run clean && rm -rf node_modules",
"format": "prettier --write "**/*.{ts,tsx,md}"",
"changeset": "changeset",
"version-packages": "changeset version",
"release": "turbo run build --filter=!@repo/docs && changeset publish"
},
"devDependencies": {
"turbo": "^2.0.0",
"prettier": "^3.0.0",
"changesets": "^2.26.0"
},
"packageManager": "[email protected]"
}
// 3. turbo.json - Root configuration
{
"$schema": "https://turbo.build/schema.json",
"globalEnv": [
"NODE_ENV",
"NEXT_PUBLIC_API_URL",
"DATABASE_URL"
],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**", "dist/**", "!.next/**/(!*.next)"]
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts", "test/**/*.tsx"]
},
"lint": {
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
},
"clean": {
"cache": false
},
"type-check": {
"dependsOn": ["^build"]
},
"format": {
"outputs": []
}
},
"globalDependencies": [
"**/.env.*local",
"turbo.json",
"package.json",
"pnpm-lock.yaml",
"yarn.lock",
"npm-shrinkwrap.json"
]
}
// 4. Project structure
/*
my-turbo-monorepo/
├── apps/
│ ├── web/ # Next.js frontend application
│ │ ├── package.json
│ │ ├── next.config.js
│ │ └── turbo.json
│ ├── api/ # Backend API (Express/Fastify)
│ │ ├── package.json
│ │ └── turbo.json
│ └── docs/ # Documentation site
│ ├── package.json
│ └── turbo.json
├── packages/
│ ├── ui/ # Shared UI components
│ │ ├── package.json
│ │ ├── turbo.json
│ │ └── src/
│ ├── utils/ # Shared utilities
│ │ ├── package.json
│ │ ├── turbo.json
│ │ └── src/
│ ├── config/ # Shared configuration
│ │ ├── package.json
│ │ ├── eslint.config.js
│ │ ├── tsconfig.base.json
│ │ └── turbo.json
│ └── types/ # Shared TypeScript types
│ ├── package.json
│ ├── turbo.json
│ └── src/
├── package.json
├── turbo.json
├── pnpm-workspace.yaml
└── .gitignore
*/
// 5. pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
// 6. Example app configuration (apps/web/turbo.json)
{
"extends": ["//"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**"]
},
"dev": {
"cache": false,
"persistent": true
},
"lint": {},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"]
}
}
}
// 7. Example package configuration (packages/ui/turbo.json)
{
"extends": ["//"],
"pipeline": {
"build": {
"outputs": ["dist/**"]
},
"lint": {},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"]
}
}
}
// 8. TypeScript configuration (packages/config/tsconfig.base.json)
{
"compilerOptions": {
"target": "ES2022",
"lib": ["dom", "dom.iterable", "ES2022"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "ESNext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"baseUrl": ".",
"paths": {
"@repo/ui": ["../../packages/ui/src"],
"@repo/utils": ["../../packages/utils/src"],
"@repo/types": ["../../packages/types/src"],
"@repo/config/*": ["./"]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": ["node_modules"]
}
// 9. Environment variables (.env.example)
# Database
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
# API
NEXT_PUBLIC_API_URL="http://localhost:3001/api"
# Authentication
NEXTAUTH_URL="http://localhost:3000"
NEXTAUTH_SECRET="your-secret-key"
# External services
REDIS_URL="redis://localhost:6379"
STRIPE_API_KEY="sk_test_..."
SENTRY_DSN="https://your-sentry-dsn"
💻 Turbo Multi-Application Workspace typescript
🟡 intermediate
⭐⭐⭐⭐
Fortgeschrittene Monorepo-Setup mit Next.js Frontend, Express Backend, und geteilten Paketen
⏱️ 35 min
🏷️ turbo, monorepo, nextjs, express
Prerequisites:
Turbo basics, Next.js, Express, TypeScript
// Turbo Multi-Application Workspace Example
// 1. Next.js Application (apps/web/package.json)
{
"name": "@repo/web",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "jest",
"type-check": "tsc --noEmit"
},
"dependencies": {
"next": "^14.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@repo/ui": "workspace:*",
"@repo/utils": "workspace:*",
"@repo/types": "workspace:*",
"axios": "^1.6.0",
"next-auth": "^4.24.0"
},
"devDependencies": {
"@repo/config/eslint": "workspace:*",
"@repo/config/typescript": "workspace:*",
"@types/node": "^20.0.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.0",
"tailwindcss": "^3.3.0",
"typescript": "^5.3.0"
}
}
// 2. Next.js Configuration (apps/web/next.config.js)
const withTM = require('next-transpile-modules')([
'@repo/ui',
'@repo/utils',
'@repo/types'
])
/** @type {import('next').NextConfig} */
const nextConfig = {
transpilePackages: ['@repo/ui', '@repo/utils', '@repo/types'],
experimental: {
optimizePackageImports: ['@repo/ui']
},
images: {
domains: ['example.com', 'images.unsplash.com']
},
env: {
CUSTOM_KEY: process.env.CUSTOM_KEY
}
}
module.exports = nextConfig
// 3. Express Backend Application (apps/api/package.json)
{
"name": "@repo/api",
"version": "0.1.0",
"private": true,
"main": "dist/index.js",
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"lint": "eslint src --max-warnings 0",
"test": "jest",
"type-check": "tsc --noEmit"
},
"dependencies": {
"express": "^4.18.0",
"cors": "^2.8.0",
"helmet": "^7.1.0",
"compression": "^1.7.0",
"morgan": "^1.10.0",
"@repo/utils": "workspace:*",
"@repo/types": "workspace:*",
"zod": "^3.22.0",
"prisma": "^5.6.0"
},
"devDependencies": {
"@repo/config/eslint": "workspace:*",
"@repo/config/typescript": "workspace:*",
"@types/express": "^4.17.0",
"@types/cors": "^2.8.0",
"@types/compression": "^1.7.0",
"@types/morgan": "^1.9.0",
"tsx": "^4.6.0",
"typescript": "^5.3.0"
}
}
// 4. Express Application (apps/api/src/index.ts)
import express from 'express'
import cors from 'cors'
import helmet from 'helmet'
import compression from 'compression'
import morgan from 'morgan'
import { logger } from '@repo/utils/logger'
import { ApiResponse } from '@repo/types/api'
const app = express()
const PORT = process.env.PORT || 3001
// Middleware
app.use(helmet())
app.use(compression())
app.use(cors({
origin: process.env.FRONTEND_URL || 'http://localhost:3000',
credentials: true
}))
app.use(morgan('combined'))
app.use(express.json({ limit: '10mb' }))
app.use(express.urlencoded({ extended: true }))
// Health check endpoint
app.get('/health', (req, res): ApiResponse => {
return res.json({
success: true,
message: 'API is healthy',
timestamp: new Date().toISOString()
})
})
// API routes
app.get('/api/users', async (req, res) => {
try {
// Simulate database call
const users = [
{ id: 1, name: 'John Doe', email: '[email protected]' },
{ id: 2, name: 'Jane Smith', email: '[email protected]' }
]
return res.json({
success: true,
data: users,
count: users.length
})
} catch (error) {
logger.error('Error fetching users:', error)
return res.status(500).json({
success: false,
message: 'Internal server error'
})
}
})
// Error handling middleware
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.error('Unhandled error:', err)
return res.status(500).json({
success: false,
message: 'Internal server error'
})
})
app.listen(PORT, () => {
logger.info(`API server running on port ${PORT}`)
})
export default app
// 5. Shared UI Components Package (packages/ui/package.json)
{
"name": "@repo/ui",
"version": "0.1.0",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"./styles.css": "./dist/styles.css"
},
"files": ["dist"],
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"lint": "eslint src --max-warnings 0",
"test": "jest",
"type-check": "tsc --noEmit",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"clsx": "^2.0.0",
"tailwind-merge": "^2.0.0",
"@repo/types": "workspace:*"
},
"devDependencies": {
"@repo/config/eslint": "workspace:*",
"@repo/config/typescript": "workspace:*",
"@storybook/addon-essentials": "^7.5.0",
"@storybook/react": "^7.5.0",
"@storybook/react-vite": "^7.5.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.0",
"tailwindcss": "^3.3.0",
"tsup": "^7.2.0",
"typescript": "^5.3.0"
},
"peerDependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
// 6. UI Components Build Configuration (packages/ui/tsup.config.ts)
import { defineConfig } from 'tsup'
export default defineConfig({
entry: ['src/index.ts'],
format: ['cjs', 'esm'],
dts: true,
splitting: false,
sourcemap: true,
clean: true,
external: ['react', 'react-dom'],
onSuccess: 'npm run build:css'
})
// 7. Shared Components (packages/ui/src/Button.tsx)
import React from 'react'
import { clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'outline'
size?: 'sm' | 'md' | 'lg'
loading?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant = 'primary', size = 'md', loading, children, disabled, ...props }, ref) => {
const baseStyles = 'inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2'
const variants = {
primary: 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500',
secondary: 'bg-gray-600 text-white hover:bg-gray-700 focus:ring-gray-500',
outline: 'border border-gray-300 bg-white text-gray-700 hover:bg-gray-50 focus:ring-blue-500'
}
const sizes = {
sm: 'px-3 py-1.5 text-sm',
md: 'px-4 py-2 text-sm',
lg: 'px-6 py-3 text-base'
}
return (
<button
className={clsx(
baseStyles,
variants[variant],
sizes[size],
(loading || disabled) && 'opacity-50 cursor-not-allowed',
className
)}
disabled={loading || disabled}
ref={ref}
{...props}
>
{loading && (
<svg className="animate-spin -ml-1 mr-2 h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
)}
{children}
</button>
)
}
)
Button.displayName = 'Button'
export { Button }
// 8. Shared Utilities Package (packages/utils/src/logger.ts)
export type LogLevel = 'debug' | 'info' | 'warn' | 'error'
export interface LogEntry {
level: LogLevel
message: string
timestamp: Date
metadata?: Record<string, any>
}
export class Logger {
private level: LogLevel = 'info'
setLevel(level: LogLevel) {
this.level = level
}
private shouldLog(level: LogLevel): boolean {
const levels: Record<LogLevel, number> = {
debug: 0,
info: 1,
warn: 2,
error: 3
}
return levels[level] >= levels[this.level]
}
private log(level: LogLevel, message: string, metadata?: Record<string, any>) {
if (!this.shouldLog(level)) return
const entry: LogEntry = {
level,
message,
timestamp: new Date(),
metadata
}
if (process.env.NODE_ENV === 'development') {
console[level](message, metadata || '')
} else {
// In production, you might want to send logs to a service
console.log(JSON.stringify(entry))
}
}
debug(message: string, metadata?: Record<string, any>) {
this.log('debug', message, metadata)
}
info(message: string, metadata?: Record<string, any>) {
this.log('info', message, metadata)
}
warn(message: string, metadata?: Record<string, any>) {
this.log('warn', message, metadata)
}
error(message: string, metadata?: Record<string, any>) {
this.log('error', message, metadata)
}
}
export const logger = new Logger()
// 9. Shared Types (packages/types/src/api.ts)
export interface ApiResponse<T = any> {
success: boolean
data?: T
message?: string
error?: string
timestamp?: string
}
export interface PaginatedResponse<T> extends ApiResponse<T[]> {
pagination: {
page: number
limit: number
total: number
totalPages: number
}
}
export interface ApiError {
code: string
message: string
field?: string
}
// 10. Shared Types (packages/types/src/user.ts)
export interface User {
id: number
name: string
email: string
avatar?: string
role: UserRole
createdAt: string
updatedAt: string
}
export type UserRole = 'admin' | 'user' | 'moderator'
export interface CreateUserRequest {
name: string
email: string
role?: UserRole
}
export interface UpdateUserRequest {
name?: string
email?: string
role?: UserRole
}
💻 Turbo Advanced Workflows yaml
🔴 complex
⭐⭐⭐⭐⭐
Fortgeschrittene Turbo-Workflows inklusive Caching, Filtering, Deployment, und CI/CD-Integration
⏱️ 45 min
🏷️ turbo, ci/cd, deployment, advanced
Prerequisites:
Advanced Turbo, Docker, GitHub Actions, CI/CD
// Turbo Advanced Workflows and CI/CD
// 1. Advanced turbo.json with complex dependencies
{
"$schema": "https://turbo.build/schema.json",
"globalEnv": [
"NODE_ENV",
"NEXT_PUBLIC_API_URL",
"DATABASE_URL",
"STRIPE_API_KEY",
"SENTRY_DSN"
],
"globalPassThroughEnv": [
"VERCEL_*",
"AWS_*",
"GITHUB_*"
],
"pipeline": {
"build": {
"dependsOn": ["^build", "^db:generate"],
"outputs": [
"dist/**",
".next/**",
"!.next/cache/**",
"!.next/**/(!*.next)",
"public/build/**"
],
"env": ["NODE_ENV", "NEXT_PUBLIC_API_URL"],
"inputs": ["src/**/*.tsx", "src/**/*.ts", "package.json"]
},
"db:generate": {
"outputs": ["prisma/migrations/**", "node_modules/.prisma/**"],
"inputs": ["prisma/schema.prisma", "package.json"]
},
"db:push": {
"cache": false,
"outputs": ["prisma/migrations/**"]
},
"db:migrate": {
"cache": false,
"outputs": ["prisma/migrations/**"]
},
"test": {
"dependsOn": ["build", "db:generate"],
"outputs": ["coverage/**", "test-results/**"],
"inputs": [
"src/**/*.tsx",
"src/**/*.ts",
"test/**/*.ts",
"test/**/*.tsx",
"jest.config.*"
],
"passThroughEnv": ["CI"]
},
"test:watch": {
"cache": false,
"persistent": true,
"dependsOn": ["build"]
},
"lint": {
"outputs": [],
"inputs": ["src/**/*.tsx", "src/**/*.ts", "*.config.*"]
},
"lint:fix": {
"cache": false,
"outputs": []
},
"type-check": {
"dependsOn": ["^build"],
"outputs": []
},
"dev": {
"cache": false,
"persistent": true,
"dependsOn": ["db:generate"]
},
"clean": {
"cache": false,
"outputs": []
},
"format": {
"outputs": [],
"inputs": [
"**/*.{ts,tsx,js,jsx,json,md,css,scss}",
".prettierrc*"
]
},
"storybook": {
"cache": false,
"persistent": true,
"dependsOn": ["build"]
},
"build-storybook": {
"dependsOn": ["build"],
"outputs": ["storybook-static/**"]
},
"deploy": {
"dependsOn": ["build", "test", "lint"],
"cache": false
},
"size-limit": {
"dependsOn": ["build"],
"outputs": []
},
"bundlesize": {
"dependsOn": ["build"],
"outputs": []
}
}
}
// 2. GitHub Actions Workflow (.github/workflows/ci.yml)
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
NODE_VERSION: 20
PNPM_VERSION: 8
jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ env.STORE_PATH }}
key: pnpm-store-${{ runner.os }}-${{ matrix.node-version }}-${{ env.PNPM_VERSION }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
pnpm-store-${{ runner.os }}-${{ matrix.node-version }}-${{ env.PNPM_VERSION }}-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Generate database schema
run: pnpm db:generate
- name: Run type checking
run: pnpm type-check
- name: Run linting
run: pnpm lint
- name: Run tests
run: pnpm test --coverage
- name: Build packages and apps
run: pnpm build
- name: Check bundle sizes
run: pnpm size-limit
- name: Upload coverage reports
uses: codecov/codecov-action@v3
with:
file: ./coverage/lcov.info
flags: unittests
name: codecov-umbrella
lint-pr:
name: Lint Pull Request
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run changesets
uses: changesets/action@v1
with:
publish: pnpm changeset publish
commit: 'chore: release packages'
title: 'chore: release packages'
// 3. Deployment Script (scripts/deploy.sh)
#!/bin/bash
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Configuration
ENVIRONMENT=${1:-production}
APP_NAME="my-turbo-app"
echo -e "${GREEN}Starting deployment of ${APP_NAME} to ${ENVIRONMENT}${NC}"
# Step 1: Run tests
echo -e "${YELLOW}Running tests...${NC}"
pnpm test
echo -e "${GREEN}✓ Tests passed${NC}"
# Step 2: Build all packages
echo -e "${YELLOW}Building packages...${NC}"
pnpm build
echo -e "${GREEN}✓ Build completed${NC}"
# Step 3: Deploy based on environment
case ${ENVIRONMENT} in
"production")
echo -e "${YELLOW}Deploying to production...${NC}"
# Deploy web app to Vercel
echo "Deploying web app to Vercel..."
cd apps/web
npx vercel --prod --token $VERCEL_TOKEN
cd ../..
# Deploy API to Railway/Heroku
echo "Deploying API to production..."
cd apps/api
# Railway deployment
railway deploy
cd ../..
echo -e "${GREEN}✓ Production deployment completed${NC}"
;;
"staging")
echo -e "${YELLOW}Deploying to staging...${NC}"
# Deploy web app to Vercel preview
cd apps/web
npx vercel --token $VERCEL_TOKEN
cd ../..
# Deploy API to staging
cd apps/api
# Staging deployment
docker build -t ${APP_NAME}-api:staging .
docker push ${DOCKER_REGISTRY}/${APP_NAME}-api:staging
cd ../..
echo -e "${GREEN}✓ Staging deployment completed${NC}"
;;
*)
echo -e "${RED}Unknown environment: ${ENVIRONMENT}${NC}"
exit 1
;;
esac
echo -e "${GREEN}🚀 Deployment completed successfully!${NC}"
// 4. Docker Compose for Development (docker-compose.dev.yml)
version: '3.8'
services:
postgres:
image: postgres:15
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: myapp_dev
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
minio:
image: minio/minio:latest
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin123
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/data
api:
build:
context: .
dockerfile: apps/api/Dockerfile.dev
ports:
- "3001:3001"
environment:
NODE_ENV: development
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/myapp_dev
REDIS_URL: redis://redis:6379
depends_on:
- postgres
- redis
volumes:
- ./apps/api:/app/apps/api
- ./packages:/app/packages
- /app/node_modules
web:
build:
context: .
dockerfile: apps/web/Dockerfile.dev
ports:
- "3000:3000"
environment:
NODE_ENV: development
NEXT_PUBLIC_API_URL: http://localhost:3001
depends_on:
- api
volumes:
- ./apps/web:/app/apps/web
- ./packages:/app/packages
- /app/node_modules
volumes:
postgres_data:
redis_data:
minio_data:
// 5. API Dockerfile for Development (apps/api/Dockerfile.dev)
FROM node:20-alpine
WORKDIR /app
# Copy package files
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY apps/api/package.json ./apps/api/
COPY packages/*/package.json ./packages/*/
# Install pnpm
RUN npm install -g pnpm
# Install dependencies
RUN pnpm install --frozen-lockfile
# Copy source code
COPY apps/api ./apps/api
COPY packages ./packages
# Generate Prisma client
RUN pnpm db:generate
EXPOSE 3001
CMD ["pnpm", "dev"]
// 6. Web Dockerfile for Development (apps/web/Dockerfile.dev)
FROM node:20-alpine
WORKDIR /app
# Copy package files
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY apps/web/package.json ./apps/web/
COPY packages/*/package.json ./packages/*/
# Install pnpm
RUN npm install -g pnpm
# Install dependencies
RUN pnpm install --frozen-lockfile
# Copy source code
COPY apps/web ./apps/web
COPY packages ./packages
EXPOSE 3000
CMD ["pnpm", "dev"]
// 7. Size Limit Configuration (size-limit.json)
[
{
"name": "Web App Bundle",
"path": "apps/web/.next/static/chunks/**/*.js",
"limit": "1 MB",
"ignore": [
"**/node_modules/**"
]
},
{
"name": "API Bundle",
"path": "apps/api/dist/**/*.js",
"limit": "500 KB"
},
{
"name": "UI Components",
"path": "packages/ui/dist/**/*.js",
"limit": "100 KB"
},
{
"name": "Utils Package",
"path": "packages/utils/dist/**/*.js",
"limit": "50 KB"
}
]
// 8. Advanced Package Scripts
{
"scripts": {
// Development workflows
"dev:all": "concurrently "pnpm dev:web" "pnpm dev:api" "pnpm dev:storybook"",
"dev:web": "turbo run dev --filter=@repo/web",
"dev:api": "turbo run dev --filter=@repo/api",
"dev:storybook": "turbo run storybook --filter=@repo/ui",
// Build workflows
"build:affected": "turbo run build --filter='...[origin/HEAD]'",
"build:web": "turbo run build --filter=@repo/web",
"build:api": "turbo run build --filter=@repo/api",
// Test workflows
"test:affected": "turbo run test --filter='...[origin/HEAD]'",
"test:ci": "turbo run test --concurrency=1",
"test:coverage": "turbo run test -- --coverage",
// Quality assurance
"lint:affected": "turbo run lint --filter='...[origin/HEAD]'",
"type-check:affected": "turbo run type-check --filter='...[origin/HEAD]'",
"quality-check": "pnpm lint && pnpm type-check && pnpm test && pnpm build",
// Database workflows
"db:generate": "turbo run db:generate",
"db:push": "turbo run db:push",
"db:migrate": "turbo run db:migrate",
"db:reset": "pnpm db:push --force-reset",
// Package management
"clean": "turbo run clean && rm -rf node_modules",
"reinstall": "pnpm clean && pnpm install",
"update": "pnpm update -i -r && pnpm install",
// Release workflows
"changeset": "changeset",
"version": "changeset version",
"release": "pnpm build && pnpm test && changeset publish",
// Deployment workflows
"deploy:staging": "./scripts/deploy.sh staging",
"deploy:production": "./scripts/deploy.sh production",
// Performance monitoring
"size-limit": "size-limit",
"bundle-analyzer": "turbo run build --filter=@repo/web && npx @next/bundle-analyzer apps/web/.next"
}
}