AnyDigi
アイキャッチ
Next+MicroCMSのハイライトをhighlight.jsからshikiへ
2024年7月17日

Next.js + Micro CMSのシンタックスハイライトは公式にも紹介されているようにcheerio + highlight.jsのようです。

サーバーサイドでシンタックスハイライト

非常にシンプルに実装できて良かったのですが、なぜか本番環境でのビルド時に以下のエラーで失敗します。

SyntaxError: Invalid regular expression: /0[oO](([0-7]_*)+)/mu: Invalid escape


検索しても、あまり同様の記事がないため、highlight.jsを諦めてshikiでのハイライトの実装を行いました。

shikiを選んだのはどうしてもサーバーサイドで処理したかったため。

コードとしては以下のように実装して、無事本番環境でもビルドすることができました。

import { type MicroCMSQueries } from 'microcms-js-sdk'
import type { Article } from '@/types'
import { client } from './fetchClient'
import { codeToHtml } from 'shiki'
import * as he from 'he'

export const fetchArticleDetail = async (
  contentId: string,
  queries?: MicroCMSQueries,
) => {
  const data = await client.getListDetail<Article>({
    customRequestInit: {
      next: {
        revalidate: 60,
      },
    },
    endpoint: 'articles',
    contentId,
    queries,
  })

  const codeBlockRegex =
    /<pre><code class="language-([^"]+)">([\s\S]*?)<\/code><\/pre>/g
  let match
  const promises = []

  while ((match = codeBlockRegex.exec(data.content)) !== null) {
    const [fullMatch, lang, code] = match
    const decodedCode = he.decode(code)

    promises.push(
      codeToHtml(decodedCode, { lang, theme: 'min-light' }).then((codeHtml) => {
        data.content = data.content.replace(fullMatch, codeHtml)
      }),
    )
  }

  await Promise.all(promises)

  return data
}


ちゃんとハイライトできてますよね!!