Rehype プラグインで HTML の見出し要素にリンクを貼る
GitHub で表示される Markdown や Bootstrap のドキュメントなんかで、見出しにカーソルを当てると左右に $
とか #
みたいなアイコンが表示されて、コレが該当の見出しへのパーマリンクになっているモノがある。
自分で HTML を書くと、以下のように実装する感じだ。
<h1 id="my-headline">
<a href="#my-headline">$</a>
こんにちは見出しです
</h1>
今回は <a href="#my-headline">$</a>
この部分を自動的に付与してくれる Rehype プラグイン rehype-autolink-headings を紹介する。
必要なパッケージとサンプルコード
今回は Markdown から HTML にパースする際に、見出しにリンクを付けてみる。Rehype プラグインなので、HTML を読み込んで、見出しにリンクを付けて、再度 HTML にパースし直す、といった使い方もできる。
# Markdown を HTML へと変換するために必要な最低限の Unified・Remark・Rehype 関連パッケージ
$ npm install --save-dev unified remark-parse remark-rehype rehype-stringify
# 見出しへの ID 付与を行う Remark プラグインと、見出しリンクを付与する今回のプラグイン
$ npm install --save-dev remark-slug rehype-autolink-headings
以下のようにパースする。
const fs = require('fs').promises;
const unified = require('unified');
const remarkParse = require('remark-parse');
const remarkSlug = require('remark-slug');
const remarkRehype = require('remark-rehype');
const rehypeAutolinkHeadings = require('rehype-autolink-headings');
const rehypeStringify = require('rehype-stringify');
(async () => {
const inputMarkdown = await fs.readFile('./example.md', 'utf-8');
const processor = unified()
.use(remarkParse)
.use(remarkSlug) // 見出しに ID を自動付与する
.use(remarkRehype) // Markdown から HTML に変換する
.use(rehypeAutolinkHeadings, { // HTML に変換後、見出しリンクを自動付与する
behavior: 'prepend', // `prepend`・`append`・`wrap`・`before`・`after` でリンクの挿入位置を指定できる
properties: {}, // `a` 要素に付与する属性
content: { // hast Node として `a` 要素の子要素を定義できる・今回は span 要素を追加してみる
type: 'element',
tagName: 'span',
properties: {
className: ['icon-header-link']
},
children: [{
type: 'text',
value: '$'
}]
}
})
.use(rehypeStringify);
const result = await processor.process(inputMarkdown);
const outputHtml = result.contents;
await fs.writeFile('./example.html', outputHtml, 'utf-8');
})();
コレで、生成される HTML は以下のようになる。インデントだけ調整している。
<h1 id="タイトル">
<a href="#タイトル"><span class="icon-header-link">$</span></a>
タイトル
</h1>
<p>文章</p>
<h2 id="はじめに">
<a href="#はじめに"><span class="icon-header-link">$</span></a>
はじめに
</h2>
<p>文章…</p>
こんな感じ。
behavior: 'prepend'
という指定で、h1
要素などの先頭に a
要素が追加されている。挿入位置はお好みで。
content
オプションは hast (HTML AST) の仕様に則って子要素を指定できるモノ。今回は span
要素を内側に入れ、$
というテキストノードを追加している。
こうした見出しリンクの付与が自動化できるのはありがたい。