Skip to content

Commit 0d02ee3

Browse files
Gaic4o김
andauthored
docs(kr): sync Next.js guide with updated English version (#916)
Co-authored-by: 김 <minsu@gim-ui-Macmini.local>
1 parent 488f55c commit 0d02ee3

1 file changed

Lines changed: 148 additions & 86 deletions

File tree

src/content/docs/kr/docs/guides/tech/with-nextjs.mdx

Lines changed: 148 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -4,131 +4,193 @@ sidebar:
44
order: 1
55
---
66

7-
import { FileTree } from '@astrojs/starlight/components';
7+
import { Tabs, TabItem, FileTree } from '@astrojs/starlight/components';
88

9-
NextJS 프로젝트에도 FSD 아키텍처를 적용할 수 있지만, 구조적 차이로 두 가지 충돌이 발생합니다.
9+
FSD는 Next.js의 App Router와 Pages Router 양쪽에 적용할 수 있습니다.
10+
다만 Next.js가 요구하는 `app`, `pages` 폴더는 FSD 구조와 분리해 두어야 합니다.
1011

11-
- **`pages` layer 라우팅 파일**
12-
- **NextJS에서 `app` layer의 충돌 또는 미지원**
12+
## App Router \{#app-router\}
1313

14-
## `pages` layer 충돌 \{#pages-conflict}
14+
### `app` layer에서 FSD와 Next.js의 충돌 \{#conflict-between-fsd-and-nextjs-in-the-app-layer\}
1515

16-
NextJS는 파일 시스템 기반 라우팅을 위해 **`pages` 폴더**의 파일을 URL에 매핑합니다.
17-
그러나 이 방식은 FSD에서 권장하는 **평탄(flat)한 slice 구조**와 맞지 않아 충돌이 발생합니다.
16+
App Router에서는 `app` 폴더 구조가 곧 라우트 구조가 됩니다. 반면 FSD에서 `app`은 라우트 폴더가 아니라 애플리케이션 전역 구성을 위한 layer입니다. 두 구조가 같은 `app` 폴더를 서로 다른 용도로 사용하기 때문에 충돌이 발생합니다.
1817

19-
### NextJS `pages` 폴더를 Project Root로 이동 (권장)
20-
21-
`pages` 폴더를 **프로젝트 최상위**로 옮긴 뒤,<br/>
22-
FSD `src/pages`의 각 페이지 컴포넌트를 `pages` 폴더에서 **re-export** 하면 NextJS 라우팅과 FSD 구조를 모두 유지할 수 있습니다.
18+
이 충돌을 피하려면 Next.js의 `app` 폴더는 프로젝트 루트에 두고, 여기에는 라우트 파일만 둡니다. 실제 페이지 파일은 `src` 하위의 FSD 구조에 유지합니다. 루트 `app`의 각 라우트 파일은 `src/pages`의 페이지 파일을 가져와 연결합니다.
2319

20+
프로젝트 루트에는 빈 `pages` 폴더도 함께 두어야 합니다. App Router를 쓰더라도 Next.js는 `src/pages`를 Pages Router로 사용하려 하므로 빌드가 실패합니다. 루트의 빈 `pages` 폴더가 이 동작을 막습니다. 폴더 안에는 왜 비어 있어야 하는지 설명하는 `README.md`를 두는 것이 좋습니다.
2421

2522
<FileTree>
26-
- pages/ NextJS 라우팅 폴더 (FSD pages를 재-export)
27-
- index.tsx
28-
- about.tsx
29-
- src/
30-
- app/
31-
- entities/
23+
- app App folder (Next.js)
24+
- api
25+
- get-example
26+
- route.ts
27+
- example
28+
- page.tsx
29+
- pages Empty pages folder (Next.js)
30+
- README.md
31+
- src
32+
- app
33+
- api-routes API routes
34+
- pages
35+
- example
36+
- index.ts
37+
- ui
38+
- example.tsx
39+
- widgets/
3240
- features/
33-
- pages/ FSD pages layer
41+
- entities/
3442
- shared/
35-
- widgets/
3643
</FileTree>
3744

38-
### FSD pages layer 이름 변경
45+
루트 `app`의 라우트 파일에는 페이지 코드가 들어 있지 않습니다. `src/pages`의 페이지 파일을 가져와 연결합니다.
46+
47+
```tsx title="app/example/page.tsx"
48+
export { ExamplePage as default, metadata } from '@/pages/example';
49+
```
50+
51+
### Middleware \{#middleware\}
52+
53+
middleware를 사용한다면 Next.js의 `app`, `pages` 폴더와 함께 프로젝트 루트에 둡니다.
54+
55+
### Instrumentation \{#instrumentation\}
56+
57+
`instrumentation.js`는 애플리케이션의 성능과 동작을 모니터링하는 파일입니다. `middleware.js`와 같은 이유로, 이 파일도 프로젝트 루트에 둡니다.
3958

40-
FSD의 `pages` layer 이름을 변경해 NextJS `pages` 폴더와 충돌을 방지할 수 있습니다.
41-
예를 들어, `pages``views`로 바꾸면 라우팅 폴더와 FSD 페이지 layer를 동시에 사용할 수 있습니다.
59+
## Pages Router \{#pages-router\}
60+
61+
### `pages` layer에서 FSD와 Next.js의 충돌 \{#conflict-between-fsd-and-nextjs-in-the-pages-layer\}
62+
63+
Pages Router도 App Router와 같은 원리로 분리합니다. 라우트 파일은 프로젝트 루트의 `pages` 폴더에 두고, 실제 페이지 파일은 `src` 하위의 FSD 구조에 유지합니다.
4264

4365
<FileTree>
44-
- app/
45-
- entities/
46-
- features/
47-
- pages/ NextJS 라우팅 폴더
48-
- views/ 변경된 FSD pages layer
49-
- shared/
50-
- widgets/
66+
- pages Pages folder (Next.js)
67+
- _app.tsx
68+
- api
69+
- example.ts API route re-export
70+
- example
71+
- index.tsx
72+
- src
73+
- app
74+
- custom-app
75+
- custom-app.tsx Custom App component
76+
- api-routes
77+
- get-example-data.ts API route
78+
- pages
79+
- example
80+
- index.ts
81+
- ui
82+
- example.tsx
83+
- widgets/
84+
- features/
85+
- entities/
86+
- shared/
5187
</FileTree>
5288

53-
폴더 이름을 변경했다면 프로젝트 README나 내부 문서에 반드시 기록해야 합니다.
54-
이 내용을 [프로젝트 지식][project-knowledge]에 포함해 팀원들이 쉽게 확인할 수 있도록 하세요.
55-
56-
## NextJS에서 `app` layer 구현하기 \{#app-absence}
89+
루트 `pages`의 각 파일도 `src/pages`의 페이지 파일을 가져와 연결합니다.
5790

58-
NextJS 13 이전 버전에는 FSD app layer에 대응하는 전용 폴더가 없습니다.
59-
대신 pages/_app.tsx가 모든 페이지의 wrapping component로 작동합니다.
60-
이 파일에서 전역 상태 관리(global state management)와 레이아웃 구성(layout)을 담당합니다.
91+
```tsx title="pages/example/index.tsx"
92+
export { Example as default } from '@/pages/example';
93+
```
6194

62-
### `pages/_app.tsx`에 app layer 기능 통합하기
95+
### Custom `_app` 컴포넌트 \{#custom-_app-component\}
6396

64-
먼저 `src/app/providers/index.tsx``App` 컴포넌트를 정의합니다.
65-
이 컴포넌트에서 전체 애플리케이션의 provider와 layout을 설정합니다.
97+
Custom App 컴포넌트는 `src/app/_app` 또는 `src/app/custom-app`에 둘 수 있습니다. 루트의 `pages/_app.tsx`는 이 컴포넌트를 가져와 연결합니다.
6698

67-
```tsx
68-
// app/providers/index.tsx
99+
```tsx title="src/app/custom-app/custom-app.tsx"
100+
import type { AppProps } from 'next/app';
69101

70-
const App = ({ Component, pageProps }: AppProps) => {
71-
return (
72-
<Provider1>
73-
<Provider2>
74-
<BaseLayout>
75-
<Component {...pageProps} />
76-
</BaseLayout>
77-
</Provider2>
78-
</Provider1>
79-
);
102+
export const MyApp = ({ Component, pageProps }: AppProps) => {
103+
return (
104+
<>
105+
<p>My Custom App component</p>
106+
<Component { ...pageProps } />
107+
</>
108+
);
80109
};
110+
```
81111

82-
export default App;
112+
```tsx title="pages/_app.tsx"
113+
export { App as default } from '@/app/custom-app';
83114
```
84115

85-
다음으로 `pages/_app.tsx`에서 위 `App` 컴포넌트를 export합니다.
86-
이 과정에서 global style도 함께 import할 수 있습니다.
116+
## Route Handlers (API routes) \{#route-handlers-api-routes\}
117+
118+
Route Handlers는 `app` layer의 `api-routes` segment에 둡니다. 루트의 라우트 파일은 여기서 가져와 연결합니다.
87119

88-
```tsx
89-
// pages/_app.tsx
120+
FSD는 프론트엔드 애플리케이션 구조를 위한 방법론입니다. API 코드가 많다면 같은 구조 안에 함께 두는 방식은 구조 파악을 어렵게 만들 수 있으므로, Monorepo의 별도 패키지로 분리하는 편이 낫습니다.
90121

91-
import 'app/styles/index.scss'
122+
<Tabs>
92123

93-
export { default } from 'app/providers';
124+
<TabItem value="app-router" label="App Router">
125+
126+
```tsx title="src/app/api-routes/get-example-data.ts"
127+
import { getExamplesList } from '@/shared/db';
128+
129+
export const getExampleData = () => {
130+
try {
131+
const examplesList = getExamplesList();
132+
133+
return Response.json({ examplesList });
134+
} catch {
135+
return Response.json(null, {
136+
status: 500,
137+
statusText: 'Ouch, something went wrong',
138+
});
139+
}
140+
};
94141
```
95142

96-
## App Router 사용하기 \{#app-router}
143+
```tsx title="app/api/example/route.ts"
144+
export { getExampleData as GET } from '@/app/api-routes';
145+
```
97146

98-
NextJS 13.4부터 `app` 폴더 기반 App Router를 지원합니다.
99-
FSD 아키텍처를 App Router와 함께 사용하려면 다음 구조를 적용하세요.
147+
</TabItem>
100148

101-
`app` 폴더는 NextJS App Router 전용입니다.
102-
`src/app`은 FSD의 app layer를 유지합니다.
103-
필요에 따라 App Router와 Pages Router를 함께 사용할 수 있습니다.
149+
<TabItem value="pages-router" label="Pages Router">
104150

105-
<FileTree>
106-
- app/ NextJS의 App Router용 폴더
107-
- pages/ NextJS의 Pages Router용 폴더 (선택적)
108-
- README.md 폴더의 용도 설명
109-
- src/
110-
- app/ FSD의 app layer
111-
- entities/
112-
- features/
113-
- pages/ FSD의 pages layer
114-
- shared/
115-
- widgets/
116-
</FileTree>
151+
```tsx title="src/app/api-routes/get-example-data.ts"
152+
import type { NextApiRequest, NextApiResponse } from 'next';
117153

118-
`app` 폴더에서 `src/pages`의 컴포넌트를 re-export하세요.
119-
App Router만 사용해도 `Pages Router`와의 호환성을 위해 `root pages` 폴더를 유지합니다.
154+
const config = {
155+
api: {
156+
bodyParser: {
157+
sizeLimit: '1mb',
158+
},
159+
},
160+
maxDuration: 5,
161+
};
162+
163+
const handler = (req: NextApiRequest, res: NextApiResponse<ResponseData>) => {
164+
res.status(200).json({ message: 'Hello from FSD' });
165+
};
166+
167+
export const getExampleData = { config, handler } as const;
168+
```
169+
170+
```tsx title="src/app/api-routes/index.ts"
171+
export { getExampleData } from './get-example-data';
172+
```
173+
174+
```tsx title="app/api/example.ts"
175+
import { getExampleData } from '@/app/api-routes';
176+
177+
export const config = getExampleData.config;
178+
export default getExampleData.handler;
179+
```
120180

181+
</TabItem>
121182

122-
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)][ext-app-router-stackblitz]
183+
</Tabs>
123184

