Markdownで書かれた内容をHTMLに変換してみます。ライブラリとして「marked.js」を利用します。シンタックスハイライト、独自クラスの追加、目次の生成などについても取り上げます。
目次
MarkdownをHTMLに変換
markedをインストール
npm install marked
ソース
const marked = require('marked')
const markdown = '# heading\n' +
'## list\n' +
'- list1\n' +
'- list2\n\n' +
'## code\n' +
'```js\n' +
'let x = 1;\n' +
'```\n' +
'## table\n' +
'| col1 | col2 |\n' +
'---|---\n' +
'abc|123\n' +
'xyz|456';
console.log(marked(markdown))
実行結果
以下のように、HTMLに変換されました。
$ node app.js
<h1 id="heading">heading</h1>
<h2 id="list">list</h2>
<ul>
<li>list1</li>
<li>list2</li>
</ul>
<h2 id="code">code</h2>
<pre><code class="language-js">let x = 1;</code></pre>
<h2 id="table">table</h2>
<table>
<thead>
<tr>
<th>col1</th>
<th>col2</th>
</tr>
</thead>
<tbody><tr>
<td>abc</td>
<td>123</td>
</tr>
<tr>
<td>xyz</td>
<td>456</td>
</tr>
</tbody></table>
オプション|setOptions
オプションで marked.js
の動作を変更できます。利用可能なオプションは以下ページで確認できます。
https://marked.js.org/#/USING_ADVANCED.md#options
シンタックスハイライト
highlight.jsをインストール
npm install highlight.js
ソース
const marked = require('marked')
const highlight = require('highlight.js')
marked.setOptions({
highlight: code => {
return highlight.highlightAuto(code).value
}
})
const markdown = '## code\n' +
'```js\n' +
'let x = 1;\n' +
'```'
console.log(marked(markdown))
実行結果
highlight.js
によって hljs-attribute
のクラスが追加されました。
$ node app.js
<h2 id="code">code</h2>
<pre><code class="language-js"><span class="hljs-attribute">let x</span> = 1;</code></pre>
対応するスタイルは、node_modules/highlight.js/stylesディレクトリ
配下に存在します。
拡張|独自クラスの追加
テーブルタグに独自のClassを追加するよう拡張してみます。
オリジナルの処理を探す
https://github.com/markedjs/marked/blob/master/lib/marked.js にて Renderer.prototype.table
で検索すると以下処理が見つかりました。
Renderer.prototype.table = function(header, body) {
if (body) body = '<tbody>' + body + '</tbody>';
return '<table>\n'
+ '<thead>\n'
+ header
+ '</thead>\n'
+ body
+ '</table>\n';
};
ソース
先ほど見つけたtableタグの処理を拡張してみます。
const marked = require('marked')
const renderer = new marked.Renderer()
renderer.table = (header, body) => {
if (body) body = '<tbody>' + body + '</tbody>'
return '<table class="wakuwaku">\n'
+ '<thead>\n'
+ header
+ '</thead>\n'
+ body
+ '</table>\n'
}
marked.setOptions({ renderer: renderer })
const markdown = '## table\n' +
'| col1 | col2 |\n' +
'---|---\n' +
'abc|123\n' +
'xyz|456'
console.log(marked(markdown))
実行結果
tableタグ
に class="wakuwaku"
が追加されました。
$ node app.js
<h2 id="table">table</h2>
<table class="wakuwaku">
<thead>
<tr>
<th>col1</th>
<th>col2</th>
</tr>
</thead>
<tbody><tr>
<td>abc</td>
<td>123</td>
</tr>
<tr>
<td>xyz</td>
<td>456</td>
</tr>
</tbody></table>
拡張|目次(toc)の生成
目次(table of contents)用のリストを生成してみます。
ソース
toc変数
に目次データを格納します。
const marked = require('marked')
const toc = []
const renderer = new marked.Renderer()
renderer.heading = (text, level) => {
const slug = encodeURI(text.toLowerCase())
toc.push({
level: level,
slug: slug,
title: text
})
return '<h'
+ level
+ ' id="'
+ slug
+ '">'
+ text
+ '</h'
+ level
+ '>\n'
}
marked.setOptions({ renderer: renderer })
const markdown =
'# 見出し1\n' +
'## 見出し1-1\n' +
'### 見出し1-1-1\n' +
'### 見出し1-1-2\n' +
'## 見出し1-2\n' +
'## 見出し1-3\n' +
'# 見出し2\n' +
'## 見出し2-1\n' +
'## 見出し2-2\n' +
'# 見出し3'
console.log(marked(markdown))
console.log(toc)
実行結果
$ node app.js
<h1 id="%E8%A6%8B%E5%87%BA%E3%81%971">見出し1</h1>
<h2 id="%E8%A6%8B%E5%87%BA%E3%81%971-1">見出し1-1</h2>
<h3 id="%E8%A6%8B%E5%87%BA%E3%81%971-1-1">見出し1-1-1</h3>
<h3 id="%E8%A6%8B%E5%87%BA%E3%81%971-1-2">見出し1-1-2</h3>
<h2 id="%E8%A6%8B%E5%87%BA%E3%81%971-2">見出し1-2</h2>
<h2 id="%E8%A6%8B%E5%87%BA%E3%81%971-3">見出し1-3</h2>
<h1 id="%E8%A6%8B%E5%87%BA%E3%81%972">見出し2</h1>
<h2 id="%E8%A6%8B%E5%87%BA%E3%81%972-1">見出し2-1</h2>
<h2 id="%E8%A6%8B%E5%87%BA%E3%81%972-2">見出し2-2</h2>
<h1 id="%E8%A6%8B%E5%87%BA%E3%81%973">見出し3</h1>
[ { level: 1, slug: '%E8%A6%8B%E5%87%BA%E3%81%971', title: '見出し1' },
{ level: 2, slug: '%E8%A6%8B%E5%87%BA%E3%81%971-1', title: '見出し1-1' },
{ level: 3, slug: '%E8%A6%8B%E5%87%BA%E3%81%971-1-1', title: '見出し1-1-1' },
{ level: 3, slug: '%E8%A6%8B%E5%87%BA%E3%81%971-1-2', title: '見出し1-1-2' },
{ level: 2, slug: '%E8%A6%8B%E5%87%BA%E3%81%971-2', title: '見出し1-2' },
{ level: 2, slug: '%E8%A6%8B%E5%87%BA%E3%81%971-3', title: '見出し1-3' },
{ level: 1, slug: '%E8%A6%8B%E5%87%BA%E3%81%972', title: '見出し2' },
{ level: 2, slug: '%E8%A6%8B%E5%87%BA%E3%81%972-1', title: '見出し2-1' },
{ level: 2, slug: '%E8%A6%8B%E5%87%BA%E3%81%972-2', title: '見出し2-2' },
{ level: 1, slug: '%E8%A6%8B%E5%87%BA%E3%81%973', title: '見出し3' } ]
参考・関連
- https://github.com/markdown-it/markdown-it
- Markdownパーサ
- https://github.com/remarkjs/remark
- Markdownパーサ を同梱
- https://github.com/highlightjs/highlight.js
- コードのハイライト
- https://github.com/PrismJS/prism
- コードのハイライト
- https://github.com/markedjs/marked
- Marked.js Documentation
markdown-it
を利用
- https://github.com/miaolz123/vue-markdown
markdown-it
を利用
- https://github.com/rexxars/react-markdown
remark
を利用