【react-markdown】コードブロックを追加してハイライトするの絵文字

【react-markdown】コードブロックを追加してハイライトする

2022-04-25

2022-04-25

はじめに

昨日たべた柿のドライフルーツ、おいしかった、こふです。

本記事では react-markdown を使って任意のプログラミング言語を書ける場所と、ハイライト(色付け)を行います。

環境

React を使います。必要な npm ライブラリは適宜インストールしてください。

インストール後の Warning が出る方は以下の記事を参考に修正してください。

更新予定:npm install 時のエラーの解決方法 3 ステップ

terminal

❯ node -v v16.14.0

package.json

... "dependencies": { ... "react": "^17.0.2", "react-dom": "^17.0.2", "react-markdown": "^8.0.1", "react-syntax-highlighter": "^15.5.0", ... }, "devDependencies": { ... "autoprefixer": "^10.4.0", "eslint": "^8.13.0", "postcss": "^8.4.5", "remark-parse": "^10.0.1", "tailwindcss": "^3.0.7", "typescript": "4.5.4" ... } ...

ソースコード

<ReactMarkdown className="省略" children={markdown} components={articleComponents} />
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' import { atomDark } from 'react-syntax-highlighter/dist/cjs/styles/prism' import { CodeComponent } from 'react-markdown/lib/ast-to-react' const customCode: CodeComponent = ({ inline, className, children }) => { const style = atomDark const match = /language-(\w+)(:?.+)?/.exec(className || '') const lang = match && match[1] ? match[1] : '' const name = match && match[2] ? match[2].slice(1) : '' if (lang === 'link') { // blog card } else if (lang === 'twitter') { // twitter embed } return !inline && match ? ( <> {name && ( <span className="rounded-md bg-stone-200 py-1 px-2 text-sm dark:bg-stone-600"> {name} </span> )} <SyntaxHighlighter children={String(children).replace(/\n$/, '')} style={style} language={lang} PreTag="div" className="border-2 text-base dark:border-stone-400 md:text-lg" /> </> ) : ( <code className="mx-1 rounded-md bg-stone-200 py-1 px-2 text-red-600 dark:bg-stone-600 dark:text-red-300"> {children} </code> ) } export const articleComponents = { code: customCode, }

ソースコード解説

分割し、説明を加えます。

ArticleContainer.tsx

<ReactMarkdown className="" children={markdown} components={articleComponents} />

これは react-mardown のコンポーネントを使い、Propsstring 型の markdown とカスタムしたコンポーネントを渡します。

ArticleComponents.tsx

import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' import { atomDark } from 'react-syntax-highlighter/dist/cjs/styles/prism' import { CodeComponent } from 'react-markdown/lib/ast-to-react' const customCode: CodeComponent = ({ inline, className, children }) => { const style = atomDark const match = /language-(\w+)(:?.+)?/.exec(className || '') const lang = match && match[1] ? match[1] : '' const name = match && match[2] ? match[2].slice(1) : '' if (lang === 'link') { // blog card } else if (lang === 'twitter') { // twitter embed }

ハイライトで囲う Prism、コードのカラーを入れてくれるテーマから atomDark、そして react-markdown から CodeComponent 型をインポートします。

正規表現の説明と方針に関しては以下で解説しています。

話はそれますが、言語(lang)ごとに出し分けていて、ブログカード・Twitter 埋め込みをしている形です。

style 変数にテーマ情報を代入します。もしダークモードでは明るい色にしたいのであれば、三項演算子などを使って代入を分けてください。


余談ですが、このサイトでは投稿日時点でハイライトのテーマは一種類に限定しています。

理由は、デフォルトの CSS 値の上書きが面倒だからです。

テーマの種類によって初期の CSS にフォントサイズが与えれているものがあります。

その場合、Tailwind CSS を使っているのですが上書きができません。

インラインの CSS を核などで対処は可能ですし、他の CSS ファイルから読み込むことも、styled-jsx を使うことも可能です。

しかし、あまり明るい色にする価値を感じていないので、一種類で大丈夫という判断です。

今後 react-markdown から軽いライブラリに変更予定なので、仮置きみたいなものです。

... return !inline && match ? ( <> {name && ( <span className="rounded-md bg-stone-200 py-1 px-2 text-sm dark:bg-stone-600"> {name} </span> )}

ここで以下のパーツを作っています。ファイルの名前を見せることで伝わりやすくする目的です。

<SyntaxHighlighter children={String(children).replace(/\n$/, '')} style={style} language={lang} PreTag="div" className="border-2 text-base dark:border-stone-400 md:text-lg" /> </> ) : (

ここがコード本体の場所で、子要素にマークダウンを渡します。

マークダウンはパースすると改行が入るので、replace で取り除いています。

replaceのドキュメント:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace

style にテーマを、language にプログラミング言語を入れます。

<code className="mx-1 rounded-md bg-stone-200 py-1 px-2 text-red-600 dark:bg-stone-600 dark:text-red-300"> {children} </code> ) } export const articleComponents = { code: customCode, }

以下のような inline のコードのデザインです。特にこだわりはありません。

他のやり方

数多くのライブラリがあるので、やり方は無限大です。

しかし、ハイライトは Prism.jsというのが一般的に普及しており、使っておけば問題ないといえます。

markdown をパースするライブラリはラップしている react-markdown が楽でおすすめです。

が、かゆいところに手が届かないので書き換え予定です。後日、記事にします。

さいごに

最後まで読んでいただきありがとうございました。

これでコードを綺麗に見せることができます、どんどん書いたコードを貼り付けよう!

参考



アバター

こふ

情報通信を専攻している大学生です。大学(研究)・趣味・アルバイトでプログラムを書いています。ITツール・サービス・文章を創作することが好きです。

ぼくについて

共有する