ไม่มีชื่อบทความ
การสร้าง Shared Packages (auth-lib, pdf-writer, ui-kit)
TL;DR
- โฟลเดอร์
packages/*ใช้เก็บโค้ดที่แชร์ข้ามแอป เช่น auth-lib, pdf-writer, ui-kit - ทุกแพ็กเกจควรมี
index.ts,tsconfig.json,package.jsonพร้อมตั้งชื่อ prefix@nokfa/ - ใช้
private: trueเพื่อไม่ให้ publish ออก npm โดยไม่ตั้งใจ - Import ข้ามแอปด้วย alias เช่น
@nokfa/ui-kit,@nokfa/auth-lib - ตั้ง convention เดียวกันทุกแพ็กเกจเพื่อให้จัดการง่ายและ scale ได้ในอนาคต
1. โครงสร้างโดยรวม
packages/
├── auth-lib/
│ ├── src/
│ │ ├── index.ts
│ │ └── firebase-auth.ts
│ ├── package.json
│ └── tsconfig.json
├── pdf-writer/
│ ├── src/
│ │ ├── index.ts
│ │ └── generate-pdf.ts
│ ├── package.json
│ └── tsconfig.json
└── ui-kit/
├── src/
│ ├── index.ts
│ ├── Button.tsx
│ └── Card.tsx
├── package.json
└── tsconfig.json
2. ตั้งค่า package.json
📄 ตัวอย่าง packages/pdf-writer/package.json
{
"name": "@nokfa/pdf-writer",
"version": "0.1.0",
"main": "src/index.ts",
"private": true
}
- ✅ ตั้งชื่อ prefix เป็น
@nokfa/เพื่อความเป็นระบบ - ✅
private: trueเพื่อป้องกัน publish ขึ้น npm โดยไม่ได้ตั้งใจ - ❗ ถ้าจะ publish ขึ้น private registry ในอนาคต ค่อยเอา
private: trueออก
3. ตั้งค่า tsconfig.json (เฉพาะแพ็กเกจ)
📄 ตัวอย่าง packages/pdf-writer/tsconfig.json
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"composite": true
},
"include": ["src"]
}
📄 แนะนำให้เพิ่มใน root tsconfig.base.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@nokfa/*": ["packages/*/src"]
}
}
}
4. โครงสร้างไฟล์ index.ts
auth-lib/src/index.ts
export * from './firebase-auth';
pdf-writer/src/index.ts
export * from './generate-pdf';
ui-kit/src/index.ts
export { Button } from './Button';
export { Card } from './Card';
✅ แนวทางนี้ทำให้ consumer import ง่าย เช่น
import { Button } from '@nokfa/ui-kit';
import { signInWithGoogle } from '@nokfa/auth-lib';
5. ตัวอย่าง stub แต่ละแพ็กเกจ
📦 auth-lib
📄 firebase-auth.ts
import { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
export const signInWithGoogle = async (auth: any) => {
const provider = new GoogleAuthProvider();
return await signInWithPopup(auth, provider);
};
📦 pdf-writer
📄 generate-pdf.ts
import { PDFDocument } from 'pdf-lib';
export const generateSimplePdf = async (text: string): Promise<Uint8Array> => {
const pdfDoc = await PDFDocument.create();
const page = pdfDoc.addPage([500, 400]);
page.drawText(text, { x: 50, y: 350 });
return await pdfDoc.save();
};
📦 ui-kit
📄 Button.tsx
'use client';
import React from 'react';
export const Button = ({ children, ...props }) => (
<button className="bg-blue-600 text-white px-4 py-2 rounded" {...props}>
{children}
</button>
);
📄 Card.tsx
'use client';
import React from 'react';
export const Card = ({ title, children }) => (
<div className="border p-4 rounded shadow">
<h3 className="font-bold text-lg mb-2">{title}</h3>
<div>{children}</div>
</div>
);
6. ตารางเปรียบเทียบ Shared Package แบบต่าง ๆ
| ชื่อแพ็กเกจ | ประเภท | ใช้ใน | จุดเด่น |
|---|---|---|---|
| auth-lib | logic (non-UI) | web, dashboard | แยก auth logic ออกจาก UI |
| pdf-writer | utility / binary | dashboard | ประมวลผล PDF ฝั่ง client หรือ server |
| ui-kit | UI Component (React) | web, dashboard | ปรับดีไซน์กลาง เปลี่ยนที่เดียวได้ทุกที่ |
7. กลยุทธ์การใช้ shared packages ภายใน Nokfa
- ❌ ไม่ใช้ npm publish สำหรับตอนนี้ → ทำงานภายใน workspace เท่านั้น
- ✅ ใช้ alias
@nokfa/*ผ่านpathsใน tsconfig - ✅ ใช้
pnpmfilter ทำ dev เฉพาะแพ็กเกจได้ เช่น:
$ pnpm --filter ui-kit dev
- ✅ สร้าง CI ตรวจแต่ละแพ็กเกจแยกกันได้ง่ายในอนาคต
- ✅ โค้ดทุกแพ็กเกจอยู่ใน workspace → sync กันหมดใน Monorepo
8. สรุปข้อดี‑ข้อเสียของการทำ Shared Packages
| ด้าน | ข้อดี | ข้อเสีย |
|---|---|---|
| Maintenance | โค้ดเป็นระบบ แก้ที่เดียว ใช้ได้หลายที่ | ต้องวางโครงสร้างชัดเจน ไม่งั้นจะรกและ import สลับไปมา |
| Dev Experience | import ด้วย alias สะดวก, ไม่ต้อง copy/paste โค้ด | ต้องคอยดูแลให้เวอร์ชัน match ทุกแพ็กเกจใน workspace |
| Performance | ใช้ TurboRepo cache ข้าม build ได้ดี | บางแพ็กเกจต้อง build ทุกครั้งหากมี dependency ลึก |
| Team Scaling | แยกความรับผิดชอบทีมได้ตามแพ็กเกจ | ต้องมี convention เดียวกัน, ไม่งั้นการแชร์จะกลายเป็นภาระ |