Just Do IT!

Contentlayer 라이브러리 next.js에서 활용하기 본문

개발 공부/Next JS

Contentlayer 라이브러리 next.js에서 활용하기

MOON달 2024. 4. 6. 17:03
728x90

요즘 next.js로 정적 블로그 만들기 관련 글들을 살펴보다가 공통적으로 나오는 contentlayer에 대해 알게 되었다.

next.js 13버전에서 사용했던 것 같은데, next.js14에서도 적용할 수가 있었다.

아직 블로그 글을 작성하지 않아서 모르는데, 추후에 확실히 적용되는지 볼 예정이다.

 

우선, Next.js의 getStaticPaths 함수에 대해 알아야 한다.

 

 

getStaticPaths?

 

 

정적 생성(static generation)을 위한 경로를 동적으로 설정하는 메서드이다.

이 함수는 next.js 에서 동적 경로를 사용하는 페이지에 사용된다.

 

getStaticPaths 함수는 비동기 함수로 작성이 되고, 경로 데이터를 동적으로 생성하는 로직을 구현해야 한다.

이 함수의 반환 값은 객체 형태로, paths와 fallback 두 가지 속성을 포함해야 합니다.

  • paths: 동적으로 생성될 경로의 리스트를 포함합니다. 이 경로들은 페이지의 경로에 매칭되어 해당 페이지의 정적 HTML 파일이 생성된다.
  • fallback: fallback 옵션은 정적 경로가 없는 경우 어떻게 동작할지를 결정한다. fallback 값으로 false를 설정하면 정적 경로가 아닌 페이지는 404 페이지로 처리된다. fallback 값으로 true를 설정하면 정적 경로가 아닌 페이지에 대해서는 요청이 들어올 때 동적으로 생성된다.

 

이렇듯, 정적 HTML 파일을 생성한다는 뜻이다.

이런 정적 콘텐츠를 관리할 목적으로 contentlayer 라이브러리를 사용하게 되었다.

 

 

 

 

 

 

 

 

 

Contentlayer란?

 

Next.js와 함께 사용할 수 있는 정적 콘텐츠 관리 도구이다.

contentlayer를 사용하면 마크다운(markdown) 파일이나 다른 데이터 소스에서 콘텐츠를 가져와 Next.js 어플리케이션에 쉽게 통합할 수 있다.

 

Contentlayer는 마크다운 파일에 대한 정적 타입 지원을 제공하며, TypeScript와 함께 사용할 수 있다.

마크다운 파일을 통해 페이지의 콘텐츠를 작성하고, Contentlayer가 해당 파일을 읽어 데이터 객체로 변환하여 사용할 수 있는 것이다. 이를 통해 마크다운 파일에서 가져온 콘텐츠를 동적으로 렌더링하고 페이지에 통합할 수 있다.

 

Contentlayer는 데이터를 가져오는 방법을 정의하는 데이터 모델과 마크다운 파일에 대한 데이터 변환기를 사용한다.

 

공식 깃허브

https://github.com/contentlayerdev/contentlayer

 

GitHub - contentlayerdev/contentlayer: Contentlayer turns your content into data - making it super easy to import MD(X) and CMS

Contentlayer turns your content into data - making it super easy to import MD(X) and CMS content in your app - contentlayerdev/contentlayer

github.com

 

처음에

npm install contentlayer next-contentlayer date-fns

 

공식 tutorial에 적힌대로 설치를 하려고 했더니,

터미널에서 에러가 나고 설치되지 않았다.

이는 next-contentlayer가 next 버전 12, 13은 가능하지만 현재 프로젝트의 버전이 14이기 때문이었다.

 

관련 내용에 대해 찾아보다가 Issue에 이를 해결하는 방법이 있음을 알게 되었다.

https://github.com/contentlayerdev/contentlayer/issues/575

 

Support NextJS 14 · Issue #575 · contentlayerdev/contentlayer

npm ERR! code ERESOLVE -- 14:57:32.907 | npm ERR! ERESOLVE could not resolve 14:57:32.908 | npm ERR! 14:57:32.908 | npm ERR! While resolving: next-contentlayer@0.3.4 14:57:32.908 | npm ERR! Found: ...

github.com

 

위의 issue에 적힌 해결 방법으로 아래 명령어로 성공적으로 설치할 수 있었다.

 

npm install contentlayer next-contentlayer date-fns --legacy-peer-deps

 

 

설치 후에는 아래 과정을 따라야 한다.

 

next.config.js에 contentlayer wrap 하기 (Next.js 플러그인으로 설정)
const { withContentlayer } = require("next-contentlayer");

module.exports = withContentlayer({
  reactStrictMode: true,
});

 

tsconfig.js에 contentlayer 설정

 

