Webのあれこれ

アイキャッチアイコンhtml-react-parser × highlight.jsでコードブロックをハイライト

カテゴリ: React / Next.js

  • 作成日:2023/03/08
  • 更新日:2023/04/02

目次

    Reactのパースライブラリである、html-react-parserとシンタックスハイライトをつけることができる highlight.jsについて紹介します。
    このブログでは、元々cheerioを使っていました。
    cheerioは、jQueryライクに書けることで人気のライブラリですが、
    ・過去のjQueryのトラウマ(?)
    ・関数の処理が直感的ではなく分かりにくい
    ・このブログを製作時に、microCMSさんのブログを参考に、ほぼそのままコードを使ったのでちゃんと理解してない気がする

    ということで、何か他のパースライブラリはないかなと思っていたら、html-react-parserがとても便利でしたのでご紹介です!

    手順

    インストール

    // npm
    npm install html-react-parser highlight.js
    
    // yarn
    yarn add dayjs html-react-parser highlight.js


    作業環境

    インストールが完了したら、実際にパース+ハイライトしていきます。
    今回は、PostSingle.tsxというところに書いていきます。

    以下のようなイメージとなります。

    src/
    ├ components/
    │     └ PostSingle/ // ここを触る
    ├ pages/
    │  └ index.tsx
    │  └ post/
    │      └ [id].tsx  // ここでデータ取得(SSG)
    └ lib/


    コンポーネントのPostSingleには、1記事分のデータが渡ってきている想定です。

    実装したコード

    先に今回実装したコードが下記になります。
    *今回のテーマに関係ない箇所は省略しています

    type ElementType = Partial<{
      fieldId: string
      richEditor: string
      html: string
    }>
    
    type Props = {
      post: MicrocmsData // microCMSの記事の返却値
    }
    
    const PostSingle = ({ post }: Props) => {
    
      // リッチエディタとテキストエリアの表示
      const contentPost: string = post.content.reduce(
        (sum: string, element: ElementType) => {
          return sum + (element.richEditor || element.html)
        },
        ''
      )
    
      // pre > code シンタックスハイライト
      const parseOptions: HTMLReactParserOptions = {
        replace: (domNode) => {
          if (!(domNode instanceof Element && domNode?.attribs)) {
            return undefined
          }
          if (domNode.name === 'pre') {
            const code: string = domNode.children[0].children[0].data // pre配下のcode(インラインコードは反映しない)
            const highlightCode: AutoHighlightResult = hljs.highlightAuto(code) // ハイライトのスタイル
    
            return (
              <pre>
                <code className="hljs">{parse(highlightCode.value)}</code>
              </pre>
            )
          }
        },
      }
    
      return  <div css={content}>{parse(contentPost, parseOptions)}</div>
        }


    解説

    記述したコードを上から解説してきます。

    まず、今回はmicroCMSのデータが繰り返しフィールドになっていたのでそちらを連結させます。
    今回は、reduceメソッドを用いてみました。
    ちなみにリッチエディタのみの場合はこの処理は不要です。

      // リッチエディタとテキストエリアの表示
      const contentPost: string = post.content.reduce(
        (sum: string, element: ElementType) => {
          return sum + (element.richEditor || element.html)
        },
        ''
      )


    npmで使い方を見ると、以下のように書いてあります。
    function ReactHtmlParser(html, [options])

    第一引数にパースしたい文字列、第二引数にオプションを渡すことが可能です。
    今回は、以下のようにオプションを渡しました。

      // pre > code シンタックスハイライト
      const parseOptions: HTMLReactParserOptions = {
        replace: (domNode) => {
          if (!(domNode instanceof Element && domNode?.attribs)) {
            return undefined
          }
          if (domNode.name === 'pre') {
            const code: string = domNode.children[0].children[0].data // pre配下のcode(インラインコードは反映しない)
            const highlightCode: AutoHighlightResult = hljs.highlightAuto(code) // ハイライトのスタイル
    
            return (
              <pre>
                <code className="hljs">{parse(highlightCode.value)}</code>
              </pre>
            )
          }
        },
      }


    domNodeに、テキストやタグの情報が格納されているので、そこの値を条件分岐することでオプションを詳細に指定することができます。いろいろカスタマイズできそう!
    ちなみに、console.log()を挟んでみるとこんな感じです。

    コンソール画面:domNodeの返却値


    最初のif文については、TypeScriptを使う場合に必要になります。詳細はこちらをご確認ください。

    2つ目のdomNode.name === 'pre' のif文については、パースした中身を表示するのと、highlight.jsを適用させるために.hljsを指定します。
    直接、codeを触った方が楽なのですが、インラインコードの場合にも適用されてしまうのでコードブロックを適用させるためにpreの分岐にしています。

    ここのreturnで、クラスの指定や加工ができ、またJSで書けるのでcheerioよりも扱いやすいなと感じました。

    またhighlight.jsでは、言語を指定してシンタックスハイライトを当てることも可能ですので試してみてください。
    こちらのデモページでスタイルの種類を確認できます。

    今回は、汎用的に使えるものを選定しました。highlight.jsに入っているので下記のようにimportするだけで使用可能です。

    import 'highlight.js/styles/hybrid.css'


    おわり

    Reactのパースライブラリは他にもいくつかありますが、html-react-parser はおすすめ出来ます。
    highlight.jsもかなり人気のライブラリですので、ブログを作る際などにぜひ取り入れてみてください🙌

    この記事へのコメント

    この記事にはまだコメントがありません。

    お気軽にコメント残してください📝

    © 2022 wadeenOpenMojiis licensed underCC BY-SA 4.0