231031(ํ) ์ฑ์ฅ
๐ค ์ฑ์ฅ์ผ์ง 7.0
์ฑ
ํ๋ณตํ ์ด๊ธฐ์ฃผ์์(์จ์ธ ๋ค์ด์ด)
์ ๋ด์ฉ์ ์๊ทน๋ฐ์ ์์ํ๋ ์๋ฐํ ์ฑ์ฅ๊ธฐ๋ก
์ด์์๋ ๊ฝ๊ณผ ์ฃฝ์ ๊ฝ์ ์ด๋ป๊ฒ ๊ตฌ๋ณํ๋๊ฐ?
์ฑ์ฅํ๊ณ ์๋ ๊ฒ์ด ์ด์ ์๋ ๊ฒ์ด๋ค.
์๋ช ์ ์ ์ผํ ์ฆ๊ฑฐ๋ ์ฑ์ฅ์ด๋ค!
โ (7.0)<์์ ๊ฐํธ>
ํ์ธ๋ง ํ์ต๋ฒ
์ ์๊ฒ ๋๋งํผ, ์ฑ์ฅ์ผ์ง๋ ์ ๋ง ๊ทธ ๋ ์ ํค์๋ ์ค์ฌ์ผ๋ก ๊ฐ๋จํ๊ฒ ์ ๋ฆฌํ๋๋ก ํ๋ค.
์ด์์ฒด์
์ด์์ฒด์ : ์ปดํจํฐ ํ๋์จ์ด๋ฅผ ๋ค๋ฃจ๊ธฐ ์ฝ๊ฒ ํด์ฃผ๋ ์ํํธ์จ์ด. ๋จ์ํ๊ฒ ์๊ฐํ๋ฉด ์ปดํจํฐ๋ผ๋ ํ๋์จ์ด๋ฅผ ์ฝ๊ฒ ๋ค๋ฃจ๊ธฐ ์ํ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํด์ค๋ค๊ณ ์๊ฐํด๋ ๋๋ค.(๋ฌผ๋ก ์ด์ธ์๋ ์ ๋ง ๋ง์ ๊ฒ๋ค์ ๊ด๋ฆฌํ์ง๋ง!)
์ด์์ฒด์ ์ ๋ชฉ์
- ์ฃผ์ด์ง ํ๋์จ์ด๋ฅผ ์ต๋ํ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๊ธฐ
- ์ปดํจํฐ ์์คํ ์ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ ์ ์๋ ํ๊ฒฝ ์ ๊ณต
*๋ฉํฐํ ์คํน: ์ฌ๋ฌ ๊ฐ์ ํ๋ก๊ทธ๋จ์ ๋์์ ์คํํ๋ ๊ฒ => CPU๋ฅผ ๋น ๋ฅด๊ฒ ์ ํํ๋ฉด์ ๋์์ ์คํํ๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๊ฒ ํ๋ ๊ฒ
์ด์์ฒด์ ์ ๊ตฌ์ฑ
- CPU => CPU ์ค์ผ์ฅด๋ง: CPU๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๊ธฐ ์ํด CPU๊ฐ ์ด๋ค ํ๋ก์ธ์ค๋ฅผ ๋จผ์ ์คํํ ์ง ๊ฒฐ์ ํ๋ ๊ฒ
- ๋ฉ๋ชจ๋ฆฌ => ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ: ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๊ธฐ ์ํด ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ด๋ป๊ฒ ํ ๋นํ ์ง ๊ฒฐ์ ํ๋ ๊ฒ
- ๋์คํฌ => ํ์ผ ์์คํ (๊ด๋ฆฌ): ๋์คํฌ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๊ธฐ ์ํด ๋์คํฌ์ ์ด๋ป๊ฒ ํ์ผ์ ์ ์ฅํ ์ง ๊ฒฐ์ ํ๋ ๊ฒ
- I/O ์ฅ์น => ์ ์ถ๋ ฅ ๊ด๋ฆฌ: ์ ์ถ๋ ฅ ์ฅ์น๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๊ธฐ ์ํด ์ ์ถ๋ ฅ ์ฅ์น๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ ์ง ๊ฒฐ์ ํ๋ ๊ฒ
- ํ๋ก์ธ์ค ๊ด๋ฆฌ: ํ๋ก์ธ์ค๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๊ธฐ ์ํด ํ๋ก์ธ์ค๋ฅผ ์ด๋ป๊ฒ ๊ด๋ฆฌํ ์ง ๊ฒฐ์ ํ๋ ๊ฒ
Next.js์ contentlayer๋ฅผ ์ด์ฉํ ๋ธ๋ก๊ทธ ๋ง๋ค๊ธฐ
์ค๋์ ์์ฑํ ๋ธ๋ก๊ทธ ๊ธ๋ค์ ๋ณด์ฌ์ค posts
ํ์ด์ง์ ๊ฐ ๊ธ์ ์์ธํ์ด์ง์ ํด๋นํ๋ posts/xxx/xxx...
ํ์ด์ง๋ฅผ ๊ตฌํํ์๋ค. ๊ธฐ์กด ๋ธ๋ก๊ทธ์์ ์์ฑํ๋ md ํ์ผ๋ค์ ์ด๋ป๊ฒ ๊ทธ๋๋ก ๊ฐ์ ธ์์ ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ๋ฅผ domain์ path๋ก ์ ์ฉํด์ ์ ์ ์ธ ํ์ด์ง๋ฅผ ๋ณด์ฌ์ค ์ ์์๊น ๊ณ ๋ฏผํ๋ ์ค ์ฌ๋ฌ ๊ตฌ๊ธ๋ง ๋์ contentlayer
๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์๊ฒ ๋์ด ์ ์ฉํด๋ณด์๋ค.
์๋์ ๊ณต์๋ฌธ์๋ฟ ์๋๋ผ ๋ค๋ฅธ ๋ถ๋ค์ ๋ธ๋ก๊ทธ์ ์๋ ์ ์ ๋ฆฌ๊ฐ ๋์ด์์ด์ ๋ฌธ์ ์์ด posts ํ์ด์ง์ ๊ฐ post ํ์ด์ง๋ฅผ ๊ตฌํํ ์ ์์๋ค.(๋ฐ๋ผ์ ์ฌ๊ธฐ์๋ ๋ฐ๋ก ์ ๋ฆฌํ์ง ์์ ์์ !)
๋ค๋ง, ์๋ ๋ ํผ๋ฐ์ค์๋ ์กฐ๊ธ ๋ค๋ฅด๊ฒ ๋ธ๋ก๊ทธ ๊ธ๋ค์ ๋๋ ํ ๋ฆฌ path๋ฅผ ๊ทธ๋๋ก domain path์ ์ ์ฉํ๊ธฐ ์ํด ๊ฒช์๋ ๋ด์ฉ๋ง ์ ๋ฆฌํด๋ณด๊ณ ์ ํ๋ค.
๋จผ์ app/src/posts/[...slug]/page.tsx
ํ์ผ์ ์์ฑํ๊ณ ์๋์ ๊ฐ์ด ์ฝ๋๋ฅผ ์์ฑํ์๋ค.
import { format, parseISO } from 'date-fns';
import { allPosts } from 'contentlayer/generated';
export const generateStaticParams = async () => {
// allPosts์ ๊ฐ post๋ 'a/b/c/d' ํํ๋ก md ํ์ผ์ ๋๋ ํ ๋ฆฌ path๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ๋ฐ๋ผ์ split('/')์ ํตํด ๊ฐ path๋ฅผ ๋๋์ด slug๋ก ์ฌ์ฉํ์๋ค.
return allPosts.map((post) => ({ slug: post._raw.flattenedPath.split('/') }));
};
export const generateMetadata = ({ params }: { params: { slug: string[] } }) => {
// ์์ ๋ฐ๋๋ก params.slug๋ฅผ join('/')์ ํตํด 'a/b/c/d' ํํ๋ก ๋ง๋ค์ด์ฃผ๊ณ ์ด๋ฅผ ํตํด post๋ฅผ ์ฐพ์์ title์ ๋ฐํํ์๋ค.
const post = allPosts.find((post) => post._raw.flattenedPath === params.slug.join('/'));
if (!post) throw new Error(`Post not found for slug: ${params.slug.join('/')}`);
return { title: post.title };
};
export default function PostPage({ params }: { params: { slug: string[] } }) {
// ์ฌ๊ธฐ๋ ๋ง์ฐฌ๊ฐ์ง๋ก params.slug๋ฅผ join('/')์ ํตํด 'a/b/c/d' ํํ๋ก ๋ง๋ค์ด์ฃผ๊ณ ์ด๋ฅผ ํตํด post๋ฅผ ์ฐพ์์ ๋ฐํํ์๋ค.
const post = allPosts.find((post) => post._raw.flattenedPath === params.slug.join('/'));
if (!post) throw new Error(`Post not found for slug: ${params.slug.join('/')}`);
return (
<article className="mx-auto max-w-xl py-8">
<div className="mb-8 text-center">
<time dateTime={post.date} className="mb-1 text-xs text-gray-600">
{format(parseISO(post.date), 'LLLL d, yyyy')}
</time>
<h1 className="text-3xl font-bold">{post.title}</h1>
</div>
<div
className="[&>*:last-child]:mb-0 [&>*]:mb-3"
dangerouslySetInnerHTML={{ __html: post.body.html }}
/>
</article>
);
}
์๋ง ์๋ ์ฐธ๊ณ ๊ธ์ ๋ฐ๋ผ์ ์งํํ๊ณ ์์ ์ฝ๋๋ฅผ ํ์ธํ๋ฉด ์ด๋ป๊ฒ ๋์ํ๋์ง ์ดํดํ ์ ์์ ๊ฒ์ด๋ค.
์์งํ ์์ ์ Next.js ๊ณต์๋ฌธ์๋ฅผ ์ฝ์ผ๋ฉด์ Catch-all Segments
ํํธ๋ ๋๋์ฒด ์ธ์ ์ฐ๋ ค๋ ์๊ฐํ๋๋ฐ, ์ผํ ๋ดค๋ ๋ด์ฉ์ด ๊ธฐ์ต๋ ๋๋ถ์ ์ ์ฉํ ์ ์์๋ค.
๐ ํ๊ณ
ํ์คํ ๋๋ ๋๋ฌด ํ๋ํ๋๋ฅผ ๋ณด๋ฉด์ ๊ณต๋ถํ๊ธฐ๋ณด๋จ ๋จผ์ ์ฒ์ ํ ๋ฒ ๋ณด๊ณ ๋์ ๋๋ฌด๋ฅผ ๋ณด๋ ๊ฒ์ด ๋ ํจ์จ์ ์ธ ๊ฒ ๊ฐ๋ค. ์ฐ์ ์ด๋ฐ ์์ผ๋ก CS์ ๋ํ ์ ์ฒด์ ์ธ ์์ผ๋ฅผ ๋ํ๊ณ ์ข๋ ๊น๊ฒ ๋ค์ด๊ฐ๊ณ ์ถ์ ์ฃผ์ ๋ฅผ ์ ์ ํด์ ๊ณต๋ถํด๋ณด๋ ๊ฒ๋ ์ข์ ๊ฒ ๊ฐ๋ค. Next.js๋ก ๋ธ๋ก๊ทธ ๋ง๋๋ ํํธ์ ๊ฒฝ์ฐ, ์ฌ์ค posts ๋ถ๋ถ์ด ๋ง๋งํ๋๋ฐโฆ ์๊ฐ๋ณด๋ค ๊ธ๋ฐฉ ํด๊ฒฐ์ด ๋์๋ค. ์ญ์ ๊ฐ๋ฐ์ ๋ญ ๋ง๋ค๋ฉด์ ๋ฐฐ์ฐ๋ ๊ฒ ๊ฐ์ฅ ๋น ๋ฅด๋ค๋ ๊ฒ์ ๋ค์ ํ ๋ฒ ๋๊ผ๋ค.