2021-05-03
NextJSで作成したブログにシンタックスハイライトを導入する(PrismJS)

導入

このブログは2021年5月3日現在NextJSを利用で静的サイト生成して配信しています。

シンタックスハイライトでよく利用されるPrismは、通常CSSやJSを外部から取得しています。この方式はもちろんNextJSでも利用できますが静的サイト生成を行う段階であらかじめ取得しておいて最適化して配布することもできます。

こちらはこの方式でシンタックスハイライトを適用した結果です

(e.g.) Python

def main(num: int) -> None:
    for i in range(num):
        if (i % 15 == 0):
            print("Fizz Buzz")
        elif (i % 3 == 0):
            print("Fizz")
        elif (i % 5 == 0):
            print("Buzz")
        else:
            print(i)

if __name__ == "__main__":
    main(30)

やり方

おおまかには以下の手順でPrismを導入します。

  • 関連するnpmパッケージを取得
  • Prismをソースコードに組み込む
  • Babelの設定

Babelの設定はシンタックスハイライトを適用する言語を指定したり、使うテーマを決めたりするのに使います。もし対応言語やテーマを初期設定から変更する必要がなければBabelの設定は必要ありません。

npmパッケージの取得

yarnまたはnpmで以下のようにnpmパッケージを取得します。

yarn add prismjs
yarn add --dev babel-plugin-prismjs @types/prismjs
  • prismjsは必須です。
  • babel-plugin-prismjsは後々に扱う言語やテーマを決めるのに必要です。逆に初期設定で十分であればインストールしなくてもよいです。
  • @types/prismjs: TypeScriptを使わない場合には不要です。

Prismを組み込む

prism.highlightAllは該当ドキュメントでソースコードを見つけて必要なクラスを適用します。適用したいコンポーネントにuseEffectフックを使ってhighlightAllを一度だけ実行するように設定します。

import prism from "prismjs"
....
  useEffect(() => {
    prism.highlightAll()
  }, [])

Babelの設定

Prismは幅広い言語に対応しているものの、初期設定ではHTML, CSS, JavaScriptにのみ適用されます。静的サイト生成を行う場合にはBabelを使うことで、生成中に対応する言語を指定することができます。

対応するすべての言語を扱えるようにするには以下の設定になります。

babel.config.js

const PrismComponents = require("prismjs/components.json")

const LANGUAGES = Object.keys(PrismComponents.languages)
    .filter(lang => lang !== "meta")
const THEME     = "tomorrow"

module.exports = {
    "presets": ["next/babel"],
    "plugins": [
      [
        "prismjs",
        {
            "languages": LANGUAGES,
            "plugins": [],
            "theme": THEME,
            "css": true
        }
      ]
    ]
}
  • THEMEは利用するテーマです。
  • LANGUAGESは対応する言語です。

これですべての言語が指定できるカラクリを簡単に説明すると、https://github.com/PrismJS/prism/blob/master/components.jsonにあるPrismのデータファイルにあるlanguagesから対応している言語名のリストを取り出しています。この際、言語名ではない設定項目のmetaが混じっているので取り除くようにします。このファイルには対応するテーマも載っているので、Prismの開発に参画するつもりがなくても目を通しておくといいと思います。

もし使用する言語を限定したい場合には使用する言語とその表記でどのように言語を指定するか確認します。

例えばSQLを導入したい場合には

SQL - sql

とあるので

// const LANGUAGES = Object.keys(PrismComponents.languages)
    // .filter(lang => lang !== "meta")
const LANGUAGES = [ 'sql' ]

と指定します。またbabel.config.jsでなく.babelrcで指定しても構いません。

参考資料

Prismの公式サイト

NextJSでBabelの設定を変更する方法が載っている公式ドキュメント

Prismの対応しているテーマや言語がわかる技術的な資料としても使える(同じ情報は公式サイトにも載っているので過度に気にする必要はない)。