N

Nokfa Docs

Current: framework-next.js

ไม่มีชื่อบทความ

Best Practice CI ใน Monorepo

TL;DR

  • ใช้ TurboRepo ร่วมกับ pnpm filter เพื่อรันงาน CI แยกส่วน ลด build time
  • ตั้ง GitHub Actions ให้ใช้ matrix สร้างงานแยกตามแอป/แพ็กเกจ พร้อม cache pnpm-store & Turbo cache
  • เพิ่ม status badge ใน README แสดงผลลัพธ์ CI เร็วขึ้นชัดเจน (เช่น จาก 15 → 4 นาที)

1. ปัญหาปัจจุบัน

  • Monorepo ใหญ่ มีหลายแอป/แพ็กเกจ ทำ CI ทีเดียว build ทั้งหมด → ใช้เวลานาน
  • ไม่มีการแยกงานตาม scope → รัน pnpm install + turbo run build ซ้ำหลายครั้ง
  • Cache ไม่ครบถ้วน → ติดตั้ง dependency ใหม่ทุกครั้ง

2. แนวทางปรับปรุงหลัก

  • Matrix Build: แยก CI job ตาม apps/* และ packages/*

  • pnpm filter: ให้แต่ละ job รันเฉพาะ scope ที่ต้องการ

  • Cache:

    • actions/cache สำหรับ ~/.pnpm-store
    • Turbo remote cache หรือ local cache ระหว่าง job
  • Parallelism: รันหลาย job พร้อมกันได้บน GitHub Actions

  • Status Badge: แสดงผลลัพธ์ที่ README เพื่อกระตุ้นทีมเห็นความเร็ว


3. โครงสร้าง Workflow (YAML)

name: CI Monorepo

on:
  push:
    branches: [main, dev]
  pull_request:
    branches: [main, dev]

jobs:
  setup:
    runs-on: ubuntu-latest
    outputs:
      pnpm-cache-key: ${{ steps.cache-pnpm.outputs.cache-hit }}
    steps:
      - uses: actions/checkout@v3

      # Cache pnpm store
      - name: Cache pnpm store
        id: cache-pnpm
        uses: actions/cache@v3
        with:
          path: ~/.pnpm-store
          key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
          restore-keys: pnpm-store-${{ runner.os }}-

      # Setup Node.js + pnpm
      - name: Setup Node.js & pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 18
          run_install: false

      - name: Install dependencies
        run: |
          $ pnpm install --frozen-lockfile --store-dir ~/.pnpm-store

  build:
    needs: setup
    runs-on: ubuntu-latest
    strategy:
      matrix:
        scope: [apps/web, apps/admin-dashboard, packages/ui-kit]
    steps:
      - uses: actions/checkout@v3

      # Restore pnpm store cache
      - name: Restore pnpm store
        uses: actions/cache@v3
        with:
          path: ~/.pnpm-store
          key: pnpm-store-${{ runner.os }}-${{ needs.setup.outputs.pnpm-cache-key }}

      - name: Setup Node.js & pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 18
          run_install: false

      - name: Install dependencies
        run: |
          $ pnpm install --frozen-lockfile --store-dir ~/.pnpm-store

      - name: Run build for ${{ matrix.scope }}
        run: |
          $ pnpm --filter ${{ matrix.scope }} build

4. ตัวอย่าง Matrix

scope คำสั่งรัน
apps/web $ pnpm --filter apps/web build
apps/admin-dashboard $ pnpm --filter apps/admin-dashboard build
packages/ui-kit $ pnpm --filter packages/ui-kit build
  • ประโยชน์:

    • Build เฉพาะส่วนที่เปลี่ยนหรือสำคัญ
    • Parallel run → ใช้เวลารวมสั้นลง
    • ง่ายต่อการ debug job ที่ล้ม

5. Cache pnpm Store & Turbo

5.1 pnpm store

  • เก็บใน ~/.pnpm-store
  • Cache ด้วย actions/cache ตาม pnpm-lock.yaml

5.2 TurboCache

  • เปิด Remote Cache (เช่นบน S3) หรือใช้ Local Disk

  • ใน turbo.json ตั้งค่า:

    {
      "pipeline": {
        "build": {
          "dependsOn": ["^build"],
          "outputs": [".next/**", "dist/**"]
        }
      },
      "remoteCache": {
        "enabled": true,
        "url": "https://<turbo-cache-endpoint>"
      }
    }
    
  • เพิ่ม step ใน CI:

    - name: Restore Turbo Cache
      uses: turborepo/action@v1
      with:
        command: remote-restore
    
    - name: Save Turbo Cache
      uses: turborepo/action@v1
      with:
        command: remote-store
    

6. Status Badge

เพิ่มใน README.md:

![CI Status](https://github.com/your-org/nokfa-monorepo/actions/workflows/ci.yml/badge.svg)
  • แสดงผลแบบ real-time
  • กระตุ้นทีมเห็นการปรับปรุง build time

7. ตารางเปรียบเทียบ Build Time (Speed-up)

Scenario Before (monolithic) After (matrix + cache) Speed-up
ติดตั้ง dependency + build 15 min 4 min 3.75×
Build apps/web 1.5 min
Build apps/admin-dashboard 1.2 min
Build packages/ui-kit 0.8 min
Full CI total (parallel jobs) 15 min 2 min 7.5×

หมายเหตุ: เวลาในตารางเป็นตัวอย่าง เบื้องต้นทดสอบบน GitHub-hosted runners


8. Tips & Best Practices

  • ✅ ใช้ --frozen-lockfile ป้องกันเปลี่ยน lockfile โดยไม่ตั้งใจ

  • ✅ รัน lint และ test แยกตาม scope ได้เช่นกัน:

    - name: Run lint
      run: pnpm --filter ${{ matrix.scope }} lint
    - name: Run tests
      run: pnpm --filter ${{ matrix.scope }} test
    
  • ✅ กำหนด timeout ให้แต่ละ job ไม่เกิน 10 นาที

  • ✅ ใช้ artifact เก็บผลลัพธ์หากต้อง debug


9. สรุป

  • แยก CI job ตาม scope → ลดงาน build ที่ไม่จำเป็น
  • Cache pnpm store + Turbo → ลดเวลาติดตั้งและ build ซ้ำ
  • Matrix build → parallelism ชัดเจน
  • Status badge + ตาราง speed-up → แสดงผลลัพธ์ทีมมองเห็นได้ง่าย

หลังปรับแล้ว Dev สามารถ merge PR ได้เร็วขึ้น ลด waiting time ของทีม Nokfa เหลือไม่กี่นาที!