junsobi

Menu

Close

MDX로 SSR 기반 블로그 만들기

Next.js와 Content Collections를 활용해 SSR 기반 MDX 블로그를 구축하는 방법을 알아봅니다.

List

shiba

MDX로 SSR 기반 블로그 만들기

이번 글에서는 **SSR(Server-Side Rendering)**을 기반으로
MDX(Markdown + JSX)를 활용한 Next.js 블로그를 구축하는 방법을 자세히 알아봅니다.
Content Collections 라이브러리를 사용해 효율적인 데이터 관리와 SSR의 장점을 결합한 블로그를 만들어봅시다.


왜 SSR로 만들었을까?

SSR(서버 사이드 렌더링)은 사용자가 페이지를 요청할 때 서버에서 HTML을 생성하여 브라우저로 전송하는 방식입니다.
이 방식은 특히 아래와 같은 이유로 유용합니다:

1. SEO 친화성

SSR은 완전한 HTML을 검색 엔진에 제공하므로 SEO 최적화에 유리합니다.

2. 최신 데이터 제공

SSR은 사용자가 페이지를 요청할 때 데이터를 서버에서 바로 렌더링하기 때문에 항상 최신 상태를 유지할 수 있습니다.

3. 유연한 데이터 관리

MDX와 JSON 메타데이터를 SSR로 처리하면 블로그 콘텐츠를 효율적으로 관리할 수 있습니다.


프로젝트 설정

1. Next.js와 Content Collections 설치

npx create-next-app my-mdx-blog
cd my-mdx-blog
npm install @content-collections/core @content-collections/mdx @fumadocs/content-collections

2. content-collections.ts 설정

프로젝트 최상위 위치에 content-collections.ts파일을 생성하고,
블로그 데이터를 처리하는 컬렉션을 정의합니다:

import { defineCollection, defineConfig } from '@content-collections/core';
import {
  createMetaSchema,
  createDocSchema,
  transformMDX
} from '@fumadocs/content-collections/configuration';
 
const blog = defineCollection({
  name: 'blog',
  directory: 'content/blog',
  include: '**/*.mdx',
  schema: (z) => {
    const docSchema = createDocSchema(z);
    return {
      ...docSchema,
      author: z.string(),
      date: z.string().date().or(z.date()).optional(),
      tags: z.array(z.string()).optional()
    };
  },
  transform: transformMDX
});
 
const blogMetas = defineCollection({
  name: 'blogMeta',
  directory: 'content/blog',
  include: '**/meta.json',
  parser: 'json',
  schema: createMetaSchema
});
 
export default defineConfig({
  collections: [blog, blogMetas]
});
  • blog 컬렉션: MDX 파일과 메타데이터를 관리합니다.
  • SSR을 통해 데이터 로드: 이 설정은 SSR에서 사용하기 위해 데이터를 정리합니다.

3. 데이터 로드 설정

app/source.ts content-collections 에서 데이터를 불러오는 로직을 작성합니다:

import { loader } from 'fumadocs-core/source';
import { createMDXSource } from '@fumadocs/content-collections';
import { allBlogs, allBlogMetas } from '../../content-collections.ts';

export const blog = loader({
  baseUrl: '/blog',
  source: createMDXSource(allBlogs, allBlogMetas)
});

4. SSR 기반 블로그 리스트 구현

app/blog/page.tsx

import Link from 'next/link';
import { blog } from '@/app/source';
 
export default function BlogPage() {
  const posts = [...blog.getPages()].sort(
    (a, b) =>
      new Date(b.data.date ?? b.file.name).getTime() -
      new Date(a.data.date ?? a.file.name).getTime()
  );
 
  return (
    <main className="my-14">
      <h1 className="mb-8 text-5xl font-bold">블로그</h1>
      <ul>
        {posts.map((post, index) => (
          <li key={index}>
            <Link href={post.url}>
              <a>
                <h2>{post.data.title}</h2>
                <p>{post.data.description}</p>
              </a>
            </Link>
          </li>
        ))}
      </ul>
    </main>
  );
}

5. 개별 포스트 페이지 구현

app/blog/[slug]/page.tsx

import { blog } from '@/app/source';
 
export default function BlogPostPage({ params }: { params: { slug: string } }) {
  const post = blog.getPage([params.slug]);
  if (!post) {
    return <div>포스트를 찾을 수 없습니다.</div>;
  }
 
  const { title, description, content } = post.data;
 
  return (
    <article>
      <h1 className="text-4xl font-bold">{title}</h1>
      <p className="text-gray-500">{description}</p>
      <div>{content}</div>
    </article>
  );
}

SSR의 작동 원리

  1. 서버에서 데이터 로드: content-collections를 통해 MDX 파일과 메타데이터를 로드합니다.
  2. 데이터 전달: source.ts에서 데이터를 로드하고, 페이지 컴포넌트로 전달합니다.
  3. 페이지 렌더링: 페이지 컴포넌트에서 데이터를 활용하여 렌더링합니다.

SSR 기반 블로그의 장점

  • SEO 최적화: 검색 엔진 최적화를 위한 완전한 HTML 제공.
  • 최신 데이터: 사용자가 요청할 때마다 최신 데이터를 제공.
  • 유연한 데이터 관리: MDX와 JSON 메타데이터를 통한 효율적인 데이터 관리.
  • 확장성: 동적 라우팅과 데이터 로딩을 통한 블로그 확장.

마치며

MDX와 Content Collections를 활용하면 강력한 SSR 기반 블로그를 구축할 수 있습니다. 이 방법은 최신 데이터를 제공하면서도 SEO 최적화에 유리하며, 확장성과 관리 편의성을 모두 갖춘 솔루션입니다.

good