วัน: 1 พฤศจิกายน 2020

Node.js: NPM Workspaces (Frontend + Backend )Node.js: NPM Workspaces (Frontend + Backend )

เมื่อโปรเจกต์ของคุณเติบโตขึ้นจนมีทั้งฝั่งหน้าบ้าน และหลังบ้าน การแยก Repository หรือการแยกโฟลเดอร์ออกจากกันโดยเด็ดขาดมักจะสร้างความยุ่งยากในการจัดการ Dependency (เช่น ต้องตามอัปเดตไลบรารีแยกกัน, เสียพื้นที่ดิสก์ซ้ำซ้อน)

NPM Workspaces คือฟีเจอร์ที่ติดมากับ Node.js ตั้งแต่เวอร์ชัน 15+ มันถูกออกแบบมาเพื่อทำ Monorepo ช่วยให้เราสามารถรวมหลายๆ โปรเจกต์ ไว้ภายใต้โฟลเดอร์หลักอันเดียว โดยที่สามารถแชร์ node_modules ร่วมกันได้ และยังคงแยกโค้ดของแต่ละฝั่งได้อย่างเป็นสัดส่วน


🏗️ โครงสร้างโฟลเดอร์หลัก

ก่อนจะเริ่มลงมือทำ ให้วางโครงสร้างโฟลเดอร์ของโปรเจกต์ให้ออกมาในลักษณะนี้

my-monorepo/
├── package.json <-- [Root] จุดควบคุมหลักของทุกโปรเจกต์
├── package-lock.json <-- [Root] มีตัวเดียวควบคุมทั้งระบบ
├── node_modules/ <-- [Root] ที่เก็บ Library ทั้งหมด (แชร์ร่วมกัน) │
├── frontend/ <-- โฟลเดอร์ Frontend (เช่น Vue 3 + Vite) │ ├── package.json 
│ ├── vite.config.ts
│ └── src/
│
└── backend/ <-- โฟลเดอร์ Backend (เช่น Node.js + Express) ├── package.json 
 └── src/

🛠️ ขั้นตอนการตั้งค่าทีละ Step

สร้าง Root Package.json

ให้สร้างโฟลเดอร์หลักนอกสุดขึ้นมา จากนั้นเปิด Terminal ในโฟลเดอร์นี้แล้วสร้างไฟล์ package.json ตัวหลักขึ้นมา และระบุคีย์ "workspaces" ลงไป

{
 "name": "my-monorepo",
 "version": "1.0.0",
 "private": true,
 "workspaces": [
 "frontend",
 "backend"
 ],
 "scripts": {
 "dev:frontend": "npm run dev -w frontend",
 "dev:backend": "npm run dev -w backend",
 "build:all": "npm run build --workspaces"
 }
}

💡 อธิบายคีย์สำคัญ

  • "private": true จำเป็นต้องใส่ เพื่อป้องกันไม่ให้เราเผลอ Publish โฟลเดอร์ Root นี้ขึ้นไปยัง npm registry
  • "workspaces" เป็นการบอก NPM ว่ามีโฟลเดอร์ไหนบ้างที่นับเป็นลูกทีมใน Monorepo นี้

ตั้งค่าในโปรเจกต์ลูก

ย้ายโฟลเดอร์โปรเจกต์ของคุณเข้ามาด้านใน หรือสร้างขึ้นใหม่ โดยที่ใน package.json ของโปรเจกต์ลูก ให้ตั้งชื่อ "name" ให้เป็นเอกลักษณ์

frontend/package.json

{
 "name": "frontend",
 "version": "0.1.0",
 "type": "module",
 "scripts": {
 "dev": "vite",
 "build": "vue-tsc -b && vite build"
 },
 "dependencies": {
 "vue": "^3.5.13",
 "axios": "^1.8.4"
 }
}

backend/package.json

{
 "name": "backend",
 "version": "0.1.0",
 "scripts": {
 "dev": "nodemon src/index.js",
 "start": "node src/index.js"
 },
 "dependencies": {
 "express": "^4.19.2"
 }
}

ลบของเก่าแล้วคลีนระบบ

หากก่อนหน้านี้คุณเคยรัน npm install แยกในโฟลเดอร์ frontend หรือ backend ไปแล้ว ให้ทำการลบโฟลเดอร์ node_modules และ package-lock.json ในโปรเจกต์ลูกออกให้หมด

