블로그 개발기

22년도 여름에 개발을 시작하고 얼마 안되었을때 기술 블로그를 작성하고자 했습니다

기존에는 공부할때 notion에 나만 보던 용도로 글을 작성했었지만, 당시에 스터디를 하면서 다른사람들에게 공유하고자 글을 작성하다보면 이해를 시키기위해 글을 쓰다보니 깊게 이해하게 되다 보니 블로그를 운영하여 기록을 하려고 했습니다.

블로그 플랫폼으로 Tstory, velog, Medium 등을 사용해보려 했지만, 플랫폼을 사용하게 되면 내가 작성한 글을 관리하거나, 커스터마이징하기가 어려워서 직접 블로그를 만들어 보기로 했습니다.

처음 고려했던거는 가장 당시에 유행했던 jekyll, gastby과 같은 정적 사이트 생성기를 사용하려 했었는데 당시에 저는 Nextjs를 공부를 하고 있었기에 Nextjs기반의 블로그를 만들어 보기로 했습니다.

또한 Notion에 글을 작성해 두었었는데 당시에 Notion API기능이 공개 되었고, 이를 활용하여 NextJs + Notion으로 블로그를 만들어 보기로 했습니다.

첫번째 블로그

nextjs-notion-blog

노션에서 제공하는 @notionhq/client 라이브러리를 사용해서 Notion Database의 데이터를 가져온뒤 Nextjs getStaticProps로 SSG방식으로 페이지를 생성했습니다.

당시에 notion API를 기반으로 블로그를 쉽게 만들기 위한 라이브러리도 존재했엇는데, 전체 코드를 작성하고자 하는 욕심이 생기다 보니 직접 모든 부분을 구현하게 되었습니다.

데이터를 가져오고 해당 데이터를 html코드로 일일이 변환하는 부분을 구현을 했었는데,

notion API를 사용하게 되면 DB와 관리자 페이지를 따로 만들지 않아도 되어서 좋았는데 디자인을 디테일하게 커스터마이징 하기가 어려웠습니다. notion에서는 한줄한줄을 block단위인 문단으로 관리했는데, notion API로 가져오는 값에는 공백이 같이 넘어 오지 않아서 텍스트의 문단을 나누는데 구분을 할 수 없다보니, 가독성있게 글을 작성하려면 notion에 글을 작성할때 일일이 제가 개발한 블로그 포멧에 맞춰서 작성을 해야 했습니다. 그리고 notion과 notionAPI가 업데이트할때마다 해당 부분을 반영해줘야 했어서 타 플랫폼에 의존성이 생기게 되어서 새롭게 블로그를 만들게 되었습니다.


두번째 블로그

next-blog

두번째 블로그는 contentlayer 라이브러리 사용하여 markdown기반의 블로그를 만들었습니다. contentlayer는 빌드타임에 markdown파일을 읽어서 json파일로 만들어서 사용할 수 있게 해주는 라이브러리입니다.

노션과 달리 MDX로 글을 작성하다보니 이후에 블로그를 이전하기에도 용의 할꺼라 생각했으며, rehype, remark라이브러리를 플러그인 형태로 추가하여 제가 원하는 기능을 쉽게 추가할 수 있어서 선택하게 되었습니다.

해당 블로그는 한동안 잘 사용하고 있다가 문제점을 발견하게 되었습니다. contentlayer 개발팀이 잠정 중단을 했는데, next는 14버전이 나오면서 next14에서 지원되지 않는 오류가 있었습니다. 그대로 사용을 해도 상관 없었으나 과거에 next13 버전이 처음 출시 되었을때 여러 라이브러리를 해당 버전에 맞춰서 업데이트를 해줄때 문제가 많아 해결하기 어려웠던 경험이 있다보니, UI를 업데이트 하면서 해당 버전도 같이 업데이트 하기로 했습니다.


세번째 블로그

세번째 블로그에는 contentlayer이전에 많이 사용하던 next-mdx-remote 라이브러리를 사용하여 만들었습니다. contentlayer와 비슷한 형식으로 mdx파일을 가져와서 마크다운으로 변환하여 사용할 수 있으면 rehype, remark라이브러리를 사용하여 커스터마이징을 할 수 있었습니다.

또한 MDX를 지원했기에 글을 작성시에 커스텀컴포넌트를 사용하여 글을 작성할 수 있었어서, MDX값을 가져와서 데이터를 가공하는 부분을 제외하면 이전에 만든 코드를 제활용하여 만들 수 있게 되었습니다.

아래와 같이 MDX파일을 읽어와서 props로 넘겨주고 커스텀 components를 넘겨주게 되면 화면에 렌더링 시킬 수 있습니다.

MdxContent.tsx
import { MDXRemote, type MDXRemoteSerializeResult } from "next-mdx-remote";
import { MdxComponents } from "./MdxComponents";

type MdxContentProps = {
  source: MDXRemoteSerializeResult;
};

export function MdxContent({ source }: MdxContentProps) {
  return <MDXRemote {...source} components={MdxComponents} />;
}

데이터를 가져오는 부분의 경우에는 mdx 파일을 읽어서 가져온뒤 next-mdx-remote의 serialize함수를 사용하여 mdx파일을 html로 변환하여 넘겨주면 됩니다.

getPost.tsx
async function getPost(filepath: string): Promise<Post<Frontmatter>> {
  const raw = await fs.readFile(filepath, 'utf-8');
 
  const serialized = await serialize(raw, {
    parseFrontmatter: true,
  });
 
  const frontmatter = serialized.frontmatter as Frontmatter;
 
  return {
    frontmatter,
    serialized,
  };
}

그리고 serializerehyperemark를 사용하여 커스터마이징을 할 수 있습니다.

  const serialized = await serialize(raw, {
    parseFrontmatter: true,
    mdxOptions: {
      rehypePlugins: [
        rehypeSlug,
        remarkGfm,
        remarkUnwrapImages,
        rehypeCodeTitles,
        rehypePrism as any,
        [
          rehypeAutolinkHeadings,
          {
            properties: {
              className: ["anchor"],
              ariaLabel: "anchor",
            },
          },
        ],
      ],
    },
  });

디자인의 경우 기존과 달리 최소한으로 단순하게 만들고자 하였고, 깃허브의 shuding님의 블로그를 참고하여 만들었습니다.