在 Next JS 中使用 `next-mdx-remote` 时,如何在 `public/` 文件夹之外的 `.mdx` 文件中使用图像?
How to use images in a `.mdx` file outside of `public/` folder while using `next-mdx-remote` in Next JS?
我正在用 next-mdx-remote 创建一个博客,并且想使用 public/
文件夹之外的 .mdx
文件中的图像。
这是我的博客项目的完整代码→https://github.com/deadcoder0904/blog-mdx-remote
我有以下文件夹结构:
.
├── 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
我的所有内容都在 posts/
文件夹中。
我有 2 个文件夹:blog/
& tutorials/
每个 post 都在 blog/
或 tutorials/
中各自的文件夹中,并且每个文件夹都包含在特定 post 中使用的图像。
例如,在hello-world
文件夹中,有一张名为Rustin_Cohle.jpg
的图片。
我想在 hello-world/index.mdx
文件中使用此图像,但我做不到。
我不能使用 import
或 require
,因为这是 next-mdx-remote
的限制。
我尝试使用一个名为 Image
的自定义组件,它在下面使用了 img
并将其传递给 hydrate
,但它也没有用。
components/Image.js
export const Image = ({ src, alt }) => (
<img style={{ backgroundColor: 'red' }} src={src} alt={alt} />
)
pages/blog/[slug].js
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>
)
}
以下 MDX 文件使用上述 Image
组件作为通过 hydrate
。
hello-world/index.mdx
---
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
我什至尝试使用 MDXProvider
,但它也没有用。
pages/index.js
import { MDXProvider } from '@mdx-js/react'
const components = { Image }
const HomePage = ({ posts }) => {
return (
<MDXProvider components={components}>
...
</MDXProvider>
)
}
那我该如何使用图片呢?我希望它们仅位于特定的 post 文件夹中,例如 hello-world
博客仅将其图像包含在 hello-world/
文件夹中。
不幸的是,这是不可能的,因为 next-mdx-remote
将降价内容视为数据并且根本不通过 Webpack :(
我能够在这种情况下加载图像。我的想法是使用 webpack file-loader
来实现这一点,并向组件映射添加更多信息,告知当前 post 放置的位置(注意组件功能)。
我的页面[slug].js是这样的:
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
还有我的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:它与 next/image 一起工作就像一个魅力:)
请注意,从 Next.js v11 开始,您可以将图像从任何目录导入到 mdx 文件中,无需任何额外配置 - Reference 1 &
我正在用 next-mdx-remote 创建一个博客,并且想使用 public/
文件夹之外的 .mdx
文件中的图像。
这是我的博客项目的完整代码→https://github.com/deadcoder0904/blog-mdx-remote
我有以下文件夹结构:
.
├── 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
我的所有内容都在 posts/
文件夹中。
我有 2 个文件夹:blog/
& tutorials/
每个 post 都在 blog/
或 tutorials/
中各自的文件夹中,并且每个文件夹都包含在特定 post 中使用的图像。
例如,在hello-world
文件夹中,有一张名为Rustin_Cohle.jpg
的图片。
我想在 hello-world/index.mdx
文件中使用此图像,但我做不到。
我不能使用 import
或 require
,因为这是 next-mdx-remote
的限制。
我尝试使用一个名为 Image
的自定义组件,它在下面使用了 img
并将其传递给 hydrate
,但它也没有用。
components/Image.js
export const Image = ({ src, alt }) => (
<img style={{ backgroundColor: 'red' }} src={src} alt={alt} />
)
pages/blog/[slug].js
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>
)
}
以下 MDX 文件使用上述 Image
组件作为通过 hydrate
。
hello-world/index.mdx
---
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
我什至尝试使用 MDXProvider
,但它也没有用。
pages/index.js
import { MDXProvider } from '@mdx-js/react'
const components = { Image }
const HomePage = ({ posts }) => {
return (
<MDXProvider components={components}>
...
</MDXProvider>
)
}
那我该如何使用图片呢?我希望它们仅位于特定的 post 文件夹中,例如 hello-world
博客仅将其图像包含在 hello-world/
文件夹中。
不幸的是,这是不可能的,因为 next-mdx-remote
将降价内容视为数据并且根本不通过 Webpack :(
我能够在这种情况下加载图像。我的想法是使用 webpack file-loader
来实现这一点,并向组件映射添加更多信息,告知当前 post 放置的位置(注意组件功能)。
我的页面[slug].js是这样的:
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
还有我的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:它与 next/image 一起工作就像一个魅力:)
请注意,从 Next.js v11 开始,您可以将图像从任何目录导入到 mdx 文件中,无需任何额外配置 - Reference 1 &