自動化無しに生活無し

WEBとかAIとかLinux関係をひたすら書く備忘録系ブログ

【JavaScript】marked.jsでマークダウン記法をHTML上でプレビューしてみる

thumbnail

以前、Pythonでマークダウンを実現させてDjangoに実装したが、最近のサイトは皆、マークダウンを書いたら即時で隣のプレビュー欄に表示させる仕様になっている事が多い。

それはJavaScriptでマークダウンを作っているからで、Pythonでマークダウンを実現させているようでは難しい。

そこで、JavaScriptマークダウンのライブラリとして名高い marked.js を使うことにした。

とりあえず作ってみたソースコード

後にReactなどのフレームワークとの運用を想定して、敢えてVanillaJSで作った。

HTML

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Hello World test!!</title>

    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">

    <!--marked.js-->
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
    <!--dompurify.js -->
    <script src="https://cdn.jsdelivr.net/npm/dompurify@2.4.0/dist/purify.min.js"></script>

    <script src="script.js"></script>
</head>
<body>

    <div class="row mx-0">
        <div class="col">
            <textarea class="form-control"></textarea>
        </div>
        <div class="col border">
            <div class="markdown"></div>
        </div>
    </div>

</body>
</html>

JavaScript

window.addEventListener("load" , function (){

    const textarea  = document.querySelector("textarea");
    const markdown  = document.querySelector(".markdown");

    textarea.addEventListener("input", function(){ 
        //console.log(this.value);

        //素のHTMLを無害化
        let cleaned         = DOMPurify.sanitize(this.value);

        console.log(cleaned);

        //マークダウンを解釈して、隣のプレビュー欄にレンダリング
        markdown.innerHTML  = marked.parse(cleaned);

    });
});

動かすとこうなる

一応、入力したら即時プレビューしてくれる。

ソースコードとして表示してくれと書いたのに、それがサニタイズされて消えている。これでは使えない。

onclick属性の削除は良いが、コード欄のscriptタグまで消すのはダメだ。

【追記】サニタイズはしなくても良い?

DOMPurifyを使うことでサニタイズ(無害化)できるが、コードブロックの中まで消されてしまうのはとても実用に堪えない。

公式はDOMPurifyを推奨しているが、『marked.js』で検索してみると、サニタイズせずにマークダウンを解釈している例もあるようだ。

そこで、サニタイズせずに解釈することにした。それから改行一つで改行するようにオプションを書いてみた。

window.addEventListener("load" , function (){ 

    const textarea  = document.querySelector("textarea");
    const markdown  = document.querySelector(".markdown");

    textarea.addEventListener("input", function(){ 
        //console.log(this.value);

        //素のHTMLを無害化
        //let cleaned         = DOMPurify.sanitize(this.value);

        // 公式はDOMPurtifyを使用してサニタイズをしたほうが良いと
        // だが、DOMPurifyを使うと、かえってHTMLのコードブロックが正常に機能しなくなる。
        // 直にscriptタグを書くと無効化されるので、サニタイズしなくても良いのでは?
        let cleaned         = this.value;

        console.log(cleaned);

        //マークダウンを解釈して、隣のプレビュー欄にレンダリング

        //改行一つで改行する。
        //https://marked.js.org/using_advanced
        marked.setOptions({
            breaks: true,
        });

        markdown.innerHTML  = marked.parse(cleaned);

    }); 
});

結論

現時点ではあまり使いこなせないっぽいが、Teratailなどのサイトではプレビューを表示しているわけで、解決策はおそらくあると思われる。

解決策が見つかり次第、追記する予定。

スポンサーリンク

シェアボタン

Twitter LINEで送る Facebook はてなブログ