서론: 마크다운, 이제 프레임워크를 가리지 않는다

블로그를 운영하거나 기술 문서를 작성하다 보면 마크다운(Markdown)을 다양한 프레임워크에서 사용하게 됩니다. 문제는 각 프레임워크마다 마크다운을 렌더링하는 방식이 조금씩 다르고, 특히 들여쓰기(Indentation) 처리에서 골치 아픈 경우가 많죠.

대부분의 마크다운 파서는 들여쓰기를 무시하지 않고, 4칸 이상의 공백을 코드 블록으로 간주합니다. 그래서 코드 구조상 어쩔 수 없이 들여쓰기를 해야 하는 상황(예: HTML 내부에 마크다운을 넣을 때)에서는 원치 않는 <pre><code> 태그가 생성되는 문제가 발생합니다.

이 글에서는 이런 들여쓰기 문제를 해결하고, 어떤 프레임워크에서든 동일한 방식으로 마크다운을 렌더링할 수 있는 유틸리티를 소개합니다. 직접 만든 유틸리티라서 부족한 점이 있을 수 있지만, 실무에서 충분히 검증된 방법이니 편하게 따라와 보세요. 😉

Developer writing Markdown component code in Astro framework for web development Software Concept Art

본론 1: 들여쓰기 문제 해결, 그리고 유틸리티 사용법

왜 기존 마크다운 라이브러리는 불편한가?

제가 마주친 문제를 먼저 보여드릴게요. 대부분의 마크다운 라이브러리는 아래와 같은 코드를 파싱할 때 들여쓰기를 코드 블록으로 오인합니다.

<div class="container">
    <p>이것은 문단입니다.</p>
    <p>두 번째 문단입니다.</p>
</div>

위 마크다운을 파싱하면 라이브러리들은 보통 다음과 같이 처리합니다.

<div class="container">
    <pre><code>&lt;p&gt;이것은 문단입니다.&lt;/p&gt;
&lt;p&gt;두 번째 문단입니다.&lt;/p&gt;
    </code></pre>
</div>

이렇게 되면 의도치 않은 코드 블록이 생겨 레이아웃이 깨지게 됩니다. 그래서 어쩔 수 없이 들여쓰기를 모두 제거하고 마크다운을 작성해야 하는데, 이는 코드의 가독성을 크게 떨어뜨립니다.

해결책: 커스텀 마크다운 유틸리티

이 문제를 해결하기 위해 마크다운을 처리하는 유틸리티를 만들었습니다. 핵심은 들여쓰기된 공백을 무시하고 올바른 HTML 태그를 생성하는 것입니다.

// @splendidlabz/utils 패키지에서 markdown 유틸리티를 가져옵니다.
import { markdown } from '@splendidlabz/utils';

// 기본 사용법: 일반 마크다운을 HTML로 변환합니다.
const html = markdown('# 안녕하세요!');

// 옵션 사용법: inline 옵션을 true로 설정하면 <p> 태그 없이 인라인 HTML만 반환합니다.
const inlineHtml = markdown('**강조된 텍스트**', { inline: true });

console.log(html); // <h1>안녕하세요!</h1>
console.log(inlineHtml); // <strong>강조된 텍스트</strong>

이 유틸리티는 단순히 마크다운 문법을 지원하는 것을 넘어, 코드의 들여쓰기 여부와 관계없이 안정적으로 파싱해 줍니다. 이제 이 유틸리티를 각 프레임워크에서 어떻게 사용하는지 알아볼게요.

Close-up of code editor showing Markdown utility handling whitespace indentation Technical Structure Concept

본론 2: 프레임워크별 적용 방법 및 주의사항

1. Astro에서 사용하기

Astro는 .astro 파일 내에서 컴포넌트 기반으로 마크다운을 처리할 수 있습니다. 아래는 Markdown 컴포넌트를 만드는 예시입니다.

---
// Markdown.astro
import { markdown } from '@splendidlabz/utils';

