본문으로 건너뛰기

"obsidian" 태그로 연결된 2개 게시물개의 게시물이 있습니다.

모든 태그 보기

sync-posts는 Obsidian Markdown을 어떻게 Docusaurus 글로 바꾸는가

· 약 2분
dev-burnern
Developer

핵심 요약

scripts/sync-posts.mjs는 Obsidian에서 작성한 Markdown을 Docusaurus가 안정적으로 빌드할 수 있는 블로그 글로 정규화한다. 핵심은 글쓴이가 매번 메타데이터와 링크 문법을 손으로 맞추지 않아도 되도록, 파일 경로와 본문을 기준으로 필요한 정보를 자동 보정하는 것이다.

이 스크립트는 글 작성 도구와 배포 도구 사이의 번역 계층이다. Obsidian의 빠른 기록 경험은 유지하고, 공개 블로그에는 Docusaurus가 이해할 수 있는 구조만 남긴다.

문제 상황

Obsidian은 개발 기록을 빠르게 남기기 좋지만, 그 문법이 정적 블로그에 그대로 맞지는 않는다. [[문서]] 형태의 wiki link는 Docusaurus 라우트가 아니고, > [!note] 같은 callout은 Docusaurus admonition과 다르다.

frontmatter도 반복 비용이 있다. 글이 늘어나면 category, tags, slug, authors, draft를 매번 같은 기준으로 채워야 한다. 이 작업을 사람이 직접 하면 누락과 불일치가 생기기 쉽다.

구현 방식

sync 단계는 먼저 posts/ 아래의 Markdown과 MDX 파일을 순회한다. Excalidraw, 내부 문서, 숨김 폴더처럼 공개 블로그에 올리지 않을 파일은 제외한다.

각 글은 gray-matter로 frontmatter와 본문을 분리한 뒤 정규화한다. title이 없으면 첫 번째 H1에서 가져오고, date가 없으면 안전한 기본값을 넣는다. categorytags는 파일 경로에서 생성하며, slug는 직접 지정하지 않았을 때 경로 기반으로 만든다.

본문 변환은 코드 블록을 먼저 보호한 뒤 수행한다. 코드 블록 안의 [[...]]나 callout 예제가 실제 링크로 바뀌면 안 되기 때문이다. 이후 Obsidian callout을 Docusaurus admonition으로 바꾸고, wiki link는 실제 대상 파일을 찾아 블로그 permalink로 변환한다.

마지막으로 공개 글만 모아 static/posts.json을 만든다. 이 파일은 검색 페이지와 시리즈 내비게이션에서 사용한다. draft: true 글은 작성 중인 상태로 보고 검색 인덱스와 AI 검색 문맥에서 제외한다.

검증 방법

핵심 변환 로직은 Vitest로 검증한다. 숫자 접두어 제거, tag 정규화, slug 정규화, 경로 기반 category/tag 추출, callout 변환, wiki link 변환, frontmatter 기본값 보정이 테스트 대상이다.

로컬에서는 npm run sync로 경고 모드 동기화를 실행한다. CI와 배포 전에는 npm run sync:strict를 사용한다. strict 모드는 slug 충돌, broken wiki link, 처리 실패, 메타데이터 품질 문제를 실패로 보고 빌드를 막는다.

개선 방향

다음 단계는 변환 결과를 더 관찰 가능하게 만드는 것이다. 예를 들어 broken wiki link 리포트를 별도 파일로 남기고, 글별 변환 전후 diff를 요약하면 배포 전에 문제를 더 빨리 찾을 수 있다.

또한 slug 충돌은 현재 strict 실패 조건이지만, 앞으로는 충돌 후보를 더 친절하게 제안할 수 있다. 파일 경로 기반 slug를 유지하되, 같은 이름의 글이 늘어날 때 어떤 경로에서 충돌했는지 명확히 보여주는 방향이 좋다.

Obsidian 기반 기술블로그 파이프라인을 만든 이유

· 약 3분
dev-burnern
Developer

