왜 마크다운 유틸리티가 필요한가?

프로젝트에서 마크다운을 사용하다 보면, 코드 블록이나 일반 텍스트를 작성할 때 들여쓰기를 자연스럽게 하게 됩니다. 그런데 대부분의 마크다운 라이브러리는 들여쓰기를 제대로 인식하지 못해, 의도하지 않은 <p> 태그나 <code> 블록이 생성되는 문제가 발생합니다.

예를 들어, 다음과 같이 작성한 경우를 생각해 봅시다.

This is a paragraph
    This is a second paragraph

위 코드는 4칸 이상 들여쓰기가 있기 때문에, 마크다운 파서는 두 번째 줄을 코드 블록으로 처리해 버립니다. 결과적으로 HTML은 다음과 같이 렌더링됩니다.

<p>This is a paragraph</p>
<pre><code>This is a second paragraph
</code></pre>

이 문제를 피하려면 모든 들여쓰기를 제거하고 한 줄로 작성해야 하는데, 이는 가독성을 떨어뜨리고 유지보수를 어렵게 만듭니다.

이 글에서는 이 문제를 해결하는 커스텀 마크다운 유틸리티를 소개하고, Astro와 Svelte를 포함한 다양한 프레임워크에서 활용하는 방법을 다룹니다.

참고: 이 유틸리티는 Splendid Labz에서 제작한 @splendidlabz/utils 패키지에 포함되어 있습니다. 자세한 내용은 원문 링크를 참고하세요.

마크다운 유틸리티의 핵심 기능

이 유틸리티는 들여쓰기 문제를 해결하여, 코드가 어떻게 들여쓰기 되어 있든 항상 올바른 HTML을 생성합니다.

// markdown 유틸리티 사용 예시
import { markdown } from '@splendidlabz/utils';

const content = `
  This is a paragraph
    This is a second paragraph
`;

// 들여쓰기를 유지한 채 올바른 HTML 생성
const html = markdown(content);
// 출력: <p>This is a paragraph</p><p>This is a second paragraph</p>

// inline 옵션을 true로 설정하면 <p> 태그 없이 반환
const inlineHtml = markdown(content, { inline: true });

Astro에서 활용하기

Astro 컴포넌트에서 이 유틸리티를 사용하는 방법은 간단합니다. 아래 코드를 참고하세요.

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

const { inline = false, content } = Astro.props;
const slotContent = await Astro.slots.render('default');

// content prop 또는 슬롯 콘텐츠를 처리
const html = markdown(content || slotContent, { inline });
---

<div class="markdown-body" set:html={html} />

사용 예시:

<Markdown>
  ### 제목
  여기에 마크다운 본문을 작성합니다.
</Markdown>

Svelte에서 활용하기

Svelte는 슬롯에서 동적 콘텐츠를 읽을 수 없기 때문에, prop으로 전달하는 방식을 사용합니다.

<!-- src/lib/Markdown.svelte -->
<script>
  import { markdown } from '@splendidlabz/utils';
  export let content = '';
  export let inline = false;
  $: html = markdown(content, { inline });
</script>

<div class="markdown-body">
  {@html html}
</div>

사용 예시:

<Markdown content="### Svelte에서 마크다운 사용하기\n- 항목 1\n- 항목 2" />

React와 Vue에서도 쉽게 확장 가능

React와 Vue도 동일한 원리로 적용할 수 있습니다. React에서는 dangerouslySetInnerHTML을 사용하고, Vue에서는 v-html 디렉티브를 사용하면 됩니다.

// React 예시
import { markdown } from '@splendidlabz/utils';

function Markdown({ content, inline = false }) {
  return <div dangerouslySetInnerHTML={{ __html: markdown(content, { inline }) }} />;
}
<!-- Vue 예시 -->
<template>
  <div v-html="html"></div>
</template>

<script setup>
import { markdown } from '@splendidlabz/utils';
import { computed } from 'vue';

const props = defineProps({ content: String, inline: Boolean });
const html = computed(() => markdown(props.content, { inline: props.inline }));
</script>

마크다운 유틸리티 사용 시 주의사항

이 유틸리티는 편리하지만, 몇 가지 주의할 점이 있습니다.

  • 보안: 사용자 입력을 마크다운으로 렌더링할 경우, XSS 공격에 취약할 수 있습니다. 반드시 sanitize-html 같은 라이브러리로 HTML을 정화하세요.
  • 성능: 매우 큰 마크다운 문서를 처리할 때는 성능 저하가 발생할 수 있습니다. 필요한 경우 캐싱을 고려하세요.
  • 문법 지원: 모든 마크다운 문법을 지원하지 않을 수 있습니다. 팀 내에서 사용할 문법을 미리 정의해 두는 것이 좋습니다.

다음 단계: 더 나은 개발 경험을 위한 도구

이 유틸리티 외에도 Splendid Labz는 레이아웃, Astro 컴포넌트, Svelte 컴포넌트 등 개발 경험(DX)을 향상시키는 다양한 도구를 제공합니다. 관심이 있다면 Splendid Utils를 방문해 보세요.

결론

마크다운 들여쓰기 문제는 많은 개발자들이 겪는 불편함입니다. 이 유틸리티를 사용하면 코드의 가독성을 유지하면서도 올바른 HTML을 생성할 수 있어, 개발 생산성이 크게 향상됩니다.

Astro, Svelte, React, Vue 등 어떤 프레임워크를 사용하든 쉽게 통합할 수 있으니, 한번 적용해 보시길 권장합니다.

함께 보면 좋은 글

Developer writing markdown code in a code editor for a web development project Coding Session Visual

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