ไม่มีชื่อบทความ
โครงสร้างโฟลเดอร์ Monorepo ของ Nokfa
เอกสารนี้อธิบายภาพรวมโครงสร้าง Monorepo ของบริษัท Nokfa ประกอบด้วยโฟลเดอร์หลัก apps สำหรับแอปพลิเคชัน, packages สำหรับไลบรารีที่แชร์, และ config สำหรับการตั้งค่ากลางต่างๆ
1. ภาพรวมโครงสร้าง (ASCII Diagram)
/
├── apps/
│ ├── web/
│ │ ├── app/
│ │ │ ├── page.tsx
│ │ │ └── layout.tsx
│ │ ├── public/
│ │ ├── next.config.js
│ │ └── package.json
│ └── admin-dashboard/
│ ├── app/
│ │ ├── page.tsx
│ │ └── layout.tsx
│ ├── public/
│ ├── next.config.js
│ └── package.json
│
├── packages/
│ ├── ui/
│ │ ├── src/
│ │ │ ├── Button.tsx
│ │ │ └── Card.tsx
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── utils/
│ │ ├── src/
│ │ │ ├── date.ts
│ │ │ └── fetcher.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ └── data-access/
│ ├── src/
│ │ ├── firestore.ts
│ │ └── auth.ts
│ ├── package.json
│ └── tsconfig.json
│
├── config/
│ ├── eslint/
│ │ └── .eslintrc.js
│ ├── prettier/
│ │ └── .prettierrc.js
│ ├── tsconfig.base.json
│ └── turbo.json
│
├── package.json
├── pnpm-workspace.yaml
└── README.md
2. โฟลเดอร์ apps/
วัตถุประสงค์: เก็บแอปพลิเคชันจริงที่ deploy ไปยัง Vercel
แต่ละโฟลเดอร์ภายใน
appsเป็น Next.js App Router instanceโครงสร้างภายในแต่ละแอป:
app/– โค้ดหน้าตา UI, routes, layoutspublic/– static assets (ภาพ, favicon)next.config.js– ปรับตั้งค่า Next.js เฉพาะแอปpackage.json– dependency เฉพาะแอป, สคริปต์
ตัวอย่าง:
apps/web– เว็บไซต์หน้า Public (marketing)apps/admin-dashboard– ระบบหลังบ้าน (จัดการข้อมูล, dashboard)
3. โฟลเดอร์ packages/
วัตถุประสงค์: ไลบรารีที่แชร์ข้ามหลายแอป เพื่อหลีกเลี่ยงโค้ดซ้ำ
แต่ละโฟลเดอร์ภายใน
packagesเป็น npm package เล็กๆโครงสร้างภายใน:
src/– โค้ด TypeScript หรือ React componentpackage.json– ชื่อแพ็กเกจ, version, dependenciestsconfig.json– config TS เฉพาะแพ็กเกจ (extends จาก base)
ตัวอย่างแพ็กเกจหลัก:
ui- ปุ่ม, การ์ด, modal, theme utilities
- ใช้ร่วมระหว่าง
webและadmin-dashboard
utils- ฟังก์ชันช่วยเรื่องวันที่, fetch wrapper, error handler
data-access- wrappers สำหรับ Firestore, Firebase Auth, server actions
4. โฟลเดอร์ config/
วัตถุประสงค์: เก็บการตั้งค่ากลางให้ทุกแพ็กเกจและแอปใช้ร่วมกัน
รายการไฟล์หลัก:
eslint/.eslintrc.js- config rule, plugin, shared globals
prettier/.prettierrc.js- format style: semi, singleQuote, printWidth
tsconfig.base.jsoncompilerOptionsกลาง:paths,strict,target
turbo.json- กำหนด pipeline tasks, cache strategy, output directories
pnpm-workspace.yaml (ระดับ root)
packages: - 'apps/*' - 'packages/*' - 'config'package.json (ระดับ root)
สคริปต์ทั่วไป:
{ "scripts": { "dev": "turbo run dev", "build": "turbo run build", "lint": "turbo run lint", "test": "turbo run test" } }
5. การตั้งค่า TurboRepo ( turbo.json )
{
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"dev": {
"cache": false
},
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"]
},
"lint": {
"outputs": []
},
"test": {
"outputs": []
}
}
}
- dev – สั่งรัน local server ทุกรายการ (
apps/*) - build – build เรียงลำดับตาม dependency graph
- lint – ตรวจโค้ดแบบ static analysis
- test – รัน unit/integration tests
6. ตัวอย่างคำสั่ง CLI
# ติดตั้ง dependencies ทั้งหมด
$ pnpm install
# รันทุกแอปในโหมด dev
$ pnpm dev
# สั่งรัน dev สำหรับแอปเฉพาะ
$ pnpm --filter web dev
$ pnpm --filter admin-dashboard dev
# Build production ทั้งหมด
$ pnpm build
# ตรวจ lint ทุกแพ็กเกจและแอป
$ pnpm lint
# รัน test ในโฟลเดอร์ utils เท่านั้น
$ pnpm --filter utils test
7. ตัวอย่าง Import ข้ามแพ็กเกจ (Cross-package)
ตั้งค่า alias ใน
tsconfig.base.json{ "compilerOptions": { "baseUrl": ".", "paths": { "@nokfa/ui": ["packages/ui/src"], "@nokfa/utils": ["packages/utils/src"], "@nokfa/data-access": ["packages/data-access/src"] } } }ใน
apps/web/app/page.tsximport { Button } from '@nokfa/ui'; import { formatDate } from '@nokfa/utils'; import { getUser } from '@nokfa/data-access'; export default function HomePage() { const today = formatDate(new Date()); const user = await getUser(); return ( <main> <h1>สวัสดี, {user.name}</h1> <p>วันนี้วันที่ {today}</p> <Button onClick={() => console.log('clicked')}>Click me</Button> </main> ); }
8. Best Practices & ข้อแนะนำ
แยกความรับผิดชอบชัดเจน:
apps/= deployable applicationspackages/= reusable librariesconfig/= global config
ใช้ alias & shared tsconfig เพื่อความสะดวกในการ import
รักษา version ในแต่ละ package.json อย่างสม่ำเสมอ
CI/CD: ตั้ง pipeline ให้แยก lint/test/build per scope และ cache ผลลัพธ์
Document: อัปเดต README.md ในแต่ละโฟลเดอร์อธิบายวิธีเริ่มต้นใช้งาน
หมายเหตุ: โครงสร้างนี้ปรับแต่งเพิ่มเติมได้ตามขนาดทีมและความซับซ้อนของโปรเจกต์ แต่สำหรับทีม Nokfa ขนาด 2 คน Monorepo ช่วยให้ Dev ใหม่เข้ามาทำงานได้เร็ว ปรับแก้โค้ดร่วมกันง่าย และจัดการ CI/CD รวมศูนย์ได้ตรงตามเป้าหมาย