개발 기록은 작성할 때보다 다시 찾아 쓰고 공유할 때 가치가 커진다. 문제는 개인 지식 관리 도구와 공개 블로그가 요구하는 형식이 다르다는 점이다. Obsidian은 빠르게 연결하고 메모하기 좋지만, 그 문법을 그대로 정적 블로그에 올리면 링크, 콜아웃, 메타데이터가 깨지기 쉽다.

이 블로그는 그 간극을 줄이기 위해 만들었다. Obsidian에서는 작성 경험을 유지하고, 배포 단계에서는 Docusaurus가 안정적으로 빌드할 수 있는 문서로 정규화한다.

문제 상황

처음에는 글마다 title, date, slug, tags를 직접 관리했다. 글 수가 적을 때는 큰 문제가 아니었지만, 카테고리가 늘어나면서 반복 작업이 많아졌다.

  • 파일 경로와 블로그 카테고리가 따로 관리되었다.
  • Obsidian의 [[위키링크]]가 공개 블로그에서 의미 없는 텍스트가 되었다.
  • > [!note] 같은 콜아웃을 Docusaurus admonition으로 매번 고쳐야 했다.
  • 작성 중인 글을 배포 전에 제외하는 기준이 흔들렸다.
  • 검색 페이지를 위해 공개 글 목록을 다시 가공해야 했다.

반복되는 작업을 사람이 기억하는 방식으로 해결하면 언젠가 실수한다. 그래서 글 작성 규칙을 코드로 옮겼다.

왜 Docusaurus를 선택했는가

Docusaurus는 기술 문서에 필요한 기능을 기본값에 가깝게 제공한다. Markdown/MDX 기반 작성 흐름, 사이드바와 라우팅, RSS/Atom, sitemap, prism 코드 하이라이트, 플러그인 생태계가 개인 기술블로그에 잘 맞았다.

특히 Mermaid와 KaTeX를 함께 사용할 수 있어 아키텍처 다이어그램과 수식을 글 안에서 자연스럽게 다룰 수 있다. 정적 사이트로 배포되므로 GitHub Pages와도 잘 맞는다.

sync-posts가 해결하는 문제

scripts/sync-posts.mjs는 Obsidian에서 작성한 Markdown을 Docusaurus 블로그 글로 정규화한다.

  1. 누락된 frontmatter를 보정한다.
  2. 파일 경로에서 category와 tag를 파생한다.
  3. slug가 없으면 경로 기반 slug를 생성한다.
  4. Obsidian callout을 Docusaurus admonition으로 변환한다.
  5. wiki link를 실제 블로그 링크로 변환한다.
  6. draft: true 글은 검색 인덱스에서 제외한다.
  7. 공개 글을 모아 static/posts.json을 생성한다.

이 방식 덕분에 작성자는 문서 내용에 집중하고, 배포 전 형식 정리는 스크립트가 담당한다.

운영 방식

파일 경로는 정보 구조의 기준이다. 예를 들어 posts/platform/obsidian-blog-pipeline.mdplatform 카테고리와 태그를 자동으로 얻는다. 글이 많아져도 폴더 구조만 보면 어떤 주제를 다루는지 알 수 있다.

slug는 직접 지정할 수 있지만, 지정하지 않아도 경로 기반으로 생성된다. 공개 URL을 직접 제어해야 하는 글만 slug를 명시하고, 일반 글은 파일 경로를 따른다.

draft는 공개 여부를 나누는 운영 스위치다. draft: true인 글은 Docusaurus 빌드 대상에는 남아 있을 수 있지만, 블로그 검색 인덱스와 공개 목록에서 제외하는 기준으로 사용한다.

앞으로의 개선 방향

다음 단계는 파이프라인을 더 신뢰할 수 있게 만드는 것이다. slug 충돌을 더 강하게 감지하고, 깨진 wiki link를 리포트로 남기며, 글 품질 체크를 CI에 붙일 수 있다. 최종 목표는 글을 작성하는 순간부터 배포 가능한 기술 문서가 되는 흐름이다.