はじめに
個人的に、Markdownって本当に便利だと思うんですよ。ドキュメント書くにも、ブログ書くにも、GitHubのREADME書くにも。ただ、世の中のコンテンツって基本的にHTMLで書かれているわけで、これをMarkdownに変換したいという場面が意外と多い。
例えば、既存のWebページの内容をドキュメント化したいとか、リッチテキストエディタの出力をMarkdownとして保存したいとか。そういう時に重宝するのがTurndownというライブラリです。
GitHub Stars 10.6k、月間ダウンロード800万という数字が示す通り、HTMLからMarkdownへの変換といえばこれ、という定番のツールになっています。
特徴・メリット
Turndownの良いところを挙げると、こんな感じですね。
1. とにかく軽量
圧縮後わずか4.43KB。これ、意外と重要なポイントで、フロントエンドで使う場合でもバンドルサイズを気にしなくていい。昨今のパフォーマンス重視の流れを考えると、ありがたい話です。
2. シンプルなAPI
基本的な使い方は3行で完結します。複雑な設定なしにすぐ使える。30代になって思うのは、こういうシンプルさが一番大事だということですね。
3. 高いカスタマイズ性
デフォルトの変換ルールで満足できない場合は、自分でルールを追加できます。見出しのスタイル、リストのマーカー、コードブロックの形式など、細かく調整可能。
4. プラグイン対応
GitHub Flavored Markdown(GFM)用のプラグインが公式で用意されていて、テーブルや取り消し線なども対応できます。
5. ブラウザでもNode.jsでも動く
クライアントサイドでもサーバーサイドでも使える。環境を選ばないのは実務的にありがたい。
インストール方法
npm経由(推奨)
npm install turndown
CDN経由(ブラウザ向け)
<script src="https://unpkg.com/turndown/dist/turndown.js"></script>
正直なところ、プロジェクトで使うならnpm一択ですね。CDNはちょっとした検証やプロトタイプ向け。
基本的な使い方
最もシンプルな例
const TurndownService = require('turndown');
const turndownService = new TurndownService();
const markdown = turndownService.turndown('<h1>Hello World!</h1>');
console.log(markdown);
// 出力: # Hello World!
ES Modulesを使う場合はこう。
import TurndownService from 'turndown';
const turndownService = new TurndownService();
const markdown = turndownService.turndown('<p>これはテストです。</p>');
DOM要素を直接渡す
ブラウザ環境なら、DOM要素をそのまま渡せます。
const element = document.getElementById('content');
const markdown = turndownService.turndown(element);
これ、Webスクレイピングとかで地味に便利なんですよ。
オプションを指定する
const turndownService = new TurndownService({
headingStyle: 'atx', // # 形式の見出し
bulletListMarker: '-', // リストを - で表示
codeBlockStyle: 'fenced', // ``` でコードブロック
emDelimiter: '*', // 強調を * で
strongDelimiter: '**', // 太字を ** で
linkStyle: 'inlined' // リンクをインライン形式で
});
個人的にはheadingStyle: 'atx'とcodeBlockStyle: 'fenced'は必須設定ですね。モダンなMarkdownスタイルを使うならこの組み合わせ。
実践的なユースケース
カスタムルールを追加する
例えば、取り消し線(<del>や<s>タグ)に対応したい場合。
turndownService.addRule('strikethrough', {
filter: ['del', 's'],
replacement: function(content) {
return '~~' + content + '~~';
}
});
特定のタグをそのまま残す
HTMLタグを変換せずに残したい場合はkeepメソッドを使います。
// <iframe>と<video>はそのままHTMLとして出力
turndownService.keep(['iframe', 'video']);
不要な要素を削除する
広告やナビゲーションなど、Markdownに含めたくない要素を除外。
turndownService.remove(['nav', 'aside', 'footer']);
GFMプラグインでテーブル対応
GitHub Flavored Markdownの機能が必要な場合。
npm install turndown-plugin-gfm
const TurndownService = require('turndown');
const turndownPluginGfm = require('turndown-plugin-gfm');
const turndownService = new TurndownService();
turndownService.use(turndownPluginGfm.gfm);
const html = `
<table>
<tr><th>名前</th><th>年齢</th></tr>
<tr><td>田中</td><td>35</td></tr>
</table>
`;
console.log(turndownService.turndown(html));
// | 名前 | 年齢 |
// | --- | --- |
// | 田中 | 35 |
テーブルの変換って地味に需要があるので、これは覚えておいて損はないです。
実用例:Webページのコンテンツを抽出
// ブラウザで実行
const article = document.querySelector('article');
const turndownService = new TurndownService({
headingStyle: 'atx',
codeBlockStyle: 'fenced'
});
// 不要な要素を除外
turndownService.remove(['script', 'style', 'nav', 'aside']);
const markdown = turndownService.turndown(article);
console.log(markdown);
ドキュメント作成の時短になるので、QOL上がりますよ。
注意点
いくつか気をつけるポイントがあります。
完璧な変換は期待しない
HTMLの構造によっては、意図した通りに変換されないこともあります。特に複雑にネストしたリストや、CSSで見た目を調整しているケースは要確認。
画像のパス
相対パスの画像は、変換後も相対パスのまま。絶対パスに変換したい場合はカスタムルールで対応する必要があります。
turndownService.addRule('images', {
filter: 'img',
replacement: function(content, node) {
const alt = node.alt || '';
const src = node.src; // ブラウザ環境では絶対URLになる
return ``;
}
});
まとめ
TurndownはHTMLからMarkdownへの変換において、軽量・シンプル・拡張可能という三拍子揃ったライブラリです。
- 4KB以下の軽量さ
- 3行で使い始められるシンプルさ
- カスタムルールやプラグインによる拡張性
- ブラウザ・Node.js両対応
HTMLをMarkdownに変換したいという要件があれば、とりあえずTurndownを試してみることをおすすめします。コスパ的にも学習コスト的にも、これ一択ですね。
公式ドキュメントも充実しているので、より詳しく知りたい方はGitHubリポジトリをチェックしてみてください。
参考リンク