Markdown 和 MDX
Markdown 是一种轻量级标记语言,用于格式化文本。 它允许您使用纯文本语法编写,并将其转换为结构有效的 HTML。 通常用于在网站和博客上编写内容。
你可以这样写...
I **love** using [Next.js](https://nextjs.org/)
输出:
<p>I <strong>love</strong> using <a href="https://nextjs.org/">Next.js</a></p>
MDX 是 markdown 的超集, 允许您直接在 markdown 文件中编写 JSX。 这是一种在内容中添加动态交互性并嵌入 React 组件的强大方式。
Next.js 可以支持应用内的本地 MDX 内容,以及在服务器上动态获取的远程 MDX 文件。 Next.js 插件负责将 markdown 和 React 组件转换为 HTML, 包括在 App Router 中使用 Server Components(在 App Router 中为默认设置 )的支持。
@next/mdx
@next/mdx
包用于配置 Next.js,以便处理 markdown 和 MDX。
它从本地文件中提取数据,允许您直接在 /pages
或 /app
目录中创建扩展名为 .mdx
的页面。
让我们来看看如何配置和使用 Next.js 中的 MDX。
入门
安装用于渲染 MDX 所需的包:
npm install @next/mdx @mdx-js/loader @mdx-js/react @types/mdx
在应用程序的根目录(/app
或 src
的父文件夹)创建一个 mdx-components.tsx
文件:
使用 App Router 与 MDX 需要 mdx-components.tsx
,没有它将无法正常工作。
import type { MDXComponents } from 'mdx/types'
export function useMDXComponents(components: MDXComponents): MDXComponents {
return {
...components,
}
}
更新项目根目录下的 next.config.js
文件以配置其使用 MDX:
const withMDX = require('@next/mdx')()
/** @type {import('next').NextConfig} */
const nextConfig = {
// 配置 `pageExtensions` 以包含 MDX 文件
pageExtensions: ['js', 'jsx', 'mdx', 'ts', 'tsx'],
// 可选地,在下面添加任何其他 Next.js 配置
}
module.exports = withMDX(nextConfig)
然后,在 /app
目录中创建一个新的 MDX 页面:
your-project
├── app
│ └── my-mdx-page
│ └── page.mdx
└── package.json
现在,您可以在 MDX 页面中直接使用 markdown 并导入 React 组件:
import { MyComponent } from 'my-components'
# Welcome to my MDX page!
This is some **bold** and _italics_ text.
This is a list in markdown:
- One
- Two
- Three
Checkout my React component:
<MyComponent />
导航到 /my-mdx-page
路由应该显示您渲染的 MDX。
远程 MDX
如果您的 markdown 或 MDX 文件或内容存储在其他位置,您可以在服务器上动态获取它。这对于存储在单独的本地文件夹、CMS、数据库或其他任何地方的内容非常有用。
有两个用于获取 MDX 内容的流行社区包:
next-mdx-remote
contentlayer
请小心使用。MDX 编译为 JavaScript 并在服务器上执行。 您应该只从可信赖的源获取 MDX 内容,否则可能导致远程代码执行(RCE)。
以下示例使用 next-mdx-remote
:
import { MDXRemote } from 'next-mdx-remote/rsc'
export default async function RemoteMdxPage() {
// MDX 文本 - 可以来自本地文件、数据库、CMS、fetch 等任何地方...
const res = await fetch('https://...')
const markdown = await res.text()
return <MDXRemote source={markdown} />
}
导航到 /my-mdx-page-remote
路由应该显示您渲染的 MDX。
布局
要在 MDX 页面之间共享布局,可以使用 App Router 的内置布局支持。
export default function MdxLayout({ children }: { children: React.ReactNode }) {
// 在这里创建任何共享布局或样式
return <div style={{ color: 'blue' }}>{children}</div>
}
Remark 和 Rehype 插件
您可以选择提供 remark
和 rehype
插件来转换 MDX 内容。
例如,您可以使用 remark-gfm
来支持 GitHub Flavored Markdown。
由于 remark
和 rehype
生态系统仅支持 ESM,
您需要使用 next.config.mjs
作为配置文件。
import remarkGfm from 'remark-gfm'
import createMDX from '@next/mdx'
/** @type {import('next').NextConfig} */
const nextConfig = {
// 配置 `pageExtensions` 以包含 MDX 文件
pageExtensions: ['js', 'jsx', 'mdx', 'ts', 'tsx'],
// 可选地,在下面添加任何其他 Next.js 配置
}
const withMDX = createMDX({
// 在这里添加 markdown 插件,根据需要
options: {
remarkPlugins: [remarkGfm],
rehypePlugins: [],
},
})
// 将 MDX 配置与 Next.js 配置 合并
export default withMDX(nextConfig)
Frontmatter
Frontmatter 是一种类似于 YAML 的键值对,用于存储有关页面的数据。
@next/mdx
默认不支持 frontmatter,
尽管有许多解决方案可以将 frontmatter 添加到 MDX 内容中,例如:
要使用 @next/mdx
访问页面元数据,您可以在 .mdx
文 件内导出一个 metadata 对象:
export const metadata = {
author: 'John Doe',
}
# My MDX page
自定义元素
使用 markdown 的一个愉快之处是,它映射到本机 HTML
元素,使得编写快速且直观。
This is a list in markdown:
- One
- Two
- Three
上述生成以下 HTML:
<p>This is a list in markdown:</p>
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
当您想为网站或应用程序的自定义感觉为您自己的元素设置样式时,您可以传递短代码。
这些是映射到 HTML
元素的您自己的自定义组件。
为此,打开应用程序根目录中的 mdx-components.tsx
文件并添加自定义元素:
import type { MDXComponents } from 'mdx/types'
import Image from 'next/image'
// 此文件允许您提供要在 MDX 文件中使用的自定义 React 组件
// 您可以导 入和使用任何您想要的 React 组件,包括内联样式、
// 来自其他库的组件等等。
export function useMDXComponents(components: MDXComponents): MDXComponents {
return {
// 允许自定义内置组件,例如添加样式。
h1: ({ children }) => <h1 style={{ fontSize: '100px' }}>{children}</h1>,
img: (props) => (
<Image
sizes="100vw"
style={{ width: '100%', height: 'auto' }}
{...props}
/>
),
...components,
}
}