// Props로 content 또는 슬롯을 전달받습니다.
const { inline = false, content } = Astro.props;
const slotContent = await Astro.slots.render('default');

// 슬롯 또는 Props로 전달된 콘텐츠를 마크다운으로 변환합니다.
const html = markdown(content || slotContent, { inline });
---

<!-- 변환된 HTML을 출력합니다. -->
<Fragment set:html={html} />

사용법은 매우 간단합니다. 컴포넌트를 불러와서 콘텐츠를 넣으면 됩니다.

---
import Markdown from '../components/Markdown.astro';
---

<Markdown>
    ### 이렇게 들여쓰기가 되어 있어도

    문제없이 파싱됩니다.
</Markdown>

2. Svelte에서 사용하기

Svelte는 동적 슬롯 콘텐츠를 읽을 수 없기 때문에, Props로 콘텐츠를 전달받는 방식이 더 적합합니다.

<!-- Markdown.svelte -->
<script>
  import { markdown } from '@splendidlabz/utils';

  // Props를 정의합니다.
  export let content = '';
  export let inline = false;

  // 마크다운을 변환합니다.
  $: html = markdown(content, { inline });
</script>

<!-- 변환된 HTML을 출력합니다. -->
{@html html}

사용 예시는 아래와 같습니다.

<script>
  import Markdown from './Markdown.svelte';

  const content = `
  ## Svelte에서도
  이렇게 사용할 수 있습니다.
  `;
</script>

<Markdown {content} />

3. React 및 Vue에서 사용하기

React와 Vue도 동일한 원리로 적용할 수 있습니다. 다만, 각 프레임워크의 문법에 맞게 컴포넌트를 구성해야 합니다. 이 부분은 여러분이 직접 구현해 보는 것을 추천합니다. 위 예시를 기반으로 충분히 확장할 수 있을 거예요.

주의사항 및 한계

이 유틸리티는 들여쓰기 문제를 해결하는 데 초점을 맞추고 있습니다. 하지만 만능은 아닙니다. 복잡한 마크다운(예: 표, 각주)을 사용할 때는 기존 파서와 동일한 한계를 가질 수 있습니다. 실제 프로덕션 환경에 도입하기 전에 충분한 테스트가 필요하다는 점, 꼭 기억해 주세요.

Developer workspace with laptop displaying Svelte and React Markdown integration code Development Concept Image

결론: 실무 적용 조언 및 다음 단계

이번에 소개한 유틸리티를 사용하면 프레임워크에 종속되지 않고, 마크다운의 들여쓰기 문제에서 자유로워질 수 있습니다. 특히 여러 프레임워크를 오가며 개발하는 분들이라면 더욱 유용하게 사용할 수 있을 거라 생각합니다.

실무 적용을 위한 팁

  • 공통 유틸리티로 관리: 이 유틸리티를 각 프로젝트에 복사해서 사용하기보다는, 별도의 패키지로 만들어 공통으로 관리하는 것을 권장합니다.
  • 테스트 강화: 마크다운 파싱은 생각보다 많은 엣지 케이스가 존재합니다. 다양한 상황을 가정한 테스트 코드를 작성해 두는 것이 좋아요.

함께 보면 좋은 글

이 글을 통해 마크다운 처리에 대한 고민이 해결되셨나요? 다음 내용도 확인해 보시면 개발 생산성 향상에 도움이 될 거예요.

이 글이 유용했다면, 다른 개발자분들과도 공유해 주시면 감사하겠습니다. 궁금한 점은 댓글로 남겨주세요. 😊

이 글은 원문을 기반으로 한국 개발자들의 실무 맥락에 맞게 재가공되었습니다.

본 콘텐츠는 신뢰할 수 있는 출처를 바탕으로 AI 도구를 활용하여 초안이 작성되었으며, 편집자의 검토를 거쳐 발행되었습니다. 전문가의 조언을 대체하지 않습니다.