Gatsby Code SyntaxHighlighter

Gatsby Code SyntaxHighlighter

contentful リッチテキストで codeシンタックスハイライトを使う

4 minute read

このブログポストは今日現在、Gatsby+Contentful+netlifyで公開している。 プロジェクトスターターにContentful社のstarter-gatsby-blogを使ったので、ContentfulにあるBlog Postとの連携まではやたらスムーズだった。

これは他のThema、スターターを利用した場合と比較にならないくらい。 理由は、Contentful側でスターター用のContent modelとサンプルPostが用意されているのでローカルdevelopの初っ端からページ間の移動などわかりやすく構成されているためである。

ただしPostの中にあるコードにシンタックスハイライトをつけるのは、少々手間取った。 MarkdownのPostにprismjsでシンタックスハイライトをつける方法はググるとすぐ出てくるのだが、「Contentful+RichText」だと情報量がグッと減ってしまう。

途中少し諦めモードに入りそうだったが、Reactで考えると、ありそうなんだよなーと探し続け、ドンピシャの記事

Gatsby(GatsbyJS)× Contentful RichText Markdownそれぞれのcodeシンタックスハイライトの適用方法

ー GatsbyのMarkdownと、RichText、両ケースでの方法を併記してある のおかげで即解決しました。感謝!

かいつまんで違いを説明すると、Markdownの方は「gatsby-remark-prismjs」をプラグインとして適用するためConfig(gatsby-config.js)の加筆から入るが、RichTextの方は、Reactのフックと呼んでいいのか、Blog Postの[BLOCKS.PARAGRAPH] 部分で「code」を見つけたら抽出・置き換えという方法。

まずは開発環境に react-syntax-highlighter をインストール

1yarn add react-syntax-highlighter

Blog Postを表示するテンプレートファイルのimportを書き換える。

1// import { BLOCKS } from '@contentful/rich-text-types'
2import { BLOCKS, MARKS } from '@contentful/rich-text-types'

render() {・・・} の中で、const options = { } の適切な位置 renderNode: {・・・} に [BLOCKS.PARAGRAPH]と renderMark: {・・・} の [MARKS.CODE]を加筆。

1const options = {
2  renderNode: {
3    [BLOCKS.EMBEDDED_ASSET]: (node) => {
4    const { gatsbyImage, description } = node.data.target
5    return (
6      <GatsbyImage
7          image={getImage(gatsbyImage)}
8          alt={description}
9        />
10      )
11    },
12    [BLOCKS.PARAGRAPH]: (node, children) => {
13      if (
14        node.content.length === 1 &&
15        node.content[0].marks.find((x) => x.type === "code")
16      ) {
17        return <div>{children}</div>;
18      }
19      return <p>{children}</p>;
20    },
21  },
22  renderMark: {
23    [MARKS.CODE]: text => (
24      <SyntaxHighlighter language="javascript" style={okaidia} showLineNumbers>
25        {text}
26      </SyntaxHighlighter>
27    ),
28  },
29};

[BLOCKS.PARAGRAPH]のIFの戻り値を、最初は

1return <div><pre>{children}</pre></div>;

とPreタグを入れていたのですが・・・

Next.jsにreact-syntax-highlighterを導入する という記事を最後まで読むと、SyntaxHighlighterにはPreタグも含まれると書いてあったので、この長い記事を書いたあとローカル検証してPreは消しました。

Markdownの「gatsby-remark-prismjs」は prismjs 「react-syntax-highlighter」はおそらく highlightjs をベースにしてるんだろうなーと思った時に、highlightjs ならPreタグさえ入れときゃどうにかしてくれる! 感があって(←思い込み)

当初はPreだけで囲い、次にDiv+Preで囲い、結局Divだけに戻したという迷走w コードの色をつけるCSSは、ファイル冒頭のimportで

1import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
2import { okaidia } from 'react-syntax-highlighter/dist/cjs/styles/prism';

と元記事に倣ってそのままにしてますが、Next.jsの記事で紹介されていた React Syntax Highlight Sample Page のスタイルも適用できるはず。


後日早々に { dracula } テーマへ変えたときに、本家のDemoを見つけました。

React Syntax Highlighter Demo

Highlight.js (default)がベースで、Prism.jsも使えてと、すごい汎用度。