"compilerOptions": {
    ...
    "baseUrl": ".",
    "paths": {
      "contentlayer/generated": ["./.contentlayer/generated"]
    }
},
"include": [
    ...
    ".contentlayer/generated"
], ...

 

contentlayer.config.ts 파일 생성

 

import { defineDocumentType, makeSource } from "contentlayer/source-files";
 
export const Post = defineDocumentType(() => ({
  name: "Post",
  contentType: "mdx",
  filePathPattern: `**/*.mdx`,
  fields: {
    title: { type: "string", required: true },
    date: { type: "string", required: true },
    description: { type: "string", required: true },
  },
}));
 
export default makeSource({
  contentDirPath: "posts",
  documentTypes: [Post],
});

 

이는 content schema를 정의하는 것이다.

블로그 글 작성을 위해 Post라는 document type을 정의하는 것이다.

 

 

스키마에 맞는 md 파일 생성
// text.mdx

---
title: 첫번째 블로그글
date: 2024-04-18
description: 설명란입니다.
---

## 제목

- 내용 1
- 내용 2

 

여기서 mdx란?

Markdown과 JSX를 결합한 방식이다. 그래서 이를 통해 Markdown 문서에 React 컴포넌트를 넣을 수 있다.

 

 

위의 과정을 거친 후 다시 npm run dev로 실행하면, contentlayer가 실행되어 마크다운 파일을 기반으로 데이터를 생성한다. 데이터를 생성한 후에는 contentlayer/generated 디렉토리에 생성된 데이터 파일이 위치하게 된다.

 

 

 

실제로 내가 구현하고 있는 블로그에 적용한 예시이다.

// pages/blog.tsx

import { allPosts } from "contentlayer/generated";
import BlogPost from "../components/BlogPost";
import Container from "../components/Container";
import { InferGetStaticPropsType } from "next";

const Blog = ({ posts }: InferGetStaticPropsType<typeof getStaticProps>) => {
  return (
    <Container>
      <div className={`mt-10 flex flex-col`}>
        {posts?.map((post) => (
          <BlogPost
            date={post.date}
            title={post.title}
            des={post.description}
            slug={post._raw.flattenedPath}
            key={post._id}
          />
        ))}
      </div>
    </Container>
  );
};

export const getStaticProps = async () => {
  const posts = allPosts.sort(
    (a, b) => Number(new Date(b.date)) - Number(new Date(a.date))
  );

  return {
    props: {
      posts,
    },
  };
};

export default Blog;

 

  • allPosts는 Contentlayer에서 생성된 파일인데, 여기서 모든 블로그 포스트를 가져온다.
  • BlogPost는 블로그 포스트를 표시하는 데 사용되는 컴포넌트이다.
  • InferGetStaticPropsTypegetStaticProps 함수의 반환 유형을 유추하는 데 사용된다.
  • getStaticProps 함수를 정의하기 전에 InferGetStaticPropsType를 사용하여 함수의 반환 유형을 추론한다.
    • getStaticProps 함수는 Next.js의 정적 생성 기능을 사용하여 페이지의 초기 데이터를 가져온다.
    • allPosts를 사용하여 모든 블로그 포스트를 가져온 후, 날짜별로 정렬한다.
    • 반환된 데이터는 posts props로 전달된다.

 

getStaticProps란 사전 렌더링 프로세스 동안 이 함수를 실행한다는 뜻이다. 즉, 빌드할 때 실행된다.

params를 받아 그에 해당하는 paths를 받아온다. 미리 생성된 paths는 캐싱되기 때문에 라우터로 페이지를 이동할 때 굉장히 빠른 랜더링 속도를 보여준다.

 

위의 함수는 정적 페이지를 만드는데 도움을 주는 함수이다. 그래서 이를 적용하였다.

 

 

 

 

 

 

 


우선은 next.js에 대해 잘 몰라서 아래 블로그 글을 참고하면서 따라해보고 있다.

코드를 따라치면서 모르는 건 이렇게 블로그에 정리하면서 구현해볼 예정이다.

전부 완성된 후에는 내 식으로 조금씩 바꿀 거라서 우선은 클론 코딩 형식으로 진행하고 있다 ㅎㅎ

 

 

 

 

 

참고 블로그

https://miryang.dev/blog/build-blog-with-nextjs

https://velog.io/@blcklamb/Next-%ED%8F%AC%ED%8A%B8%ED%8F%B4%EB%A6%AC%EC%98%A4-02.-%EB%A7%88%ED%81%AC%EB%8B%A4%EC%9A%B4-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EC%84%B8%ED%8C%85

 

'개발 공부 > Next JS' 카테고리의 다른 글

Next.js + Typescript 초기 세팅하기  (0) 2024.02.27