I am making a blog with next-mdx-remote & want to use images in the .mdx
file outside of the public/
folder.
Here's the complete code of my blog project → https://github.com/deadcoder0904/blog-mdx-remote
I have the following folder structure:
.
├── package-lock.json
├── package.json
├── pages
│ ├── _app.js
│ ├── blog
│ │ └── [slug].js
│ ├── dark.css
│ ├── index.js
│ └── new.css
├── posts
│ ├── blog
│ │ ├── hello-world
│ │ │ ├── Rustin_Cohle.jpg
│ │ │ └── index.mdx
│ │ └── shit-world
│ │ └── index.mdx
│ └── tutorials
│ └── console-log-in-javascript
│ └── index.mdx
└── utils
└── mdxUtils.js
I have all my content in posts/
folder.
I have 2 folders in it: blog/
& tutorials/
Each post is in their own folder inside of blog/
or tutorials/
& every one of those folder contain images that are used in that particular post.
For example, in the hello-world
folder, there is 1 image named Rustin_Cohle.jpg
.
I want to use this image in hello-world/index.mdx
file but I'm unable to do it.
I can't use import
or require
as it's a limitation of next-mdx-remote
.
I tried using a custom component called Image
that used img
underneath & passed it to hydrate
but it didn't work either.
export const Image = ({ src, alt }) => (
<img style={{ backgroundColor: 'red' }} src={src} alt={alt} />
)
import hydrate from 'next-mdx-remote/hydrate'
import { Image } from '../components/Image'
const components = { Image }
const Blog = ({ source, frontMatter }) => {
const content = hydrate(source, { components })
return (
<div>
<h1>{frontMatter.title}</h1>
{content}
</div>
)
}
The following MDX file uses the above Image
component as passed through hydrate
.
---
title: Hello World
date: '2019-09-06T14:54:37.229Z'
tags: ['hello', 'world']
author: John Doe
description: This is the first post
---
Hey this is my first post
![Rustin Cohle](./Rustin_Cohle.jpg)
<img src="./Rustin_Cohle.jpg" alt="Rust Cohle" />
<Image src="./Rustin_Cohle.jpg" alt="Rust Cohle" />
This is the end of the first post
I even tried using MDXProvider
& it didn't work either.
import { MDXProvider } from '@mdx-js/react'
const components = { Image }
const HomePage = ({ posts }) => {
return (
<MDXProvider components={components}>
...
</MDXProvider>
)
}
How do I use images then? I want them to be only in the particular post's folder like hello-world
blog would contain its images only in hello-world/
folder.
I was able to load images in this scenario. My idea was to use webpack file-loader
to accomplish this and add more info to components mapping telling where the current post is placed (note the components function).
My page [slug].js is like this:
import renderToString from 'next-mdx-remote/render-to-string'
import hydrate from 'next-mdx-remote/hydrate'
import matter from 'gray-matter'
import { getAllPostSlugs, getPostdata } from '../lib/posts'
const components = (slug) => ({
h1: ({ children }) => <h1>{children}</h1>,
img: ({ src, alt }) => {
return (
<p>
<img
alt={alt}
src={require('../content/' + slug + '/' + src).default}
/>
</p>
)
}
})
const Post = ({ source, frontMatter, slug }) => {
const content = hydrate(source, {
components: components(slug)
})
return (
<>
<h1>Post</h1>
<p>{content}</p>
</>
)
}
export async function getStaticPaths() {
const paths = getAllPostSlugs()
return {
paths,
fallback: false
}
}
export async function getStaticProps({ params }) {
const postContent = await getPostdata(params.slug)
const { data, content } = matter(postContent)
const mdxSource = await renderToString(content, {
components: components(params.slug),
scope: data
})
return {
props: {
slug: params.slug,
source: mdxSource,
frontMatter: data
}
}
}
export default Post
And my next.config.js:
module.exports = {
webpack: (config, options) => {
config.module.rules.push({
test: /\.(svg|png|jpe?g|gif|mp4)$/i,
use: [
{
loader: 'file-loader',
options: {
publicPath: '/_next',
name: 'static/media/[name].[hash].[ext]'
}
}
]
})
return config
}
}
Ps: it works like a charm with next/image :)
It's not possible unfortunately as next-mdx-remote
treats the markdown content as data & doesn't pass through Webpack at all :(
Note that starting with Next.js v11, you can import images from any directory into a mdx file without any additional config - Reference 1 & Reference 2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With