@next/mdx
插件的主要作用是 让 Next.js 支持 MDX 文件的导入和使用。
什么是 @next/mdx
@next/mdx
是 Next.js 官方提供的一个插件,它结合了:
- Markdown(
.md
)的简洁书写格式 - 和 JSX(React 组件)的功能
即:你可以在 .mdx
文件中写 Markdown 内容,也可以直接写 React 组件,比如:
# 这是一个标题
这是正文内容
<MyComponent />
主要作用
使用 require('@next/mdx')
的目的是:
把 .mdx
文件转译为可以被 Next.js 使用的 React 组件
常见的配置写法如下:
const withMDX = require('@next/mdx')({
extension: /\.mdx?$/
})
module.exports = withMDX({
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx']
})
配置解释
require('@next/mdx')({ extension })
这是创建 MDX 插件实例,同时指定要处理.mdx
文件。withMDX(...)
把这个插件应用到你的 Next.js 配置中。pageExtensions
告诉 Next.js,页面可以用.mdx
、.md
、.tsx
等文件扩展名。
总结一句话:
require('@next/mdx')
的作用是让 Next.js 可以加载和渲染.mdx
文件,把它们当作 React 组件来用。
完整例子
一、安装依赖
npm install @next/mdx @mdx-js/loader
二、配置 next.config.js
创建或修改 next.config.js
:
// next.config.js
const withMDX = require('@next/mdx')({
extension: /\.mdx?$/,
})
module.exports = withMDX({
// 支持哪些扩展名作为页面
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'mdx'],
})
三、创建一个 .mdx
页面
在 pages
目录下创建一个 .mdx
页面,比如:
touch pages/about.mdx
内容示例:
# 关于我们
这是一个用 **MDX** 写的页面。
你还可以使用 React 组件,比如:
<CustomMessage name="张三" />
四、定义你用到的 React 组件
比如你用了 <CustomMessage />
,就要在 _app.js
或 .mdx
文件中导入:
方法一:直接在 .mdx
文件中引入
import CustomMessage from '../components/CustomMessage'
# 欢迎
<CustomMessage name="李四" />
方法二:在 _app.js
中提供(不推荐除非全局使用)
五、创建组件
mkdir components
touch components/CustomMessage.js
components/CustomMessage.js
:
export default function CustomMessage({ name }) {
return <p>你好,{name},欢迎访问我们的网站!</p>
}
六、运行项目
npm run dev
访问 http://localhost:3000/about,你将看到:
关于我们
这是一个用 MDX 写的页面。
你好,张三,欢迎访问我们的网站!
高级玩法
一、带 Layout 的 .mdx
页面写法
目标:每个 .mdx
页面可以套用一个公共的布局(如统一导航、样式等)
1. 创建一个 Layout 组件(比如 components/Layout.js
)
// components/Layout.js
export default function Layout({ children }) {
return (
<div style={{ padding: 20, border: '1px solid #ddd' }}>
<h1>网站公共标题</h1>
<main>{children}</main>
</div>
);
}
2. 在 .mdx
页面中使用这个 Layout
---
layout: ../components/Layout
---
# 欢迎访问
这是一段内容。
上面这段
---
是 YAML Frontmatter,用来指定 layout。
3. 在 pages/_app.js
中配置 MDX 的 layout 插件解析
需要用 next-mdx-enhanced
或自己写 loader,但更推荐直接使用 MDX Component Wrapping 方案:
新方法(MDX 文件中直接导入组件):
import Layout from '../components/Layout'
export default ({ children }) => <Layout>{children}</Layout>
# 标题
MDX 页面内容。
你也可以把 Layout 封装为默认导出的组件,.mdx
就变成一个真正的 React 组件。
二、多语言 MDX 页面结构(i18n)
Next.js 内置国际化(i18n)支持,你可以结合 .mdx
页面实现多语言切换。
1. 修改 next.config.js
增加 i18n
:
module.exports = {
i18n: {
locales: ['en', 'zh'],
defaultLocale: 'zh',
},
}
2. 按语言目录创建页面结构
pages/
zh/
about.mdx
en/
about.mdx
然后访问:
/zh/about
:中文页面/en/about
:英文页面
三、动态加载 MDX 内容(next-mdx-remote
)
这种方式适合动态内容渲染,比如从 CMS、文件系统、数据库读取 .mdx
内容,然后渲染为 React 页面。
1. 安装依赖:
npm install next-mdx-remote
2. 页面示例(pages/blog/[slug].js
):
import { MDXRemote } from 'next-mdx-remote';
import { serialize } from 'next-mdx-remote/serialize';
import fs from 'fs';
import path from 'path';
export default function BlogPost({ source }) {
return (
<article>
<MDXRemote {...source} />
</article>
);
}
export async function getStaticPaths() {
const files = fs.readdirSync('posts');
const paths = files.map(file => ({
params: { slug: file.replace(/\.mdx$/, '') },
}));
return { paths, fallback: false };
}
export async function getStaticProps({ params }) {
const filepath = path.join('posts', `${params.slug}.mdx`);
const raw = fs.readFileSync(filepath, 'utf-8');
const mdxSource = await serialize(raw); // 转换为 MDX 可渲染结构
return { props: { source: mdxSource } };
}
3. 示例目录结构:
posts/
hello.mdx
pages/
blog/
[slug].js
4. 访问效果:
访问 /blog/hello
就会动态渲染出 posts/hello.mdx
内容。
总结对比
方式 | 用途 | 是否支持动态内容 | 是否能嵌入组件 |
---|---|---|---|
@next/mdx |
静态页面,支持组件,配置简单 | 否 | ✅ |
带 Layout 的 MDX | 统一结构化渲染,适合文档站 | 否 | ✅ |
多语言结构 | 多语言版本页面支持 | 否 | ✅ |
next-mdx-remote |
动态渲染,适合博客/CMS场景 | ✅ | ✅ |