MerkedとMermaidを連携ができずうがーってなって微調整した

MerkedとMermaidを連携させたのにうまく行かなくなった!

自分のツールとして作っているコードの中で、MarkedとMermaidの連携について、mermaid.jsの見本であるmermaidjs.github.io - UsageのExample of a marked rendererをそのまま使っていた。
しかし、最近なぜかうまく表示されなくなった。原因は、この記事執筆時点でも未だにわからず。

コードの紹介

Usageにかかれていたコードは以下のとおり。
要するに、markdownの ``` に当たる部分でmermaidの構文を書いた場合に、mermaidが適用できる(<div class="mermaid">に記述した構文をmermaidがsvg画像化してくれる)ようにmarkedがDIVタグを加えるようHTML変換する仕組みを取るという、ごく単純な方法だ。
var renderer = new marked.Renderer();
renderer.code = function (code, language) {
    // mermaidはcode部分の冒頭がこの2つの文言になるので、それで判断している
    if(code.match(/^sequenceDiagram/)||code.match(/^graph/)){
        // divタグを加えて上げると、mermaidが認識してくれるのだ!
        return '<div class="mermaid">'+code+'</div>';
    }
    else{
        return '<pre><code>'+code+'</code></pre>';
    }
};
HTMLツール全体としては、以下のソースにしていた。これに、mermaidの構文を含むmdファイルを読み込ませることで、mermaidを図化する方式をとっていた。
<!DOCTYPE html>
<html lang="jp">
  <head>
    <meta charset="utf-8">
    <title>MARKUP</title>
    <link rel="stylesheet" href="./styles/default.css" />
    <script src="./lib/jquery-3.3.1.js"></script>
    <script src="./lib/marked.min.js"></script>
    <script src="./lib/mermaid.min.js"></script>
    <script src="./lib/highlight.pack.js"></script>
  </head>
  <body>
    <div id="content"></div>
    <script>
      var renderer = new marked.Renderer();
      renderer.code = function (code, language) {
        if(code.match(/^sequenceDiagram/)||code.match(/^graph/)||code.match(/^gantt/)){
           return '<div class="mermaid">'+code+'</div>';
        }else{
           return '<pre><code>' + hljs.highlightAuto(code).value + '</code></pre>';
        }
      };
      $(document).ready(function(){
        if (location.href.split("#").length > 1){
          var urlParam = location.href.split("#")[1];
          $.get( urlParam, function( data ) {
          // console.log(data);
          $('#content').html(marked(data, { renderer: renderer })); });
        }else{
          $('#content').html('please url#any.md');
        }
      });

      </script>
  </body>
</html>
これでうまく動いていた、少し前までは。
それが、最近いつの間にか動かなくなり、marmaid構文のまま表示されるようになってしまった。 パソコンを変えたタイミングだったので、内部的に何かしらの設定が変わってしまったのかもしれないが…根本的な原因はわからない。
さて、それで3,4時間頭を悩ませ続けて、ようやく対処法に気づいた。
merked がレンダリングする前に、mermaidが動いてしまっているのだろう
mermaidは <div class="mermaid"></div>の中に、コードがなければならないことは、先に書いたとおりだ。
つまり、下の理想の図になるはずだ。

実際には、mermaidがclass="mermaid"がないmarkdownソースのままにレンダリングしてしまって、それからmarkedがmarkdownをHTMLにレンダリングするということが起こったのだと推測した。
つまり、下の実際の図のとおりに処理が動いた。

昔は、パソコンのスペックが少し悪かったから、markedとmermaidの処理の順番が逆になって、理想どおりに動いていた…? 考えにくいがそうかもしれない。

対処方法を調べよう

ということで、google先生に聞いたところ、素晴らしい講師を紹介していただいた。 mermaidを非同期で読み込む - なおしむ論
記事を読めば一目瞭然だが、要するに、読み込んだタイミングでmermaidが動くなら、最初から動かさなければいいじゃないという論理。
至極、当然の話であった。
さて、この方が書いた内容は自分のコードでも適用できるので、真似させてもらった。

コード修正

ということで、<HEAD&mt;に、mermaidがHTMLをロード時に勝手に動かないようにするコードを入れる。
// デフォルトのtrueだと、HTMLのロード時にレンダリングしてしまうので、falseで停止してあげる
mermaid.initialize({startOnLoad:false})
そして、mermaidを動かしたいタイミング、具体的にはmarkedのレンダリングが終わった直後に以下のコードを入れる。
// このコードで自主的にレンダリングしてくれる。
mermaid.init()
あっさりと成功した。
元記事の方もおっしゃっているが、驚くほど簡単だった。3,4時間何に悩んでいたんだろう…。
最終的なコードは以下のようになった。 なお、MDファイルの読み込み方は、URLに「mermaid.html#hoge.md」のようにして#で変換したいmdファイルを付けるMDwiki - Markdown based wiki done 100% on the client via javascriptリスペクトの方式である。

<!DOCTYPE html>
<html lang="jp">
  <head>
    <meta charset="utf-8">
    <title>MARKUP</title>
    <link rel="stylesheet" href="./styles/default.css" />
    <script src="./lib/jquery-3.3.1.js"></script>
    <script src="./lib/marked.min.js"></script>
    <script src="./lib/mermaid.min.js"></script>
    <script src="./lib/highlight.pack.js"></script>
    <!--
    MEMO: レンダリングを読み込み時にしない
    任意のタイミングで行うために、するのだ。
    ref: https://naosim.hatenablog.jp/entry/2018/02/20/071042
    -->
    <script>mermaid.initialize({startOnLoad:false});</script>
  </head>
  <body id="content">
    <script>
      var renderer = new marked.Renderer();
      renderer.code = function (code, language, escaped) {
        if(code.match(/^sequenceDiagram/)||code.match(/^graph/)||code.match(/^gantt/)){
           return '<div class="mermaid">' + code + '\n</div>';
        }else{
           return '<pre><code>\n' + hljs.highlightAuto(code).value + '\n</code></pre>';
        }
      };
      $(document).ready(function(){
        if (location.href.split("#").length > 1){
          var urlParam = location.href.split("#")[1];
          $.get( urlParam, function( data ) {
            // Memo: markedのレンダリング-> marmaid.init()
            // ただし、あらかじめstartOnLoad:falseにしておかないと、
            // markedの前にmermaidが走ってしまって、mermaidで変換されない。
            $('#content').html(marked(data, { renderer: renderer }));
            mermaid.init();
          });
        }else{
          $('#content').html('please url#any.md');
        }
      });
      </script>

  </body>
</html>

コメント

このブログの人気の投稿

リモートワークをLogicoolのマウスとキーボードで複数PC切り替えて優勝した

VBAでのInterfaceやキャスト

SUPERHOTがいかにSUPERHOTか語りたい