ข้ามไปยังเนื้อหาหลัก

การใช้ร่วมกับ Next.js

FSD สามารถใช้ร่วมกับ Next.js ได้ทั้งเวอร์ชัน App Router และ Pages Router หากคุณแก้ปัญหาความขัดแย้งหลักได้ — นั่นคือเรื่องโฟลเดอร์ app และ pages

App Router

ความขัดแย้งระหว่าง FSD และ Next.js ใน app layer

Next.js แนะนำให้ใช้โฟลเดอร์ app เพื่อกำหนด Application routes มันคาดหวังให้ไฟล์ในโฟลเดอร์ app ตรงกับ Pathnames กลไกการ Routing นี้ ไม่ตรงกัน กับแนวคิดของ FSD เนื่องจากมันทำให้ไม่สามารถรักษาโครงสร้าง Slice แบบแบนราบ (Flat slice structure) ได้

ทางแก้คือย้ายโฟลเดอร์ app ของ Next.js ไปไว้ที่ Project root และ Import FSD pages จาก src (ซึ่งเป็นที่อยู่ของ FSD layers) เข้าไปในโฟลเดอร์ app ของ Next.js

คุณจะต้องเพิ่มโฟลเดอร์ pages ไว้ที่ Project root ด้วย ไม่อย่างนั้น Next.js จะพยายามใช้ src/pages เป็น Pages Router แม้ว่าคุณจะใช้ App Router ก็ตาม ซึ่งจะทำให้ Build พัง และเป็นความคิดที่ดีที่จะใส่ไฟล์ README.md ไว้ใน Root pages folder นี้เพื่ออธิบายว่าทำไมมันถึงจำเป็นต้องมี แม้ว่าข้างในจะว่างเปล่าก็ตาม

├── app                              # App folder (Next.js)
│ ├── api
│ │ └── get-example
│ │ └── route.ts
│ └── example
│ └── page.tsx
├── pages # Empty pages folder (Next.js)
│ └── README.md
└── src
├── app
│ └── api-routes # API routes
├── pages
│ └── example
│ ├── index.ts
│ └── ui
│ └── example.tsx
├── widgets
├── features
├── entities
└── shared

ตัวอย่างการ Re-export page จาก src/pages ใน app ของ Next.js:

app/example/page.tsx
export { ExamplePage as default, metadata } from '@/pages/example';

Middleware

ถ้าคุณใช้ Middleware ในโปรเจกต์ของคุณ มันต้องวางอยู่ที่ Project root ข้างๆ โฟลเดอร์ app และ pages ของ Next.js

Instrumentation

ไฟล์ instrumentation.js ช่วยให้คุณ Monitor ประสิทธิภาพและพฤติกรรมของ Application ถ้าคุณใช้มัน มันต้องวางอยู่ที่ Project root เหมือนกับ middleware.js

Pages Router

ความขัดแย้งระหว่าง FSD และ Next.js ใน pages layer

Routes ควรวางอยู่ในโฟลเดอร์ pages ใน Root ของโปรเจกต์ คล้ายกับโฟลเดอร์ app สำหรับ App Router โครงสร้างภายใน src ที่เป็นที่ตั้งของ Layer folders จะยังคงเหมือนเดิม

├── pages                            # Pages folder (Next.js)
│ ├── _app.tsx
│ ├── api
│ │ └── example.ts # API route re-export
│ └── example
│ └── index.tsx
└── src
├── app
│ ├── custom-app
│ │ └── custom-app.tsx # Custom App component
│ └── api-routes
│ └── get-example-data.ts # API route
├── pages
│ └── example
│ ├── index.ts
│ └── ui
│ └── example.tsx
├── widgets
├── features
├── entities
└── shared

ตัวอย่างการ Re-export page จาก src/pages ใน pages ของ Next.js:

pages/example/index.tsx
export { Example as default } from '@/pages/example';

Custom _app component

คุณสามารถวาง Custom App component ใน src/app/_app หรือ src/app/custom-app:

src/app/custom-app/custom-app.tsx
import type { AppProps } from 'next/app';

export const MyApp = ({ Component, pageProps }: AppProps) => {
return (
<>
<p>My Custom App component</p>
<Component { ...pageProps } />
</>
);
};
pages/_app.tsx
export { App as default } from '@/app/custom-app';

Route Handlers (API routes)

ใช้ api-routes segment ใน app layer เพื่อทำงานกับ Route Handlers

ระวังเมื่อเขียน Backend code ในโครงสร้าง FSD — FSD มีเป้าหมายหลักสำหรับ Frontend ซึ่งหมายความว่าเป็นสิ่งที่คนจะคาดหวังว่าจะเจอ ถ้าคุณมี Endpoints เยอะ พิจารณาแยกพวกมันออกเป็น Package ต่างหากใน Monorepo

src/app/api-routes/get-example-data.ts
import { getExamplesList } from '@/shared/db';

export const getExampleData = () => {
try {
const examplesList = getExamplesList();

return Response.json({ examplesList });
} catch {
return Response.json(null, {
status: 500,
statusText: 'Ouch, something went wrong',
});
}
};
app/api/example/route.ts
export { getExampleData as GET } from '@/app/api-routes';

คำแนะนำเพิ่มเติม

  • ใช้ db segment ใน shared layer เพื่ออธิบาย Database queries และการใช้งานต่อใน Layers ที่สูงกว่า
  • Logic การทำ Caching และ Revalidating queries ควรเก็บไว้ที่เดียวกับ Queries เอง

ดูเพิ่มเติม