なぜマークダウンユーティリティが必要なのか?

プロジェクトでマークダウンを利用していると、コードブロックや通常のテキストを自然にインデントして書きたい場面があります。しかし、多くのマークダウンライブラリはインデントを正しく認識せず、意図しない <p> タグや <code> ブロックが生成されてしまう問題があります。

例えば、次のようなコードを考えてみましょう。

This is a paragraph
    This is a second paragraph

上記のコードは4スペース以上のインデントがあるため、マークダウンパーサーは2行目をコードブロックとして扱います。その結果、HTMLは次のようにレンダリングされます。

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

この問題を回避するには、すべてのインデントを削除して1行で書く必要がありますが、それは可読性を損ない、メンテナンスが難しくなります。

この記事では、この問題を解決するカスタムマークダウンユーティリティを紹介し、AstroやSvelteを含むさまざまなフレームワークで活用する方法を解説します。

参考: このユーティリティは、Splendid Labzが開発した @splendidlabz/utils パッケージに含まれています。詳細は元記事リンクをご覧ください。

マークダウンユーティリティの核となる機能

このユーティリティはインデント問題を解決し、コードがどのようにインデントされていても常に正しいHTMLを生成します。

// マークダウンユーティリティの使用例
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ツールを活用して作成され、編集者によるレビューを経て公開されています。専門家によるアドバイスの代替となるものではありません。