【JavaScript】marked.jsでマークダウン記法をHTML上でプレビューしてみる
- 作成日時:
- 最終更新日時:
- Categories: フロントサイド
- Tags: JavaScript JavaScriptライブラリ マークダウン 追記予定
以前、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』で検索してみると、サニタイズせずにマークダウンを解釈している例もあるようだ。
- https://qiita.com/samuraibrass/items/d40d54aa0754692d5439
- https://mebee.info/2020/07/21/post-14683/
- https://kannokanno.hatenablog.com/entry/2013/06/19/132042
そこで、サニタイズせずに解釈することにした。それから改行一つで改行するようにオプションを書いてみた。
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などのサイトではプレビューを表示しているわけで、解決策はおそらくあると思われる。
解決策が見つかり次第、追記する予定。