MarkdownプレビューをJavaScriptで作った話|`#`と`**`がHTMLになる仕組み

MarkdownプレビューをJavaScriptで作った話|`#`と`**`がHTMLになる仕組み

GitHubのREADME.mdを書いたことはありますか? # で見出しを作り、**太字** と書くと太字になる——あの記法が Markdown(マークダウン) です。

ZennやQiita、Notion、Obsidianなど、エンジニアが使うツールのほとんどがMarkdownをサポートしています。この記事では、Lapis Tech Toolsの Markdownプレビュー を題材に、Markdownの仕組みとブラウザでのリアルタイムプレビューの実装を解説します。


1. Markdownとは何か

Markdown は、2004年にJohn GruberとAaron Swartzが考案した軽量マークアップ言語です。

マークアップ言語とは? HTMLのように「このテキストは見出しだ」「この部分は太字だ」という意味(マーク)をテキストに付加する言語のことです。HTMLは <h1>タイトル</h1> と書きますが、Markdownは # タイトル と書くだけです。

「プレーンテキストで書いていても読みやすく、かつHTMLに変換できる」というコンセプトで設計されています。

# これはH1見出し
## これはH2見出し

**太字テキスト***斜体テキスト*

- リスト項目1
- リスト項目2

[リンクテキスト](https://example.com)

これが自動的に以下のHTMLに変換されます:

<h1>これはH1見出し</h1>
<h2>これはH2見出し</h2>
<p><strong>太字テキスト</strong> と <em>斜体テキスト</em></p>
<ul>
  <li>リスト項目1</li>
  <li>リスト項目2</li>
</ul>
<a href="https://example.com">リンクテキスト</a>

2. Markdownの主要な記法

見出し(Heading)

# H1 見出し(ページタイトル)
## H2 見出し(章)
### H3 見出し(節)

# の数がHTMLの h1h6 に対応します。

テキスト装飾

**太字(Bold)**
*斜体(Italic)*
~~取り消し線(Strikethrough)~~
`インラインコード`

リスト

- 箇条書きリスト(- または * または +)
- 項目2
  - インデントでネスト

1. 番号付きリスト
2. 項目2
3. 項目3

コードブロック

```javascript
const greeting = 'Hello, World!';
console.log(greeting);
```

バッククォート3つで囲むとコードブロックになります。言語名を指定するとシンタックスハイライトが適用されます。

テーブル

| 列1 | 列2 | 列3 |
|-----|-----|-----|
| A   | B   | C   |
| D   | E   | F   |

引用(Blockquote)

> これは引用文です。
> メール形式の `>` を使います。

水平線

---

3. MarkdownをHTMLに変換する仕組み

Markdownのテキストを渡すと自動的にHTMLを返してくれるMarkdownパーサーというプログラムで変換します。

変換の大まかな流れ

Markdownテキスト
     ↓ トークナイズ(記号を認識して分割)
トークン列 [HEADING, TEXT, BOLD, ...]
     ↓ パース(構造を解析してASTを構築)
AST(抽象構文木)
     ↓ レンダリング(HTMLに変換)
HTMLテキスト

AST(抽象構文木)とは? テキストの構造をツリー状のオブジェクトで表現したものです。# タイトル{type: 'heading', depth: 1, text: 'タイトル'} というオブジェクトになります。コンパイラやパーサーが内部で使う中間表現です。

JavaScriptのMarkdownライブラリ

自前でパーサーを実装するのは複雑なため、実務ではライブラリを使います。

ライブラリ特徴用途
marked.js高速・軽量・シンプルブラウザでのリアルタイムプレビュー
remarkプラグイン豊富・AST操作可能Next.js・静的サイト生成
markdown-itCommonMark準拠・高拡張性バックエンド変換

4. marked.jsを使ったリアルタイムプレビューの実装

基本的な変換

import { marked } from 'marked';

const markdownText = `# Hello
**World**`;

const html = marked.parse(markdownText);
console.log(html);
// → <h1>Hello</h1>\n<p><strong>World</strong></p>

リアルタイムプレビューのコア

const editor = document.getElementById('md-input');
const preview = document.getElementById('md-preview');

// テキスト入力のたびにプレビューを更新
editor.addEventListener('input', () => {
  const rawHtml = marked.parse(editor.value);
  preview.innerHTML = rawHtml;
});

たったこれだけでリアルタイムプレビューが動きます。ポイントは input イベントです。change ではフォーカスが外れたときにしか発火しませんが、input は文字を入力するたびに発火します。


5. XSS対策:innerHTML の危険性

Markdownテキストには任意のHTMLを埋め込めます。そのまま innerHTML に設定するとXSS(クロスサイトスクリプティング)攻撃に脆弱になります。

<script>alert('攻撃!')</script>

このMarkdownをそのまま変換して innerHTML に設定すると、JavaScriptが実行されてしまいます。

対策1:marked.jsのオプション

marked.setOptions({
  // HTMLタグをエスケープして無効化
  sanitize: true,  // 古いAPI(非推奨)
});

対策2:DOMPurify(推奨)

import DOMPurify from 'dompurify';
import { marked } from 'marked';

function renderMarkdown(text) {
  const rawHtml = marked.parse(text);
  // DOMPurifyで危険なHTMLを除去
  const cleanHtml = DOMPurify.sanitize(rawHtml);
  preview.innerHTML = cleanHtml;
}

DOMPurify はXSS対策に特化したライブラリで、危険なタグ・属性を自動的に除去します。<script> タグや onerror 属性などを検知・削除するため、Markdownプレビューには必須です。


6. コードハイライトの追加

コードブロックにシンタックスハイライトを付けると、読みやすさが大幅に向上します。

import { marked } from 'marked';
import hljs from 'highlight.js';

// markedにhighlight.jsを組み込む
marked.setOptions({
  highlight: (code, lang) => {
    if (lang && hljs.getLanguage(lang)) {
      return hljs.highlight(code, { language: lang }).value;
    }
    return hljs.highlightAuto(code).value;
  },
});

これで ```javascript と指定したコードブロックが自動的に色付きで表示されます。


7. Markdownが使われている場所

サービス用途
GitHub READMEリポジトリの説明文
Zenn / Qiita技術記事執筆
Notionドキュメント・Wiki
Slackメッセージの書式
VS Codeドキュメントプレビュー
Discordメッセージの書式
GitHub Issues / PR課題・プルリクエストの説明

エンジニアとしてMarkdownを素早く書けることは、日々の業務効率に直結します。Markdownプレビューで練習するのがおすすめです。


8. まとめ

学んだこと内容
Markdown記法# 見出し・**太字**- リスト・```コードブロック
変換の仕組みテキスト→トークン→AST→HTMLのパース処理
marked.js高速・軽量なブラウザ向けMarkdownパーサー
リアルタイムプレビューinput イベント + innerHTML で実現
XSS対策DOMPurifyで innerHTML への出力を無害化
シンタックスハイライトhighlight.jsをmarkedに組み込む

GitHubのREADMEを書くだけでなく、日々のドキュメント作成にMarkdownを活用してください。Markdownプレビューはサーバーへのデータ送信なし・登録不要でブラウザ上だけで動きます。

→ Markdownプレビューを使ってみる


ツール解説シリーズ:第1回・IP計算機 | 第2回・Base64エンコーダー | 第3回・chmod計算機 | 第4回・JSONフォーマッター | 第5回・Cronジェネレーター | 第6回・正規表現テスター | 第7回・UUIDジェネレーター | 今ここ(第8回・Markdownプレビュー)

この記事をシェアする

関連記事


CHECK IT OUT

Members Only

サブスク加入者限定の コンテンツを配信中

  • 毎月のAI・自動化トレンドレポート
  • クリエイター向け業務効率化テンプレート
  • ツール選定・SaaS比較まとめ(限定公開)
Discord サーバー & LINE 公式の両方で通知します
クリエイター・個人事業主向け 受付中

「これ自動化できないかな?」 そのアイデア、ITで実現できます。

業務の自動化・お客様向けツール開発・AI活用まで、クリエイター・個人事業主専門のITコンサルタントが対応します。まずは気軽にご相談ください。

LINEで相談 フォームで相談