tech-book-labs
データユーティリティ · 最終検証 2026-05-10 · marked 17.0.3 · 初公開 2026-05-09

marked v17 で Markdown を HTML に変換する

marked v17 系で Markdown → HTML を最小コードでパースする方法、GFM 拡張、サニタイズの注意点を触れる demo で確認する実装メモ。

marked markdown javascript

検証日: 2026-05-09

使用バージョン: marked@17.0.3

対象: ブラウザ / Node で MD → HTML 変換が必要な場面、軽量 Markdown プレビューを実装したい人

marked v17 で Markdown → HTML 変換 を最小コードで動かすパターン。GFM 拡張、サニタイゼーション(DOMPurify 併用)、カスタムレンダラ、同期 vs 非同期、を動く demo で確認します。

触って試す

最小サンプル(marked v17、3 行で動かす)

marked.parse(src) で Markdown 文字列を HTML 文字列に変換するだけ。ブラウザでも Node でも同じ API:

import { marked } from "marked";

const html = marked.parse("# Hello\n\n**bold** _italic_");
// "<h1>Hello</h1>\n<p><strong>bold</strong> <em>italic</em></p>"

ブラウザでも Node でも同じ API。

marked 内部のパイプライン

marked.parse() の中身は 3 段のパイプ。各段で hook できるので、カスタマイズしたい時にどこに割り込むかが見えやすい。

marked の Lexer → Parser → Renderer 3 段パイプラインと拡張ポイント (クリックで拡大)

実用例:

  • link を全部 target="_blank" rel="noopener" にしたい → renderer 上書き(後述)
  • :::note のようなカスタム記法を追加 → lexer 拡張で新トークンを定義
  • AST だけ欲しい(HTML 不要)marked.lexer(src) で tokens を直接取得

GFM 拡張(GitHub Flavored Markdown)

オプションで GFM テーブル / ストライクスルー / タスクリスト / autolink を有効化:

const html = marked.parse(src, { gfm: true, breaks: true });
オプション効果
gfm: trueTable、strike-[x] チェックリスト、autolink を有効化
breaks: true単純改行を <br> に変換(GitHub の挙動)
pedantic: falsetrue にすると Markdown.pl 厳密、false の方が一般的

サニタイゼーション(必須)

marked.parse()HTML をそのまま透過する(<script> も含む)。ユーザー入力をパースする時は サニタイズ必須

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

const html = DOMPurify.sanitize(marked.parse(userInput) as string);
container.innerHTML = html;

カスタムレンダラ

marked.Renderer を継承して特定要素の出力 HTML を上書き。link に rel="noopener" を強制する例:

const renderer = new marked.Renderer();
renderer.link = ({ href, text }) => `<a href="${href}" rel="noopener noreferrer" target="_blank">${text} ↗</a>`;

marked.use({ renderer });

特定の要素だけ書き換えたい時に使う。リンクに rel="noopener" を強制する、画像に loading="lazy" を付けるなど。

同期 vs 非同期

デフォルトは同期で文字列を返す。async プラグイン(remote fetch する transformer 等)を使う場合だけ async: true で Promise になる:

// 同期(デフォルト、文字列を返す)
const html = marked.parse(src) as string;

// 非同期(Promise を返す、async プラグインを使う時)
const html = await marked.parse(src, { async: true });

カスタム async プラグインを使わない通常用途は同期で OK。

つまずいたポイント

  • HTML エスケープしない仕様 — XSS 対策は呼び出し側の責任
  • async: true の戻り値は Promise<string> — 同期と混ぜると型エラー
  • GFM table の | 区切りはセル間にスペース必須(|a|b| ではなく | a | b |)
  • 改行モード:breaks: true にすると一般的な MD と挙動が変わる(段落内改行が <br> になる)
  • コードブロックハイライトは別途:Shiki / Prism / highlight.js を marked.use({ extensions }) で繋げる

評価

観点評価コメント
学習コストAPI は parse(text, options) 中心
速度ベンチで markdown-it と僅差、十分速い
サニタイズ自前で DOMPurify 等を噛ませる
拡張renderer / extensions / hooks で柔軟
バンドルサイズ30KB 前後(min+gzip)

向く / 向かないケース

  • 向く: ブラウザ内 MD プレビュー、Node での HTML 生成、軽量 docs viewer
  • 向かない: HTML / MDX の expression が必要(MDX 自体を使う)、AST 操作が中心(remark / unified を直接使う)
  • 向かない: 高度なサニタイズ要件 → markdown-it + DOMPurify か rehype-sanitize 系

関連 Topic / 関連書籍

この記事と関係する tech-book.net の Topic と、それぞれの Topic に紐づく書籍:

tech-book.net /books/9784297144944

JavaScriptによるはじめてのアルゴリズム入門

河西 朝雄
詳細を tech-book.net で見る
tech-book.net /books/9784873118086

Python と JavaScriptではじめるデータビジュアライゼーション

Kyran Dale/嶋田 健志/木下 哲也
詳細を tech-book.net で見る
tech-book.net /books/9784839966645

React Native+Expoではじめるスマホアプリ開発 : JavaScriptによるアプリ構築の実際

松澤 太郎 · マイナビ出版 · 2018年

「React Native」は、Facebookが開発しているスマートフォンアプリ向けの開発環境です。ほとんどのコードをJav…

詳細を tech-book.net で見る
tech-book.net /books/9784627857216

はじめてのWebデザイン&amp;プログラミング : HTML、CSS、JavaScript、PHPの基本

村上 祐治
詳細を tech-book.net で見る
tech-book.net /books/9784297138714

フロントエンドの知識地図ーー 一冊でHTML/CSS/JavaScriptの開発技術が学べる本

株式会社ICS 池田 泰延/西原 翼/松本 ゆき
詳細を tech-book.net で見る