124-
## Middleware \{#middleware}
185+
## 추가 권장사항 \{#additional-recommendations\}
125186

126-
NextJS middleware 파일은 반드시 프로젝트 root 폴더(`app` 또는 `pages` 폴더와 동일 수준)에 둬야 합니다.
127-
`src` 아래에 두면 NextJS가 인식하지 않으므로, middleware 파일을 root로 이동하세요.
187+
- 데이터베이스 쿼리는 `shared` layer의 `db` segment에 정의하고, 상위 layer에서 가져와 사용합니다.
188+
- 쿼리의 캐싱과 재검증(revalidate) 로직은 쿼리 정의와 같은 위치에 둡니다.
128189

129-
## 참고 자료 \{#see-also}
190+
## 참고 자료 \{#see-also\}
130191

131-
- [(스레드) NextJS의 pages 폴더에 대한 토론](https://t.me/feature_sliced/3623)
192+
- [Next.js Project Structure](https://nextjs.org/docs/app/getting-started/project-structure)
193+
- [Next.js Page Layouts](https://nextjs.org/docs/app/getting-started/layouts-and-pages)
132194

133-
[project-knowledge]: /kr/docs/about/understanding/knowledge-types
134-
[ext-app-router-stackblitz]: https://stackblitz.com/edit/stackblitz-starters-aiez55?file=README.md
195+
[project-knowledge]: /docs/about/understanding/knowledge-types
196+
[ext-app-router-stackblitz]: https://stackblitz.com/edit/stackblitz-starters-aiez55?file=README.md

0 commit comments

Comments
 (0)