จัดระเบียบโปรเจกต์ด้วย pnpm workspace + Turborepo
วิธีแบ่ง apps / packages ของ monorepo ให้รันเร็วและ deploy สบาย พร้อม pattern ที่ใช้ได้จริงในปี 2025
เมื่อโปรเจกต์มี website, mobile app, shared utility ไปจนถึง CMS อยู่ใน repo เดียวกัน การจัดระเบียบให้ build เร็วและดูแลรักษาง่ายเป็นเรื่องสำคัญ บทความนี้เล่าประสบการณ์การใช้ pnpm workspace คู่กับ Turborepo ในโปรเจกต์จริง
ทำไมต้อง monorepo
ข้อดีหลักของ monorepo คือแบ่ง code เป็น package เล็ก ๆ ที่ reuse ได้ — เช่น schema ของ Sanity, utility function, UI component library — โดย apps หลายตัวใช้ package เดียวกันได้โดยไม่ต้อง publish เป็น npm package จริง
ข้อดีในทางปฏิบัติ
เปลี่ยน shared utility ครั้งเดียว ทุก app ได้ประโยชน์ทันที ไม่ต้อง publish + wait + update dependency แยก ๆ ให้ทุก app เหมาะกับทีมที่ต้องการ iterate เร็ว ส่วนข้อเสียคือ CI ต้องฉลาด — ไม่งั้น build ทุก app แม้เปลี่ยน 1 ไฟล์
pnpm workspace
pnpm workspace ใช้ไฟล์ pnpm-workspace.yaml ระบุว่า package ใดบ้างอยู่ใน workspace ข้อดีของ pnpm เทียบกับ npm/yarn คือใช้ hard link ทำให้ disk space น้อยกว่าเยอะ และ install เร็วขึ้น 2-3 เท่า
โครงสร้างทั่วไปคือ apps/* สำหรับแอปที่ deploy จริง และ packages/* สำหรับ library ภายใน apps ต่าง ๆ depend บน packages ผ่าน workspace:* protocol ซึ่ง pnpm จะ resolve ให้เป็น symlink ภายใน repo
Turborepo: cache แบบฉลาด
Turborepo เป็น task runner ที่เข้าใจ dependency graph ของ monorepo รู้ว่าถ้า package A เปลี่ยน ต้อง rebuild package B,C ที่ depend ด้วย — ถ้าไม่เปลี่ยน ก็ใช้ cache เดิมได้เลย
จาก build 2 นาที เหลือ 10 วินาที — cache ช่วยชีวิตเวลา CI วันละหลายครั้ง
Remote cache
Turborepo รองรับ remote cache ฝาก artifact ไว้บน Vercel, S3 หรือ self-host ของตัวเอง ทำให้ทีมหลายคน share cache กันได้ — pull request ของเพื่อน build ครั้งเดียว คุณ pull มา run ต่อได้เลย ไม่ต้อง build ใหม่
Pattern ที่ใช้งานได้จริง
1. Shared config
ใส่ tsconfig, eslint, prettier ใน packages/config แล้ว extend จาก app ต่าง ๆ ทำให้เปลี่ยน convention ครั้งเดียวได้ทั้ง repo
2. Public vs private package
แต่ละ package ระบุ name เป็น @workspacename/package ชัดเจน เช่น @sinananr/sanity, @sinananr/ui ทำให้ import path อ่านง่าย และ refactor หาได้ง่ายเวลา search
3. Turbo pipeline
ตั้ง turbo.json ให้มี task build, dev, typecheck, lint โดยระบุ dependsOn เช่น build depends on ^build (หมายถึง build dependencies ก่อน) ทำให้ order ถูกต้องเสมอ
ข้อควรระวัง
อย่าแบ่ง package มากเกินไปตั้งแต่แรก เริ่มจาก monorepo ที่มีแค่ 2-3 package แล้วค่อย extract shared code ออกเมื่อเห็น pattern ชัด ถ้าแบ่งเร็วเกินไปจะเจอปัญหา abstraction ที่ผิดแล้ว refactor ลำบาก
สรุป
pnpm + Turborepo เป็นคู่ที่ลงตัวสำหรับ monorepo สมัยใหม่ ติดตั้งใน 10 นาที เห็นประโยชน์ทันทีเมื่อโปรเจกต์โต ไม่ต้องเขียน build script เองไม่ต้องจัดการ dependency graph เอง — ปล่อยให้ tool ทำให้