※記事のURLの一部は広告を含みます。

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

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

2022-04-25

2022-04-25

はじめに

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

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

環境

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

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

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

terminal

1❯ node -v 2v16.14.0

package.json

1... 2"dependencies": { 3 ... 4 "react": "^17.0.2", 5 "react-dom": "^17.0.2", 6 "react-markdown": "^8.0.1", 7 "react-syntax-highlighter": "^15.5.0", 8 ... 9 }, 10 "devDependencies": { 11 ... 12 "autoprefixer": "^10.4.0", 13 "eslint": "^8.13.0", 14 "postcss": "^8.4.5", 15 "remark-parse": "^10.0.1", 16 "tailwindcss": "^3.0.7", 17 "typescript": "4.5.4" 18 ... 19 } 20...

ソースコード

1<ReactMarkdown 2 className="省略" 3 children={markdown} 4 components={articleComponents} 5/>
1import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' 2import { atomDark } from 'react-syntax-highlighter/dist/cjs/styles/prism' 3import { CodeComponent } from 'react-markdown/lib/ast-to-react' 4 5const customCode: CodeComponent = ({ inline, className, children }) => { 6 const style = atomDark 7 const match = /language-(\w+)(:?.+)?/.exec(className || '') 8 const lang = match && match[1] ? match[1] : '' 9 const name = match && match[2] ? match[2].slice(1) : '' 10 if (lang === 'link') { 11 // blog card 12 } else if (lang === 'twitter') { 13 // twitter embed 14 } 15 return !inline && match ? ( 16 <> 17 {name && ( 18 <span className="rounded-md bg-stone-200 py-1 px-2 text-sm dark:bg-stone-600"> 19 {name} 20 </span> 21 )} 22 <SyntaxHighlighter 23 children={String(children).replace(/\n$/, '')} 24 style={style} 25 language={lang} 26 PreTag="div" 27 className="border-2 text-base dark:border-stone-400 md:text-lg" 28 /> 29 </> 30 ) : ( 31 <code className="mx-1 rounded-md bg-stone-200 py-1 px-2 text-red-600 dark:bg-stone-600 dark:text-red-300"> 32 {children} 33 </code> 34 ) 35} 36export const articleComponents = { 37 code: customCode, 38}

ソースコード解説

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

ArticleContainer.tsx

1<ReactMarkdown 2 className="" 3 children={markdown} 4 components={articleComponents} 5/>

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

ArticleComponents.tsx

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

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

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

https://blog.cohu.dev/react-markdown-blog-card#どうやるか

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

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


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

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

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

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

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

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

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

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

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

ファイルのパーツ

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

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

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

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

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

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

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

inline のコードのデザイン

他のやり方

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

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

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

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

おわりに

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

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

参考




共有する