🥱

なるべくコードを書かずに「.md」ファイルを HTML に変換 / Marked.js + Prism.js + Mermaid.js

に公開

はじめに

CDN で公開されているものを組み合わせて、マークダウン記法で書けるサイトができたらと考えた。今回は JavaScript から MD ファイルを読み込んで DOM を生成する。

使用したライブラリ

各ファイルの中身

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta http-equiv="content-security-policy" content="script-src 'self' *.cloudflare.com *.jsdelivr.net">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.8.1/github-markdown.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/themes/prism-okaidia.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/plugins/line-numbers/prism-line-numbers.min.css">
    <link rel="stylesheet" href="main.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/16.2.0/lib/marked.umd.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/prism.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/components/prism-typescript.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@mermaid-js/tiny@11.10.0/dist/mermaid.tiny.min.js"></script>
</head>
<body class="markdown-body">
    <div>
        <header>
            <h1>header</h1>
        </header>
        <main id="main"></main>
        <footer>
            <hr>
            <p>footer</p>
        </footer>
    </div>
    <script src="main.js"></script>
</body>
</html>
main.css
.markdown-body {
    font-family: 'Noto Sans JP', 'Hiragino Sans', sans-serif;
}

.markdown-body > div {
    max-width: 1000px;
    width: 100%;
    margin: 0 auto;
    padding: 0 16px;
    box-sizing: border-box;
}
main.js
/**
 * MAIN
 * @returns {Promise<void>}
 */
async function main() {

    const mainContents = document.getElementById('main');
    const df = await makeDocumentFragment();
    mainContents.appendChild(df);

    Prism.highlightAll();
    mermaid.initialize({ securityLevel: 'loose', theme: 'neutral' });
    mermaid.init(undefined, document.getElementsByClassName('language-mermaid'));

}
main().catch(console.error);

/* ################################################################ */

/**
 * メインコンテンツの DocumentFragment を生成
 * @returns {Promise<DocumentFragment>}
 */
async function makeDocumentFragment() {

    const df = document.createDocumentFragment();
    const text = await importTextFile('main.md');
    const doc = document.createElement('div');

    marked.use({ renderer: { code: appendClass } });
    marked.setOptions({ breaks: true });
    doc.innerHTML = marked.parse(text);

    df.appendChild(doc);
    return df;

}

/**
 * テキストファイルをインポート
 * @param filename ファイル名
 * @returns {Promise<string>} テキスト
 */
async function importTextFile(filename) {

    const file = await fetch(filename);
    return await file.text();

}

/**
 * コードエリアへ Class を追加
 * @param code コードの種類
 * @returns {string} 変換後の HTML
 */
function appendClass(code) {

    if (code.lang === 'mermaid' || code.lang === 'Mermaid') {
        return '<pre class="language-mermaid">' + code.text + '</pre>';
    } else {
        return '<pre><code class="language-' + code.lang + ' line-numbers">' + code.text + '</code></pre>';
    }

}

結果

若干、色がちぐはぐですが、よいのではないでしょうか。

ダークモード

ダークモード

ライトモード

ライトモード

おわりに

Marked.js + Prism.js + Mermaid.js のサンプルが見つからなかったので書いた。これをベースに日記を作りたい (願望)。

参考リンク

Discussion