【Next.js】next/imageとReact-Markdownを使いマークダウン内の画像を最適化する
タグ:
Next.js
next/imageについて
Next10より提供されたnext/imageは、画像の軽量化とレスポンシブ対応を自動で適応してくれるImageタグを提供してくれます。
このライブラリはImageタグを書く必要があるので、そのままではマークダウン内の画像にも適用させることができません。
今回は、React-Markdownを利用してnext/image をマークダウン内の画像に適用させる方法をメモします。
Next.jsの公式チュートリアルを終えたところからの主な変更点を掲載します。
参考: Using NextJS and Next/Image with MDX Markdown Processing
React-Markdownを導入する
yarn add react-markdown
React-Markdownではrenderersオブジェクトでレンダリング方法を変更することができる。 詳しくはこちらReact-MarkDown
このrenderersオブジェクトでimgタグはnext/imageを使用するように指定すれば良い。
import Image from 'next/image' import Layout from '../components/layout' const renderers = { image: image => { return <Image src={image.src} alt={image.alt} width="600" height="450" /> }, } export default function Post({ postData }) { return ( <Layout> <Head> <title>{postData.title}</title> </Head> {/* ReactMarkdownを使わないとき */} {/* <div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} /> */} {/* ReactMarkdownを使うとき */} <ReactMarkdown children={postData.content} allowDangerousHtml = {true} renderers={renderers} /> </Layout> ) } //その他使っている関数 export async function getStaticProps({ params }) { // Fetch necessary data for the blog post using params.id const postData = await getPostData(params.id) return { props: { postData } } } export async function getPostData(id) { const fullPath = path.join(postsDirectory, `${id}.md`) const fileContents = fs.readFileSync(fullPath, 'utf8') const { data, content } = matter(fileContents) //本来はマークダウンから取得した本文が入っているcontentをHTMLに変換する // const contentHtml = await markdownToHtml(matterResult) //マークダウンから取得した本文が入っているcontentをそのまま渡す return { id, ...data, content } }
これによってブログ画像のレスポンシブ対応はnext/imageに全て任せることが出来るようになった。
おまけ:react-syntax-highlighterを導入する
ついでにreact-syntax-highlighterを使って、 このページのようにコードブロックを扱えるようにします。
yarn add react-syntax-highlighter
react-syntax-highlighterを導入したあと、下記のようにrenderersを書き換えればOK。
import ReactMarkdown from 'react-markdown'; import Image from "next/image"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; const renderers = { image: image => { return <Image src={image.src} alt={image.alt} width="600" height="450" /> }, code: ({ language, value }) => { return <SyntaxHighlighter language={language} children={value} /> } }