LoginSignup
4
2

More than 1 year has passed since last update.

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

Last updated at Posted at 2019-04-14

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>
4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2