最近在評估把部落格寫作工具由 Markdown Monster 遷移到 VSCode + Markdown Preview Enhanced + 自製發佈工具的組合。

研究過程認識好用 Markdown 轉網頁 JavaScript 程式庫 - markdown-it 開源 JavaScript 程式庫,用純網頁 <script> 載入 .js 就能在網頁端直接將 Markdown 語法轉成 HTML,是我偏愛的免編譯不用打包的「輕前端」風格,更讚的是它有很豐富的 Plugin 生態系,其中有個我夢寐以求的功能 - 在標題、文字片段、圖片套用 CSS 樣式,終於不必透過 HTML 也能改文字顏色跟調整圖檔尺寸了!! (灑花)

我做了一個簡單範例,展示以下九種功能:

  1. 程式碼區塊,文字高亮顯示 (搭配 prism.js)
  2. 標註 id="..." 及 class="..."
  3. 註腳 (Footnote) 功能:標註 [1] 註解,點選連到頁尾的說明
  4. Emoji 快速輸入 :smile: :cry: :rocket: :dog:
  5. 底線、螢光標記、下標字、上標字
  6. 帶勾選方格的任務清單
  7. 數學公式:行內 (Inline) 及區塊兩種模式
  8. Mermaid 流程圖
  9. 自動將標題轉成目錄 (Table of Content, TOC)

範例網頁我放上 Github 了,大家可線上看效果:

完整程式碼如下,我直接在網頁從 CDN 載入 markdown-it、用到的外掛、prism.js、Mermaid... 等程式庫,免裝前端開發套件,不需編譯打包就能寫完,用 window.markdownit() 建立轉換物件,用 use() 載入外掛,用 md.render("Markdown 語法") 即可轉成 HTML 內容,就這麼簡單!!

<!doctype html>
<html lang="zh-Hant">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Markdown Viewer</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/themes/prism-tomorrow.min.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/markdown-it.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/prism.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/plugins/autoloader/prism-autoloader.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/texmath.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/mermaid.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/markdownItAnchor.umd.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/markdown-it-attrs.browser.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/markdown-it-footnote.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/markdown-it-emoji.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/markdown-it-ins.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/markdown-it-mark.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/markdown-it-sub.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/markdown-it-sup.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/markdown-it-task-lists.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/markdownItTocDoneRight.umd.js"></script>
    <link rel="stylesheet" href="style.css" />
</head>

<body>
    <header>
        <h1>Markdown 即時轉網頁展示</h1>
        <p class="subtitle">由 <code>sample.txt</code> 載入 Markdown, 使用 markdown-it + 外掛渲染成網頁。</p>
    </header>

    <main>
        <article id="content">Loading...</article>
    </main>

    <script>
        // 設定 Prism.js 的自動依語言宣告載入指定語言語法標示
        Prism.plugins.autoloader.languages_path = 'https://cdn.jsdelivr.net/npm/[email protected]/components/';
        // 設定 Mermaid.js 的主題為暗色系
        mermaid.initialize({ startOnLoad: false, theme: 'dark' });

        const md = window.markdownit({
            html: true, // 允許 HTML 標籤
            linkify: false, // 不要將 xxx.com 之類的網址自動轉成連結
            typographer: true, // 使用 typographer 會將 "..." 轉成 …,"--" 轉成 –,"---" 轉成 —,"(c)" 轉成 ©,"(r)" 轉成 ®,"(tm)" 轉成 ™
            // Prism.js 語法標示
            highlight(code, lang) {
                if (lang === 'mermaid') return `<pre class="mermaid">${md.utils.escapeHtml(code)}</pre>`;
                const grammar = lang && Prism.languages[lang];
                return grammar ? Prism.highlight(code, grammar, lang) : md.utils.escapeHtml(code);
            }
        })
            // 使用 markdown-it 外掛
            .use(window.markdownItAnchor)
            .use(window.markdownItAttrs)
            .use(window.markdownitFootnote)
            .use(window.markdownitEmoji)
            .use(window.markdownitIns)
            .use(texmath, {
                engine: katex,
                delimiters: 'dollars',
                katexOptions: { throwOnError: false }
            })
            .use(window.markdownitMark)
            .use(window.markdownitSub)
            .use(window.markdownitSup)
            .use(window.markdownitTaskLists, { enabled: true })
            .use(window.markdownItTocDoneRight, {
                placeholder: "\\[\\[toc\\]\\]",
                level: [2, 3],
                listType: "ul",
                containerClass: "toc"
            });


        async function render() {
            const content = document.getElementById('content');
            try {
                const res = await fetch('sample.txt');
                if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
                // 使用 markdown-it 將 Markdown 轉成 HTML
                content.innerHTML = md.render(await res.text());
                // 使用 Prism.js 將程式碼區塊加上語法標示
                Prism.highlightAllUnder(content);
                // 使用 Mermaid.js 生成流程圖
                await mermaid.run({ nodes: content.querySelectorAll('.mermaid') });
            } catch (err) {
                content.innerHTML = `<p class="error">Failed to load sample.txt: ${err.message}</p>`;
            }
        }

        render();
    </script>
</body>

</html>

markdown-it for lightweight client-side Markdown-to-HTML rendering. The demo showcases plugins for syntax highlighting, CSS classes, footnotes, emoji, styling, task lists, math, Mermaid diagrams, and auto-generated tables of contents.


Comments

# by JJ

GOOD

# by 小黑

太頂了哥

# by SHIH HUNG YANG

Markdown 中的圖片有什麼好方法處理嗎? 每個平台的 Markdown 圖片處理方法好像都不一樣,圖一多都很麻煩。

Post a comment