WOF Tech Blog

Next.jsでmarkdownで挿入した画像をnext/imgタグを使って画像最適化する

背景

react-markdown を使って markdown→html 変換をしていたが、md 内に挿入した画像は、img タグとして html 化されることがわかった(next/img による画像最適が行われていない)。そのため、next/img タグを使用した html 変換ができる方法を探した。

結論

next-mdx-remote というパッケージを利用することでできた。

next.jsコード
[slug].js
// this object will contain all the replacements we want to make
const components = {
img: (props) => (
// height and width are part of the props, so they get automatically passed here with {...props}
<Image {...props} layout="responsive" loading="lazy" />
),
};
const PostContent = ({ post }) => {
return (
<>
<Head>
<title>{post.title} | MyWebsite</title>
</Head>
<article>
<header>
<h2 className={styles.header}>{post.title}</h2>
<span>
Posted: <time dateTime={post.date}>{post.date}</time>
</span>
</header>
<div className={mdstyles.mdody}>
{/* MDXRemote uses the components prop to decide which html elements to switch for components */}
<MDXRemote {...post.mdxSource} components={components} />
</div>
</article>
</>
);
}
(snip)
export const getStaticProps = async ({ params }) => {
const postPath = path.join("data", `${params.slug}.md`);
const file = matter.read(postPath);
const post = {
title: file.data.title,
date: file.data.date,
body: file.content,
};
// get your markdown here
// pass your markdown string to the serialize function
const mdxSource = await serialize(post.body, {
mdxOptions: {
// use the image size plugin, you can also specify which folder to load images from
// in my case images are in /public/images/, so I just prepend 'public'
rehypePlugins: [[imageSize, { dir: "public" }]],
},
});
// return your serialized content as a prop here
return {
props: {
post: {
title: post.title,
date: post.date,
mdxSource
},
},
};
};
markdown中身
![beach](/blog/beach.jpg)
---
![tree](/blog/tree.jpg)
表示結果

beach


tree

参考にしたサイト

https://ironeko.com/posts/how-to-use-next-js-image-with-markdown-or-mdx