ข้ามไปเนื้อหาหลัก

Category: reference

npm Workspaces & Monorepo Basics

จัดการ multiple packages ใน repo เดียวด้วย npm workspaces — shared dependencies, cross-package scripts, และ monorepo patterns

· อ่านประมาณ 3 นาที

สารบัญ

npm Workspaces คืออะไร

npm Workspaces ให้จัดการหลาย packages ใน repository เดียวได้ — แชร์ node_modules ร่วมกัน, import กันได้โดยไม่ต้อง publish, และ run scripts ใน workspace ทั้งหมดด้วยคำสั่งเดียว

my-monorepo/
├── package.json          ← root (workspace root)
├── node_modules/         ← shared (symlinks จาก packages/)
├── packages/
│   ├── core/             ← @myapp/core
│   │   ├── package.json
│   │   └── src/
│   ├── ui/               ← @myapp/ui
│   │   ├── package.json
│   │   └── src/
│   └── cli/              ← @myapp/cli
│       ├── package.json
│       └── src/
└── apps/
    └── web/              ← main app (ใช้ packages ข้างบน)
        ├── package.json
        └── src/

Setup

// package.json (root)
{
  "name": "my-monorepo",
  "private": true,
  "workspaces": [
    "packages/*",
    "apps/*"
  ],
  "scripts": {
    "build": "npm run build --workspaces --if-present",
    "test": "npm test --workspaces --if-present",
    "lint": "npm run lint --workspaces --if-present"
  }
}
# ติดตั้ง dependencies ทั้งหมดจาก root
npm install

# npm จะสร้าง symlinks ใน node_modules/ สำหรับแต่ละ workspace
# packages/core → node_modules/@myapp/core

Package Names ใน Workspace

// packages/core/package.json
{
  "name": "@myapp/core",
  "version": "1.0.0",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js",
      "types": "./dist/index.d.ts"
    }
  },
  "scripts": {
    "build": "tsc",
    "dev": "tsc --watch"
  }
}
// apps/web/package.json
{
  "name": "@myapp/web",
  "dependencies": {
    "@myapp/core": "*",    // ✓ ใช้ * เพื่อ reference workspace package
    "@myapp/ui": "*"
  }
}

Install Dependencies

# ติดตั้ง dependency ใน workspace เฉพาะ
npm install lodash --workspace=packages/core

# ติดตั้ง dev dependency ที่ root (shared across all)
npm install --save-dev typescript --workspace=.

# ติดตั้ง package อื่นใน workspace เป็น dependency
npm install @myapp/core --workspace=apps/web

Run Scripts

# รัน script ใน workspace เดียว
npm run build --workspace=packages/core

# รันใน workspaces หลายตัว
npm run build --workspace=packages/core --workspace=packages/ui

# รันใน workspace ที่มี script นั้น (ข้ามถ้าไม่มี)
npm run build --workspaces --if-present

# รันตามลำดับ (default: parallel)
npm run build --workspaces --if-present --foreground-scripts

Shared TypeScript Config

// tsconfig.base.json (root)
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  }
}
// packages/core/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src"]
}

TypeScript Project References

Project references ทำให้ TypeScript รู้ว่า packages ไหน depend on กัน → incremental build เร็วขึ้น

// tsconfig.json (root)
{
  "files": [],
  "references": [
    { "path": "./packages/core" },
    { "path": "./packages/ui" },
    { "path": "./apps/web" }
  ]
}
// apps/web/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist",
    "composite": true
  },
  "references": [
    { "path": "../../packages/core" },
    { "path": "../../packages/ui" }
  ]
}
# Build แบบ incremental (เฉพาะส่วนที่เปลี่ยน)
tsc --build

# Build ทั้งหมด
tsc --build --force

# Watch mode แบบ project references
tsc --build --watch

Shared ESLint Config ใน Monorepo

// eslint.config.js (root)
export default [
  { ignores: ['**/dist/**', '**/node_modules/**'] },
  // shared rules สำหรับ TS files
];
// packages/core/package.json
{
  "scripts": {
    "lint": "eslint --config ../../eslint.config.js src"
  }
}

เปรียบเทียบกับ Tools อื่น

npm workspacespnpm workspacesTurborepo
Built-in✓ ไม่ต้องติดตั้งเพิ่ม✗ ติดตั้ง pnpm✗ ติดตั้ง turbo
Speedดีเร็วกว่า (hard links)ดีที่สุด (caching)
Task runningพื้นฐานพื้นฐานซับซ้อน แต่ parallel + cache
เหมาะกับproject ขนาดกลางmonorepo จริงจังlarge-scale

สำหรับโปรเจกต์ส่วนตัว npm workspaces เพียงพอ — ไม่ต้องเพิ่ม complexity ของ pnpm หรือ Turborepo