#01　marked.js + highlight.js でMarkdownをきれいにHTMLに変換

## 概要

Markdownで書いたページをHTMLに変換する際に、
marked.js と highlight.js のライブラリの組み合わせが使いやすかったのでご紹介です。

* marked.js (Markdown→HTML変換用)
* highlight.js (コードを書いてる部分をきれいにする用)

## 準備

### marked.js

Documentation: https://marked.js.org/
Github: https://github.com/markedjs/marked

NPMで適用することもできますが、今回はgithubから直接ダウンロードしました。

1. [marked.min.js](https://github.com/markedjs/marked/blob/master/marked.min.js)をダウンロード
1. /assets/js ディレクトリに配置
1. HTMLファイルに以下を追記
```javascript
<script src="/assets/js/marked.min.js"></script>
```

### highlight.js

配布ページ: https://highlightjs.org/
GitHub: https://github.com/highlightjs/highlight.js

こちらは、NPMで適用するか、ファイルをダウンロードするか、CDNで適用するかですが、
今回は表示したい言語が決まっていなかったのでCDNで適用しました。

どの言語のコードを表示したいかあらかじめ決まっていた場合は、
その言語用のファイルだけダウンロードしたほうが軽量化になると思います。

1．HTMLファイルに以下を追記
```javascript
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>
```
2．[デモページ](https://highlightjs.org/demo)で、表示テーマを選択
3．HTMLファイルに以下を追記
```javascript
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/{テーマ名}.min.css">
```
今回は、Monokai Sublime を選択したのでテーマ名部分は`monokai-sublime`となります。

## 実装

ライブラリを適用したので、コードに組み込んでいきます。

```javascript
var markdown_text = '~~~';
// Markdown→HTMLに変換
var html = marked.parse(markdown);
// HTML要素にセット
document.getElementById('markdown').innerHTML = html;
// コードハイライト
hljs.highlightAll();
```

あとは、出力されたHTMLを見て、好みに合わせてCSSスタイルを調整すれば完成です。

## カスタマイズ

ここから先は必須ではありません。

### コード部分にファイル名を表示する

コードを記載しているところに、ファイル名も一緒に表示したかったのですが、
marked.jsのデフォルトの設定だと表示してくれないようです。

↓これが問題のMarkdownです。
~~~変換前
1. 言語名だけ
```javascript
console.log('Hello World');
```

2. 言語名+ファイル名
```javascript:hogehoge.js
console.log('Hello World');
```

3. ファイル名だけ
```hogehoge.js
console.log('Hello World');
```
~~~

↓上のMarkdownをHTMLに変換するとこうなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3843084/3ca483f9-ced5-831e-2c74-c1b1f46a6478.png)


1はファイル名を指定していないので期待通りの動作です。
2はファイル名が表示されない。。。
3はそもそもハイライトされない。。。

そこで、以下のように修正します。
```javascript
<script>
var highlight = function(code, lang, callback){
    if (lang) {
        return hljs.highlight(code, {language: lang, ignoreIllegals: true}).value;
    } else {
        return hljs.highlightAuto(code).value;
    }
}

var renderer = new marked.Renderer();
renderer.code = function(code, fileInfo, escaped) {
  if (!fileInfo) {
    fileInfo = '';
  }
  var info = fileInfo.split(':');
  langs = hljs.listLanguages();
  // hljsの対応言語に含まれていなければファイル名とする
  if (!langs.includes(info[0])) {
    var fileName = info[0];
  } else {
    var lang = info[0];
    var fileName = info[1];
  }
  var fileTag = '';
  if (fileName) {
    fileTag = '<span class="filename">'+fileName+'</span>'
  }

  if (this.options.highlight) {
    var out = this.options.highlight(code, lang);
    if (out != null && out !== code) {
      escaped = true;
      code = out;
    }
  }

  if (!lang) {
    return '<pre>'+fileTag+'<code>'
      + (escaped === false ? escape(code, true) : code)
      + '\n</code></pre>';
  }

  return '<pre>'+fileTag+'<code class="'
    + this.options.langPrefix
    + escape(lang, true)
    + '">'
    + (escaped === false ? escape(code, true) : code)
    + '\n</code></pre>\n';
};

marked.setOptions({
    renderer: renderer,
    highlight: highlight
});
</script>
```

コード部分のHTML→Markdown処理を上書きし、
ファイル名が`<span class="filename">ファイル名</span>`で表示されるようにしました。

↓改めて、HTMLに変換してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3843084/e3ae4382-b23c-5247-b501-246b54213fc4.png)

無事にファイル名が表示されるようになりました。
あとは、表示が不格好なので、CSSで整えれば完了です。
```javascript
<style>
pre span.filename {
    color: #000;
    background-color: #eeede7;
    padding: 2px 8px;
    display: block;
    overflow: hidden;
}
</style>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3843084/b8f600d3-641b-7dbc-3561-4d1c6bec1af8.png)

いい感じの表示になりました。
<br>
コード以外も、rendererに設定すればHTML変換処理をカスタマイズ可能です。
詳細はmarked.jsの[Documentation](https://marked.js.org/using_pro#renderer)を参照してください。
<br>
以上です。ご清覧ありがとうございます。

### 参考

* [markedでqiitaライクにファイル名を表示する](https://qiita.com/59naga/items/7d46155715416561aa60)