[JavaScript/Node.js] marked のコードブロックを Prism でプリレンダする
戻る > エンジニア - Web開発
関連:[JavaScript] Markdown形式をそのまま Webページとして表示する
関連:[JavaScript] marked.js のコードブロックに色付けする
関連:[JavaScript/Node.js] marked のコードブロックを Prism
でプリレンダする
概要
markedとPrism
をサイトで使用すると、画面のちらつきとか、負荷とかが気になってくる
後パーミッションとか設定が面倒
ならいっそ HTML化(プリレンダリング)するかということで思い立つも、ChatGPTを頼っても時間がかかって野で備忘
実装
結構大規模な記述になる
第1段階 - Node.jsで marked を使う
基本はサイトでの利用と同じ
npm install marked
npm install で marked をインストール
// marked のインポート (ESModule)
import { marked } from 'marked';
// 適当なマークダウン
const markdownText = "# h1content\n\nblahblahblah\n";
// パース
const markdownHtml = marked.parse(markdownText);
パースを実装するとこう
第2段階 - Prism を適用する
npm install prismjs
npm install で追加インストール
先の記述に加え、下記を適当に追加する
import Prism from 'prismjs';
import loadLanguages from 'prismjs/components/index.js';
// Prism 対象言語読み込み : ビルダーのため全種対応
loadLanguages();
// marked の設定をカスタマイズ
marked.use({
extensions: [
{
name: 'code',
level: 'block',
start(src) {
const match = src.match(/^```/gm);
return match ? match.index : undefined;
},
tokenizer(src) {
const rule = /^```(\w+)?\n([\s\S]*?)```/;
const match = rule.exec(src);
if (match) {
return {
type: 'code',
raw: match[0],
lang: match[1],
text: match[2]
};
}
return;
},
renderer(token) {
const lang = token.lang || '';
const code = token.text;
if (Prism.languages[lang]) {
const html = Prism.highlight(code, Prism.languages[lang], lang);
return `<pre class="language-${lang}"><code class="language-${lang}">${html}</code></pre>`;
}
return `<pre><code>${code}</code></pre>`;
}
}
]
});
Prismを適用するため、コードブロックを再定義する必要があるそうで、結構大変なことになった
start、tokenizer がmarkdownのパースの条件
renderer がPrismの適用
renderer の token には、lang と text が渡される
これはtokenizerの設定に従う
例えば、以下のmarkdown があったとする
```javascript
console.log('output');
```
この場合、lang は「javascript」、text は「
console.log('output');
」になる
後は if文で対応した言語か判定し、対応していればhightlight化する
対応できない方法
「setOptions」にて設定する方法、「marked
をインスタンス化して、初期化パラメータにてレンダラーを設定する方法」も見つかる(ChatGPTから提案される)が
最新の marked では非対応である
marked.setOptions({
highlight: (code, lang) => {
if (Prism.languages[lang]) {
return Prism.highlight(code, Prism.languages[lang], lang);
}
return code;
}
});
setOptions の例
const renderer = {
code(code, infostring) {
const lang = infostring || '';
if (Prism.languages[lang]) {
const html = Prism.highlight(code, Prism.languages[lang], lang);
return `<pre class="language-${lang}"><code class="language-${lang}">${html}</code></pre>`;
}
return `<pre><code>${code}</code></pre>`;
}
};
markedInstance.use({ renderer });
use にレンダラーを渡す例
infostring は undefined となり、言語を渡してこない