จากนั้นกลับมาที่โฟลเดอร์นอกสุด แล้วรันคำสั่ง
npm install

NPM จะทำการสแกนดู package.json ของตัวลูกทุกตัว แล้วดึงเอา Dependency ทั้งหมดมารวมกันและติดตั้งไว้ที่ node_modules ของ Root ตัวบนสุดเพียงที่เดียว!


🚀 วิธีการรัน Frontend และ Backend พร้อมกัน

เมื่อเปลี่ยนมาใช้ระบบ Workspaces เราไม่จำเป็นต้องเปิด Terminal หลาย ๆ หน้าต่างแล้วคอย cd เข้าโฟลเดอร์นู้นโฟลเดอร์นี้อีกต่อไป เราสามารถควบคุมทุกอย่างจากโฟลเดอร์นอกสุดได้ทันที


วิธีที่ 1: รันพร้อมกันด้วยคำสั่งเดียว

หากต้องการเปิด Terminal อันเดียวแล้วให้มันรันทั้ง Frontend และ Backend ขึ้นมาพร้อมกันในหน้าจอเดียว เราจะใช้เครื่องมือที่ชื่อว่า concurrently เข้ามาช่วย

  1. ติดตั้ง concurrently ไว้ที่โฟลเดอร์ Root
    npm install concurrently --save-dev
  2. ไปเพิ่ม Script ใน package.json ตัวนอกสุด
    "scripts": {
     "dev:frontend": "npm run dev -w frontend",
     "dev:backend": "npm run dev -w backend",
     "dev": "concurrently \"npm run dev:frontend\" \"npm run dev:backend\""
    }
    
  3. เวลาใช้งานจริง แค่พิมพ์คำสั่งเดียวที่ Root
    npm run dev
    Terminal จะทำการรันทั้งคู่ขึ้นมาพร้อมกัน โดยจะแบ่งสี Log ของหน้าบ้านและหลังบ้านให้เราเห็นอย่างชัดเจนในหน้าต่างเดียว

สั่งรันแยกตัว

หากคุณอยากแยก Terminal คนละหน้าต่างเพื่อดู Log แยกกันชัด ๆ คุณก็ยังสามารถสั่งงานจากโฟลเดอร์ Root ได้โดยใช้ Flag -w

  • เปิด Terminal หน้าต่างที่ 1
    npm run dev -w frontend
  • เปิด Terminal หน้าต่างที่ 2
    npm run dev -w backend

📦 การจัดการ Dependency

เมื่อใช้ Monorepo เวลาจะลง Library เพิ่ม ห้าม cd เข้าไปในโฟลเดอร์ลูกเด็ดขาด ให้ระบุชื่อ Workspace ปลายทางผ่านโฟลเดอร์ Root เสมอ

  • ต้องการลง jsonwebtoken ให้ฝั่ง Backend เท่านั้น
    npm i jsonwebtoken -w backend
  • ต้องการลง primevue ให้ฝั่ง Frontend เท่านั้น
    npm i primevue -w frontend
  • ต้องการลง typescript เป็น Dev Dependency ให้กับทุกโปรเจกต์
    npm i typescript -D

🏆 สรุปข้อดีของ NPM Workspaces

  1. Single Source of Truth: มี package-lock.json เพียงตัวเดียว คุมเวอร์ชันของทั้งระบบ ไม่ต้องกลัวว่าหลังบ้านจะใช้ไลบรารีเวอร์ชันเก่ากว่าหน้าบ้าน
  2. ประหยัดพื้นที่ : หากหน้าบ้านและหลังบ้านใช้ไลบรารีตัวเดียวกัน NPM จะโหลดมาเก็บไว้ที่ Root เพียงครั้งเดียว ไม่โหลดซ้ำซ้อน
  3. Workflow ที่รวดเร็ว: สามารถสั่ง Build, สั่ง Test หรือสั่ง Run ทุกโปรเจกต์ในระบบได้ผ่านคำสั่งเดียวจากจุดศูนย์กลาง

การเปลี่ยนมาใช้ NPM Workspaces ถือเป็นก้าวแรกที่สำคัญในการทำระบบสถาปัตยกรรมแบบ Monorepo ที่ได้มาตรฐาน และช่วยลดปัญหากวนใจในการจัดการ Codebase ของทีมพัฒนาได้อย่างยั่งยืนครับ


อ่านเพิ่มเติม