GitbookユーザはRust製mdBookを使うと幸せになれる、かも


## 要約

 * [mdBook](https://github.com/azerupi/mdBook)はGitbookにインスパイアされてる[Rust](https://www.rust-lang.org/)製ドキュメントビルダー
 * Rust製なのでぶっちぎりに速い、メモリとCPUに優しい
 * 諸々足りない部分はあるが、ある程度運用でカバー出来る

## 履歴
 * 2016.06.07 mermaid.jsの読み込みと図のレンダリングについての記述を追加

## はじめに

社内のドキュメント整備を行うに当たり、まあどうせならバージョン管理しながらテストもしたいし、体系的に纏められるGitbookがいいよね、って話になりました。んで、既存のドキュメントなんかもGitbookにドンドン移行してました。

私は普段、エディターはAtomを利用し、`gitbook serve`コマンドでwatch & HotReloadをさせながら表示項目を確認しつつ、ツラツラと作成してました。

基本的には **push->CI（ビルド&テスト）->デプロイ** を繰り返す環境です。
ドキュメント作成も開発スタイルに則ろうぜ！という試み。


## Gitbookが遅い

ドキュメントの数が少ないうちは全く問題ありませんでしたが、20,30と増え続け50を超えた当たりから辛くなってきました。

特にGitbook3.0以降、極端に遅くなり、`serve`でホットリローディングを行うのに毎回10秒を超える事がザラです。atomのmarkdown previewでいいやん！って話ですが、ドキュメントの構造を確認しながら作業をしたかったため、`serve`を手放したくなかったのです。

現在100程度のmarkdownファイルが存在しますが、プラグイン類全部切っても10秒以上かかります、これは辛い。ちなみに同様の意見はissueにもかなり上がっており、参考にしながら対策を試みましたが、劇的な改善はありませんでした。

## mdBook

そんなわけで[mdBook](https://github.com/azerupi/mdBook)の登場です。
Gitbook flavorなドキュメントビルダーで[Rust](https://www.rust-lang.org/)製、この時点で惹かれます。

イニシャルコミットがちょうど去年の今頃なので、ポッと出のツールでは無さそうです。
活発というほどではないですが、継続してコミットされてます。

ドキュメントは[こちら](http://azerupi.github.io/mdBook/)。

### 利用方法

rustのパッケージマネージャ `cargo` を利用します。その他のインストール方法は[こちら](https://github.com/azerupi/mdBook#installation)。

1. [cargo](https://crates.io/install) をインストール、または`brew install rust`でもいける
2. `cargo install mdbook`でmdBookをインストール
3. パスを`~/.cargo/bin`に通す（mac osの場合）

以上で利用準備は完了。

### bookを作ってみる

```
mkdir mdBook-test
cd mdBook-test
mdbook init

// .gitignoreファイルを作るかどうか聞かれる
Do you want a .gitignore to be created? (y/n) 
y

All done, no errors...
```

上記で`mdBook-test`ディレクトリに作成されます。ストラクチャはこんな感じ。

```
.
├── book
└── src
    ├── SUMMARY.md
    └── chapter_1.md
```

`src`ディレクトリにmarkdownファイルを入れて、ビルド後のファイルは`book`に入るイメージ。ちょっとこの辺がGitbookと違います。`SUMMARY.md`の役割はGitbookと同一です。

### serveしてみる

`mdbook serve`で可能。

```
mdbook serve

[*] Creating "/dev/mdBook-test/book/chapter_1.html" ✓
[*] Creating index.html from "/dev/mdBook-test/book/./chapter_1.html" ✓
[*] Creating print.html ✓

Listening for changes...
```

この状態で、http://localhost:3000 でアクセスしてみます。

![localhost_3000_1.png](https://qiita-image-store.s3.amazonaws.com/0/19949/0b9729eb-7a84-7098-cdac-977f759b31db.png "localhost_3000_1.png")


すごくシンプルですが、Gitbookぽい画面が表示されました。

## パフォーマンスチェック

ファイル数が少ないと全く恩恵がわかりませんが、ある程度の量を使ってビルドパフォーマンスを検証してみます。

まずはGitbookから。

```
gitbook serve
Live reload server started on port: 35729
Press CTRL+C to quit ...

info: 7 plugins are installed
info: loading plugin "mermaid-2"... OK
info: loading plugin "livereload"... OK
info: loading plugin "highlight"... OK
info: loading plugin "lunr"... OK
info: loading plugin "sharing"... OK
info: loading plugin "fontsettings"... OK
info: loading plugin "theme-default"... OK
info: found 76 pages
info: found 86 asset files
info: >> generation finished with success in 12.7s !
```

この時点で **76のmarkdownファイル** と **86のassetファイル（画像など）** が存在します。ビルド時間は **12.7sec**、かかりすぎです。

続いて、全く同じ構成でmdBookを利用します。
標準ではビルド時間は測定されないため、元リポジトリをクローンし、コードをいじってます。（ちなみに初Rust）
対象は`serve`実行時のcreateならびにcopyファイルの総時間。

```
mdbook serve
Serving on localhost:3000

Listening for changes...

...

[*] Copying file: "/src/images/test.png"
    to "/book/images/test.png"


180561000 //ナノ秒出力≒180ms
```


5回の計測を行ったところ、平均250ms程度。 **約50倍の高速化となりました。**

### メモリ使用量

gitbookの場合、`serve`が実行されている最中に大きくメモリを消費します。
具体的には **400-500MB** の間、更新が走ると基本CPU使用率が **100%** 超えます。

```
PID   COMMAND      %CPU  TIME     #TH   #WQ  #PORT MEM    
6080  node         102.7 00:28.60 16/1  4    49    396M+
```

一方のmdBookは優秀です。 **約8.5MB** と考えると50分の1程度にはなっています。
CPUの使用率も同環境で瞬間的に10~15%程度でした。

```
PID   COMMAND      %CPU TIME     #TH   #WQ  #PORT MEM
6099  mdbook       0.0  00:00.52 38    1    68    8480K
```

もうちょいマシなベンチマーク方法もあるんでしょうが、それはまた後日にでも。
体感速度も全くストレス無いレベルまで改善されました。


## mdBookの難点

とはいえ、以下の問題が。

 * pdf/ebookへの出力が出来ない
 * カスタムした`website.css`が合わない
 * ディレクトリ構成がGitbookと違う
 * gitbook-pluginが使えない


pdf/ebookへの出力は、まあGitbookでやればいいや。
`website.css`も、ローカルではまあいいや・・・
ディレクトリ構成については、後述。

gitbook-pluginに関しては当たり前と言ってしまえば当たり前なんですけど。
ただ、`mermaid.js`をバリバリ使ってた身としては辛いのでここはなんとかしたい。


## mermaid.jsをなんとかする

mdBookは[テーマの拡張](http://azerupi.github.io/mdBook/format/theme/index-hbs.html)が[handlebars](http://handlebarsjs.com/)で出来るとのこと。
なので、ここからmermaid.jsを読み込む指定をします。

 * srcディレクトリに`theme`ディレクトリを作成し、`index.hbs`を作成

```
cd src && mkdir theme
touch index.hbs
```

ストラクチャはこんな感じ

```/src
.
├── README.md
├── SUMMARY.md
└── theme
    └── index.hbs
```

index.hbsはgistにあげましたので、こちらをDLしてください。

 * [index.hbs](https://gist.github.com/onori/0deb81f9f97059e6b3edd3b63cef1180)

標準のテンプレートから変更点は下記のみです。

```index.hbs
<!-- mermaid.js -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/6.0.0/mermaid.min.js"></script>
<script>
    $('pre .language-mermaid').each(function () {
        $(this).html('<div class="mermaid">' + this.textContent + '</div>');
    });
</script>
```

1. cdnからmermaid.jsを読み込み
2. jQueryでDOM書き換え

の2点だけです、jQuery久しぶり過ぎて忘れてるんですが、これで多分問題ないはず。。
これでmdBookでmermaidの図が表示されるようになりました。

なお、mermaid側にもいくつかテーマが存在し、その中でも`forest`を使っていたのですが、 **なんとmdBook側のcss** と競合し、サイドバーが悲しいことになります。
そのため`<head></head>`部分には記述してますが、現在はコメントアウトしておきました。

これ完全にmermaid側のCSSが悪いです、[issue](https://github.com/knsv/mermaid/issues/292)にも上がってるけど。。
無論css上書きでどうにかなる問題ですので、お好みでどうぞ。


## 個人的運用方法

既存のGitbookとmdBookをどう連動させるか模索してまして、個人的には下記に落ち着きました。

1. 既存のGitbook内で`src`ディレクトリ作成
2. markdownファイルとassetsファイル系を全て`src`に移動
3. Gitbookの`book.json`のrootを`src`に指定
4. .gitignoreに`/book`を追加
5. `mdbook serve`実行

あまり既存ディレクトリを弄りたくなかったんですが、book.jsonの`root`指定が簡単かつ相対パスリンクも崩れないため、これで良いやってなりました。
んで、`serve`しながら、

2. ローカルでのファイル編集とホットローディングはmdBookで
3. ある程度溜まったらpush
4. CIビルドはGitbookで行う
5. デプロイ

ようはローカル側ではmdBook、本番への適用はGitbbokを使ってビルド、ってことです。プラグインのこともありますし。
作図は[atom-mermaid](https://atom.io/packages/atom-mermaid)を使わせていただき、形が整ったらドキュメント側にコピ貼りしてます。
今のところ、上記運用で大きな問題は出てません。

## 最後に

どうでしょう？幸せになれました？まだまだ発展途上感ありますが、個人的にはそこそこ満足です。
あと、Rust面白いですね、これから継続的に触りたい。
mdBookのプラグインが増えつつ（増やしつつ）、発展を願います。