こんにちは、柴田です。
みなさんはソースコードのシンタックスハイライトをどのように対応していますか?
おそらくライブラリを読み込んで、クライアントサイドで処理するのが一般的なのではないかと思います。
ただ、クライアントサイドで処理してしまうと表示されるまでラグがあるのであまり美しくありませんよね。
そこで今回はサーバサイドでシンタックスハイライトを行う方法を紹介します。
Jamstackなサイトでは、シンタックスハイライト済みのHTMLを配信できるので更にイケてますね!
microCMSのリッチエディタを例に解説していきます。
方法
以下のライブラリを使います。
cheerioはHTMLパーサーで、highlight.jsはシンタックスハイライト用のライブラリです。
highlight.jsには様々なAPIが用意されています。
今回は `highlightAuto()` を使います。
`highlightAuto()` は引数にソースコードの文字列を与えると、自動で言語を推測して良い感じにハイライトしてくれます。
microCMSではリッチエディタでソースコードの入力を行う場合、以下のようなHTMLが出力されます。
<pre>
<code>
// ソースコード
</code>
</pre>
cheerioを使って該当のソースコード部分を抜き出し、そこにハイライトを当てるには次のように記述します。
import cheerio from 'cheerio';
import hljs from 'highlight.js'
// 略
const $ = cheerio.load(data.body); // data.bodyはmicroCMSから返されるリッチエディタ部分
$('pre code').each((_, elm) => {
const result = hljs.highlightAuto($(elm).text());
$(elm).html(result.value);
$(elm).addClass('hljs');
});
console.log($.html()); // ハイライト済みのHTML
また、highlight.jsはハイライトのために `hljs` というclassを付与しておく必要があるので、その処理も入れています。
Jamstack構成のブログにおいては、事前ビルド時にこの処理を通すことで、ハイライト済みのHTMLをあらかじめ生成しておくことができます。
Nuxt.jsでの実装例
例として、Nuxt.jsでの実装例を紹介します。
ビルド時に呼ばれるasyncDataにて処理を記述します。
async asyncData({ params }) {
const { data } = await axios.get(
`https://xxxxxx.microcms.io/api/v1/blog/${params.slug}`,
{ headers: { 'X-MICROCMS-API-KEY': process.env.apiKey } }
);
const $ = cheerio.load(data.body);
$('pre code').each((_, elm) => {
const result = hljs.highlightAuto($(elm).text());
$(elm).html(result.value);
$(elm).addClass('hljs');
});
return {
...data,
body: $.html()
};
}
returnした内容がtemplete側で使えるのでv-htmlで表示してあげればOKです。
<div class="post" v-html="body"></div>
見た目の調整
ハイライト時の見た目はhighlight.js側で用意しているCSSから好きなものを選びましょう。
デモページで各スタイルのデモ見ることができます。
CSSはhighlight.jsのパッケージ内に含まれているので、下記のようにインポート可能です。
このブログはhybrid.cssを使っています。
import 'highlight.js/styles/hybrid.css';
以上で無事ソースコードがハイライトされていれば成功です。
おわりに
サーバーサイドでのシンタックスハイライトでは、HTMLのパースが必要なので面倒でやりたくないという人も多いのではないでしょうか。
実際にやってみると数行で実現することができ、やはりパフォーマンスはかなり良くなるのでオススメです。
-----
microCMSは日々改善を進めています。
ご意見・ご要望は管理画面右下のチャット、公式Twitter、メールからお気軽にご連絡ください!
引き続きmicroCMSをよろしくお願いいたします!