์ต๊ทผ์ ์์ฃผ ๋ณด์ด๋ ํ๋ก ํธ์๋ ์ํคํ
์ฒ์ ๊ด๋ จ๋ ๊ธ์ ์ ์ด๋ณด๋ ค๊ณ ํ๋ค.
๋ด๊ฐ FSD์ ๊ด๋ จ๋ ์ํฐํด์ ๋ณธ๊ฑด ๋ช ๋ฌ์ ์ ์ ํ๋๋ฐ ๊ทธ๋ ๊ธ๋ก ์ ํ์ ๋๋ ๋ฐ๋ก ์๋ฟ์ง๋ ์์์๋ค.
๊ทธ๋ฅ '์ด๋ฐ ์ํคํ
์ณ๋ ์๊ตฌ๋.., ๋์ค์ ์ ์ฉํด๋ด์ผ์ง' ํ๊ณ ๋์ด๊ฐ์๋ค.
๊ด๋ จ ์ํฐํด
(๋ฒ์ญ) ๊ธฐ๋ฅ ๋ถํ ์ค๊ณ - ์ต๊ณ ์ ํ๋ฐํธ์๋ ์ํคํ ์ฒ
์ต๊ทผ์ ํ ๋ด์์ FSD ์ํคํ
์ฒ์ ๊ดํ ์ด์ผ๊ธฐ๊ฐ ์ค๊ฐ๊ณ , ๋ค๋ฅธ ํ์์ ์ ์ฉํด๋ณธ ๊ณณ๋ ์์ด์ ์๋ก ์์ํ๋ ํ๋ก์ ํธ์ ์ ์ฉํด๋ณด๊ณ ์ ํ์๋ค.
๊ทธ๋์ ์ค์ ๋ก ์ ์ฉํด๋ณด๋ฉด์ ์ํคํ
์ฒ ์ค๋ช
๊ณผ ๋ด๊ฐ ๋๋ผ๋ ์ฅ๋จ์ ์ ์ ์ด๋ณด๊ณ ์ ํ๋ค.
์ถ์ฒ: https://emewjin.github.io/feature-sliced-design/
FSD๋ Feature-Sliced Design์ ์ถ์ฝ์ผ๋ก ํด์ํ๋ฉด ๊ธฐ๋ฅ ๋ถํ ์ค๊ณ ์ํคํ
์ฒ์ด๋ค.
ํฌ๊ฒ 3๊ฐ์ง์ ๊ฐ๋
์ผ๋ก ๊ตฌ๋ถ๋์ด ์์ผ๋ฉฐ, ๊ฐ๊ฐ Layer
, Slice
, Segment
๋ก ๊ตฌ์ฑ๋์ด ์๋ค.
์์ธํ ๋ด์ฉ์ ์ ์ํฐํด์ ๋ณด๋๊ฒ ๋์ข์์ ๊ฐ๋จํ๊ฒ ์์ฑํด๋ณด๋ ค๊ณ ํ๋ค.
๋ ์ด์ด์์๋ 7๊ฐ์ง์ ํด๋๋ก ๊ตฌ์ฑํ๋ฉด ๋๊ณ , ๊ฐ ํด๋๋ง๋ค ์๋ก์ ์ญํ ์ด ์์ด์ ํด๋๋ณ๋ก ๊ตฌ๋ถํด์ ๊ด๋ฆฌํด์ผ ํ๋ค.
๐๏ธ src
โฃ ๐๏ธ app
โฃ ๐๏ธ pages
โฃ ๐๏ธ widgets
โฃ ๐๏ธ features
โฃ ๐๏ธ entities
โ ๐๏ธ shared
ex) ๊ฒ์๋ฌผ์ ๋ถ๋งํฌํ๋ค, ๋ฉ์์ง๋ฅผ ์ ์กํ๋ค ๋ฑ
)ex) ํ๋กํ ๋ฐ์ดํฐ ๋ชจ๋ธ, ๊ฒ์ํ ๋ฐ์ดํฐ ๋ชจ๋ธ ๋ฑ
)ex) ํฌํผ ํจ์, ๊ฐ์ข
์ ํธ ํจ์๋ค, ๊ณตํต์ผ๋ก ์ฐ์ด๋ ๋ชจ๋ธ(ํ์
)
)ํด๋์ ์ญํ ์ ๋ง์ถฐ์ ๊ตฌ๋ถํ๋ ๊ฒ๋ ์ค์ํ์ง๋ง, ๊ฐ ๊ณ์ธต(ํด๋) ๋ณ๋ก ์ฌ์ฉํ ์ ์๋ ๊ฒ์ด ์ ํ์ ์ธ ๊ฒ๋ ํน์ง ์ค์ ํ๋์ด๋ค. ๊ทธ๋ฆผ์ผ๋ก ๋ณด๋๊ฒ ๋ ์ดํดํ๊ธฐ ํธํ ๊ฒ์ด๊ธฐ์ ํ๋ก ๋ํ๋ด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
Layer | ์ฌ์ฉํ ์ ์๋ ๊ณ์ธต |
---|---|
app | ๋ชจ๋ ์ฌ์ฉ ๊ฐ๋ฅ |
pages | widgets, entities, shared |
widgets | entities, shared |
entities | shared |
shared | x |
ํ๋ฅผ ๋ณด๋ฉด ๊ฐ ๊ณ์ธต์์ ์ฌ์ฉํ ์ ์๋ ๊ฒ์ด ์ ํ์ ์ด๊ธฐ์ ์ด๋ฐ ์ ์ ๋ ์๊ฐํด์ ์ค๊ณ๋ฅผ ํด์ผ ํ๋ค.
์ฌ๋ผ์ด์ค๋ Layer์ ๊ฐ ๊ณ์ธต์ ๋ชจ๋ ์กด์ฌ(shared
๋ ์ ์ธ)ํ ์ ์๋ค. ์ฌ๋ผ์ด์ค์์๋ ํ๋ก๋ํธ์ ์ฑ๊ฒฉ๋ง๋ค ๋น์ง๋์ค๊ฐ ๋ชจ๋ ๋ค๋ฅด๊ธฐ์ ๊ฐ ํ๋ก์ ํธ์ ๋ง์ถฐ์ ์ง์ ํ๋ฉด ๋๋ค.
๐๏ธ src
โฃ ๐๏ธ app
โฃ ๐๏ธ pages
โ โฃ detail/
โ โ profile/
โฃ ๐๏ธ widgets
โ โฃ header/
โ โ footer/
โฃ ๐๏ธ features
โ โ ...
โฃ ๐๏ธ entities
โ ๐๏ธ shared
์ค์ํ ์ ์ ์ฌ๋ผ์ด์ค์ ์๋ ์ฝ๋๋ฅผ ์ง์ ์ ์ผ๋ก ์ฌ์ฉํ๋ฉด ์๋๋ค.
์ฆ, import๋ฅผ ์ง์ ์ ์ผ๋ก ์ฝ๋์์ ๊ฐ์ ธ์์ ํ๋ฉด ์ ๋๋ค๋ ๊ฒ์ด๋ค.
์ธ๊ทธ๋จผํธ๋ ์ฌ๋ผ์ด์ค ๋ด์ ์กด์ฌํ๋ฉฐ, ์ธ๊ทธ๋จผํธ๋ด์ ๋๋์ด ์ฝ๋๋ฅผ ์์ฑํด ๋ค์ด๊ฐ๊ฒ ๋๋ ํด๋์ด๋ค. ํน์ดํ๊ฒ shared๋ ๋ฐ๋ก segment๊ฐ ๋ฐ๋ก ์ค๊ฒ ๋๋ค.
๐๏ธ src
โฃ ๐๏ธ app
โฃ ๐๏ธ pages
โ โฃ detail/
โ โ โฃ ui/
โ โ โ constants/
โ โ profile/
โฃ ๐๏ธ widgets
โ โฃ header/
โ โ โฃ ui/
โ โ โฃ model/
โ โ โ constants/
โ โ footer/
โฃ ๐๏ธ features
โ โ ...
โฃ ๐๏ธ entities
โ ๐๏ธ shared
โฃ ui/
โฃ model/
โ constants/
"์์์ ์ง์ ์ ์ผ๋ก import ํด์๋ ์๋๋ค" ๋ผ๋ ๋ง์ ํ์๋๋ฐ, ์ด์ ๊ด๋ จ๋ ๋ด์ฉ์ด๋ค. FSD์์๋ ๊ฒฐํฉ๋๋ ๋ฎ์ถ๊ณ ์์ง๋๋ ๋์ด๋ ๊ฒ์ด ๋ชฉํ ์ค ํ๋์ธ๋ฐ ์ด๋ฅผ publicํ ๊ฒ๊ณผ privateํ ๋ฐฉ๋ฒ์ผ๋ก ๊ด๋ฆฌํ๋ค.
// features/submitLike/ui/SubmitLikeButton.tsx
/** ์ข์์ ๋๋ฅด๊ธฐ ๋ฒํผ */
export const SubmitLikeButton = () => {
// ...
}
----------------------------------------
// widgets/postFooter/ui/PostFooterSection.tsx
// DO NOT โ
import { SubmitLikeButton } from 'features/submitLike/ui/SubmitLikeButton.tsx
// GOOD โ
import { SubmitLikeButton } from 'features/submitLike
/** ๊ฒ์๋ฌผ ํ๋จ ์์ญ */
export const PostFooterSection = () => {
// ...
return (
<>
...
<SubmitLikeButton />
...
</>
)
}
----------------------------------------
// features/submitLike/index.ts
export { SubmitLikeButton } from 'features/submitLike/ui/SubmitLikeButton'
์์ฒ๋ผ ui ํด๋ ๋ด์ ์ปดํฌ๋ํธ๋ฅผ ์ง์ ์ ์ผ๋ก import ํด์๋ ์๋๋ค.
submitLike
ํ์์ index.ts
ํ์ผ์ ์ ์ธ๋ Public ํ ์ปดํฌ๋ํธ๋ฅผ ์ํฌํธํ๋ ํํ๋ก ๊ฐ์ ธ์์ ์จ์ผํ๋ค.
privateํ ๊ฒ๋ค์ ๋ฌด์์ด ์์๊น?
๊ทธ๋ผ ๋๋ถ๋ถ์ด publicํ ์ปดํฌ๋ํธ์ธ๋ฐ ๊ตณ์ด ๊ตณ์ด ์ด๋ ๊ฒ ํด์ผํ๋? ๋ผ๊ณ ์๊ฐ์ด ๋ค์๋ ์๋ค. ๊ทธ๋ฌ๋ ์ด๋ ๊ฒ ์ธ ๊ฒฝ์ฐ ๋ช ์์ ์ผ๋ก publicํ๊ฒ ๊ด๋ฆฌ๋๋ ๊ฒ๊ณผ ์๋ ๊ฒ์ ๊ตฌ๋ถํ ์ ์๊ฒ ๋๋ค.
privateํ ์ปดํฌ๋ํธ๋ฅผ ์์๋ก ๋ค์ด๋ณด๋ฉด ๊ฐ๋จํ๊ฒ ๋ฐ๋ณต ์ปดํฌ๋ํธ์์ ์ฐ์ด๋ ๊ฒ์ด๋ผ๊ณ ๋ณด๋ฉด ๋๋ค.
export const PostList = () => {
return (
<>
{postList.map((postItem) => {
return <PostItem key={postItem.id}/>
}
</>
}
PostItem
์ปดํฌ๋ํธ๋ ์ด๋์์๋ ์ฐ์ด์ง ์๊ณ ํด๋น ํ์ผ ๋ด์์๋ง ์ฐ์ด๋ ์ปดํฌ๋ํธ์ด๋ค. ๊ทธ๋ฌ๋ฏ๋ก index.ts์ ์ ์ํ์ง ์์๋ ๋์ด privateํ ์ปดํฌ๋ํธ๊ฐ ๋๋ค.
์ด ์ธ์๋ ์์(constant
) ๊ฐ์ด๋ ์ธ๋ถ ๋ ์ด์ด์์ ์ฌ์ฉ๋์ง ์์ api๊ฐ์ ๊ฒ๋ค์ publicํ๊ฒ ์ ์ํ์ง ์์๋ ๋๋ ๊ฒ์ด๋ค.
FSD์ ๋ํ ์ ๋ฐ์ ์ธ ์ค๋ช ์ด ๋๋ฌ์ผ๋ ๋ด๊ฐ ์ฐ๋ฉด์ ๋๊ผ๋ ์ฅ์ ๊ณผ ๋จ์ ์ ์ ์ด๋ณด๋ ค๊ณ ํ๋ค.
===
ํ๊ณผ์ ์ํต์ด ์ค์ํ๋ค.์ด๋ฒ์ ๋ด๊ฐ ์ ์ฉํ ํ๋ก๋ํธ๋ ์์ฒญ ๊ท๋ชจ๊ฐ ํฌ์ง ์์์ง๋ง, ๊ผญ ์จ์ผํ๋ ์ํคํ ์ฒ๋ผ๊ณ ๋ ์๊ฐํ์ง ์๋๋ค. ๊ฐ์ฅ ํฌ๊ฒ ๋๊ผ๋ ๊ฑด '์ํคํ ์ฒ์ ์ ๋ต์ ์๋ค' ๋ผ๋ ๊ฒ์ด๋ค.
๊ฐ์ ๊ท์น์ ๋ณด๊ณ ๋ ์๋ก ๋ค๋ฅธ ๊ด์ ์ผ๋ก ์๊ฐํ๋ฉด ์๊ฒฌ์ด ๊ฐ๋ฆด ์ ์๊ฒ ๋๋ค. ์ฆ, "ํด๋น ์ปดํฌ๋ํธ๊ฐ ์ features์ ๋ค์ด๊ฐ์ผํ๊ณ ์ด๋ค ๋น์ง๋์ค ๋ก์ง์ ์ฒ๋ฆฌํด์ผ ํ๊ธฐ ๋๋ฌธ์ ํด๋น ๊ณ์ธต์ด ๋ง๋ค" ๋ผ๋ ๊ฒฐ๋ก ์ ๋๋ฌํด์ผ ํ๋ค.
๋งค์ฐ ๊ฐ๋จํ ํ๋ก์ ํธ์ ๊ฒฝ์ฐ์๋ FSD๋ฅผ ์ ์ฉํ์ง ์์๋ ๋๋ค๊ณ ์๊ฐํ๋ค. ์ด์ ์ ์์ ์ด ์์ฃผ ์ฐ๋ ์ํคํ ์ฒ๋ฅผ ์ ์ฉํ๋๋ผ๋ ์ถฉ๋ถํ ๋ฉ๋ํ ๋งํ ์ด์ ๊ฐ ์๊ณ ๊ตฌ์กฐํ๊ฐ ์๋์ด ์๋ ์ํคํ ์ฒ๋ผ๋ฉด ๊ทธ๊ฒ๋ง ํด๋ ์ข์ ์ํคํ ์ฒ๋ผ๊ณ ๋ณธ๋ค.
1. Next.js ์ฑ๋ผ์ฐํฐ ์ฐ๋ ์ฌ๋์์?
Next.js ์ฑ๋ผ์ฐํฐ๋ฅผ ์ฐ๋ ์ฌ๋์ ์๋ฌธ์ฌํญ์ด ์์์ ๊ฒ์ด๋ค.
Next.js์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก app
์ด๋ผ๋ ํด๋๋ ๋ผ์ฐํฐ๋ฅผ ์๋ฏธํ๊ธฐ ๋๋ฌธ์ ์์ ๊ท์น์ ์งํค๊ธฐ๊ฐ ์ ๋งคํ ์ ์๋ค.
์ด๋ฐ ๋ถ๋ถ์ FSD ์ค๊ณํ ์ฌ๋๋ ์ธ์งํ๊ณ ์์ด์ ๊ณต์ ๋ฌธ์์์๋ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ ์ํ๋ค.
โฃ ๐๏ธ app # NextJS app folder
โฃ ๐๏ธ src
โ โฃ ๐๏ธ app # FSD app folder
โ โฃ ๐๏ธ entities
โ โฃ ๐๏ธ features
โ โฃ ๐๏ธ pages
โ โฃ ๐๏ธ shared
โ โ ๐๏ธ widgets
์์ ๊ฐ์ด ์ฑ๋ผ์ฐํฐ๋ฅผ ์ํ ๋ณ๋ ํด๋์ FSD๋ฅผ ์ํ app ํด๋๋ฅผ ๋๋์ด์ ๊ด๋ฆฌํ๋ผ๊ณ ์ ์ํ๋ค. ๋ ๊ถ๊ธํ๋ฉด ์ฌ๊ธฐ์ ๋ณด๋ ๊ฒ์ ์ถ์ฒํ๋ค.
๊ทธ ์ธ์๋ FSD๋ฅผ ์ ์ฉํ ๋ค์ํ Example ๋ ํฌ์งํ ๋ฆฌ๊ฐ ์์ด์ ํจ๊ป ์ฐธ๊ณ ํ๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค.
2. ์ ์ฉํ ๋ค ์์ฌ์ ๋ ์ (๋ฆฌํฉํ ๋ง ํด์ผ ํ๋ ์ )
์์์ ์ธ๊ธํ pages ๊ณ์ธต์ด ๋๋ฌด ๋ง์ ์ญํ ์ ๋ด๋นํ๊ณ ์๋ ๊ฒ ์์ฌ์ ๋ค. ๊ฒฐ๊ตญ์ pages๋ด์์๋ ์์ ฏ์ด ํฉ์ณ์ ธ ๊ตฌ์ฑ๋๊ฒ ํ์ด์ง๋ฅผ ๊ตฌ์ฑํ๊ฒ ๋๋ค.
๊ฐ๋จํ๊ฒ ํ๋กํ๋ก ์์๋ฅผ ๋ค์ด๋ณด์๋ฉด...(์์ธํ ์ ์ ์ ์์ด ํ๋ง ๋ด์ฃผ์ธ์)
// pages/profile/ui/ProfilePage.tsx
/** ํ๋กํ ํ์ด์ง */
export const ProfilePage = () => {
// .. ๊ฐ์ข
state๋ค..
return (
<>
<ProfileHeader ... />
<ProfileBody ... />
<ProfileFooter ... />
</>
)
}
// widgets/ProfileBody/ui/ProfileBodySection.tsx
/** ํ๋กํ ์์ฑ ์์ญ */
export const ProfileBodySection = (...) => {
// ...
}
// features/saveProfileData/ui/SaveProfileDataButton.tsx
/** ํ๋กํ ์ ์ฅ ๋ฒํผ */
export const SaveProfileDataButton = (...) => {
// ...
}
์์ ๊ฐ์ ๊ตฌ์กฐ๋ผ๋ฉด ๊ฒฐ๊ตญ ํ๋กํ ํ์ด์ง์ ์๋ก ๋ค๋ฅธ ์ปดํฌ๋ํธ์ ๊ฐ์ ๋ฐ์ดํฐ(state)๋ฅผ ๋ฐ๋ผ๋ณด๊ฒ ํด์ผ ํ๋ค๋ฉด, Page๋จ์์ ์ํ๋ฅผ ์ ์ํด์ค์ผ ํ๋ค. ์ฆ, props๋ก ๋๊ฒจ์ฃผ์ด์ผ ๊ฐ๊ฐ์ ๋ ์ด์ด์์ ๋์ผํ๊ฒ ์ ๋ฐ์ดํธ๋ฅผ ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ด๋ ์ ์ญ ์ํ ๊ด๋ฆฌ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐ๋ฉด ์ด๋์ ๋ ํด์๋ ๊ฒ ๊ฐ์ง๋ง, ์ข ๋ ๊ทผ๋ณธ์ ์ธ ๊ตฌ์กฐ๋ฅผ ์๊ฐํด๋ณด๊ณ ์ถ๋ค.(๋ฌผ๋ก ๋ด๊ฐ ์๋ชป ์ค๊ณํ์ ์ ์๋ค.)
ui๋ฅผ ๊ทธ๋ฆฌ๋ ์ปดํฌ๋ํธ, ๋น์ง๋์ค ๋ก์ง, ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ฑ ์ข๋ ๊ฒฉ๋ฆฌ๋ ํ๊ฒฝ์ ์๊ฐํ์ฌ ๋ฆฌํฉํ ๋ง ํ๊ณ ์ถ๋ค.
ํ๋ก์ ํธ๊ฐ ๋๋๊ณ ๊ณ ๋ํ๋ฅผ ํ๋ฉด์ ์ง๊ธ๋ณด๋ค ํํํ ์ํคํ
์ฒ๋ก ๊ตฌ์ฑํด๋ณผ ๊ฒ์ด๋ค.
์ฌ๊ธฐ๊น์ง ์ฝ์ด์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค ๐๐ปโโ๏ธ
์๋ชป๋ ๋ด์ฉ์ด ์์ผ๋ฉด ์ธ์ ๋ ์ง ์ง์ ํด์ฃผ์ธ์.
๊ฐ์ฌํฉ๋๋ค ๐ซฐ
์ฐธ๊ณ ํ๋ฉด ์ข์ ์์/๋งํฌ
๊ฒฝํ๊ธฐ๋ฐ์ ์ข์ ๊ธ ์ ์ฝ์์ต๋๋ค! ์ ๊ธ์ด ๊ฑธ๋ ค์๋ค๋ ๊ฐ์ฌ๋๋ฆฝ๋๋ค :)