개발 블로그에서는 빠질 수 없는 부분이죠. 마크다운 문법으로 작성된 내용을 어떻게 블로그로 불러오는지 알아보려고 합니다.
content.mdx
의 구성
Zenithium에서는 content.mdx
라는 이름의 파일로 포스트를 관리하고 있습니다. 그럼 이 내부에는 어떤 구조로 정보가 담겨있을까요?
Front Matter
개별 포스트 파일의 최상단에는 포스트의 기본 정보가 담겨있는 영역이 있습니다. 이 부분을 Metadata 혹은 Front Matter 라고 합니다.
Front Matter에 담긴 정보를 활용해 각 페이지에서 제목, 설명, 작성일, 시리즈 등을 사용자에게 보여줄 수 있는 것이죠.
담고 싶은 정보의 key를 정하고 이에 해당하는 value를 우측에 적으면 됩니다. 이 때, Typescript의 경우 미리 Front Matter의 타입을 정의해주면 이후 데이터를 가공할 때 굉장히 편해집니다.
Content
MDX에서의 Front Matter가 포스트의 기본 정보라면 Content는 본문 내용입니다. 실제로 Front Matter는 포스트의 내용에 담기지 않지만 Content는 적혀있는 내용이 모두 화면에 나타나게 됩니다.
Front Matter가 끝나는 지점부터 Content의 시작이니 이 부분부터 내용을 적어나가면 됩니다.
그런데 Front Matter를 매 포스팅마다 일일이 적어야 하는게 번거롭다구요? 물론 좋은 방법이 있습니다.
추천 코드 스니펫
다양한 코드 편집기에서는 코드 프리셋을 등록하고 사용할 수 있는 코드 스니펫을 제공하고 있습니다. 이 포스트를 보는 분들 중에도 여러가지 코드 스니펫을 등록해서 사용중인 분들도 계실텐데요.
MDX도 이 코드 스니펫을 사용해서 Front Matter를 더욱 편하게 작성할 수 있습니다. 저는 김평안님의 블로그 소스 코드에서 코드 스니펫을 참고해 제 방식으로 수정해서 사용했어요.
이렇게 코드 스니펫을 사용하면 prefix로 설정한 문구와 tab 키로 빠르게 Front Matter를 작성할 수 있습니다.
MDX 파일 불러오기
MDX로 포스팅을 작성했다면 불러와야겠죠?
이 때의 과정은 MDX 파일을 어디에 담아두고 쓰고 있는지에 따라서 방법이 달라지게 됩니다.
외부 DB 등을 이용하는 경우 API나 DB Query를 사용해 불러오면 되지만 저는 프로젝트 내부에 위치시켜 사용하기 위해 fs
모듈을 이용했습니다.
fs
의 readFileSync
는 파일명과 확장자를 포함한 파일 경로를 인자로 받아 파일의 내용을 불러오게 됩니다. 파일의 내용을 불러왔으니 이제 사용하면 될까요?
현재 이 데이터는 Buffer의 형태로 반환되기 때문에 이를 MDX를 파싱할 수 있는 파서를 사용해 가공할 수 있는 형태의 문자열로 변환해야 합니다. 저는 이 과정에 gray-matter 라이브러리의 matter
함수를 사용했습니다.
그럼 이 함수를 사용해 모든 포스트를 불러옵시다.
저는 포스트를 /blog-contents/{slug}/content.mdx
의 경로에서 관리하고 있으니 blog-contents 디렉토리의 모든 slug 디렉토리를 순회하며 content.mdx
를 readMDXFile
함수로 파싱하면 되겠죠?
fs
의 readdirSync
는 해당 경로에 있는 모든 디렉토리 이름을 배열에 담게 되는데, 이 배열을 순회하며 content.mdx
가 담긴 경로를 만들면 됩니다. filePath
가 바로 그 경로이죠.
이 경로를 아까 만들어 둔 readMDXFile
함수에 담으면 gray-matter의 matter
함수가 파싱한 데이터를 받게 됩니다.
이 데이터는 정말 친절하게도 Front Matter와 Content로 잘 나누어서 전달해 주게 되고 Front Matter의 경우 객체의 형태로 반환되기 때문에 바로 꺼내서 사용할 수 있습니다.
추가로 필요한 데이터인 slug와 dirName을 포함해서 모든 포스트 데이터를 만들어 반환하도록 했습니다.
Front Matter와 Content 사용하기
앞에서 만든 로직으로 MDX를 파싱했다면 그대로 사용할 수 있을까요?
Front Matter는 가능하지만 Content는 아직 아닙니다.
matter
로 파싱한 Content는 아직 마크다운 문자열 형태이기 때문이죠. 이를 마크업의 형태로 한번 더 파싱해야 합니다.
콘솔로 확인한 Content
지금은 마크다운 문법이 그대로 문자열로 넘어온 형태를 가지고 있는데 다음 포스트에서는 이 문자열을 마크업의 형태로 파싱하는 라이브러리인 next-mdx-remote/rsc
에 대해서 다뤄보겠습니다.
추가로 matter
를 compileMDX
로 전환하는 과정도 생각중인데 만일 리팩토링을 하게 되면 이 부분도 기록으로 남겨볼 생각입니다.