Next.js构建报错:MDXRemote无法作为JSX组件使用
Bug描述
执行命令npm run build构建Next.js应用失败,但npm run dev开发环境运行正常。
package.json内容
{ "name": "next-app-template", "version": "0.0.1", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "eslint . --ext .ts,.tsx -c .eslintrc.json --fix" }, "dependencies": { "@nextui-org/avatar": "^2.0.33", "@react-aria/ssr": "3.9.4", "@react-aria/visually-hidden": "3.8.12", "clsx": "2.1.1", "date-fns": "^4.1.0", "framer-motion": "~11.1.1", "gray-matter": "^4.0.3", "intl-messageformat": "^10.5.0", "next": "14.2.4", "next-mdx-remote": "^5.0.0", "next-themes": "^0.2.1", "react": "18.3.1", "react-dom": "18.3.1", "react-syntax-highlighter": "^15.5.0" } }
page.tsx内容
import { MDXRemote } from "next-mdx-remote/rsc"; import { getAllPostIds, getPost } from "@/lib/post"; const components = { h2: ({ children }: { children: any }) => { const anchor = `${children.replace(/ /g, "-").toLowerCase()}`; return ( <h2 data-section id={anchor}> {children} </h2> ); } }; export default async function BlogPage({ params, }: { params: { slug: string }; }) { const post = getPost(params.slug); return ( <div className="max-h-fit"> <MDXRemote components={components} source={post.content} /> </div> ); } export async function generateStaticParams() { const postIds = await getAllPostIds(); return postIds; }
构建时的错误信息
./app/blog/[slug]/page.tsx:125:16 Type error: 'MDXRemote' cannot be used as a JSX component. Its return type 'Promise<ReactElement<any, string | JSXElementConstructor<any>>>' is not a valid JSX element. Type 'Promise<ReactElement<any, string | JSXElementConstructor<any>>>' is missing the following properties from type 'ReactElement<any, any>': type, props, key
复现方式
可自行复现该问题
next-mdx-remote版本
v5.0.0
解决方法
问题根源是next-mdx-remote v5的RSC版本MDXRemote是异步组件,返回值为Promise<ReactElement>,而Next.js App Router的Server Components中,不能直接在JSX里渲染异步组件,必须通过await处理。
方案一:直接在页面组件中await MDXRemote
修改page.tsx中的返回逻辑,将MDXRemote调用改为await形式:
export default async function BlogPage({ params, }: { params: { slug: string }; }) { const post = getPost(params.slug); // 直接await MDXRemote获取渲染结果 const mdxContent = await MDXRemote({ components, source: post.content }); return ( <div className="max-h-fit"> {mdxContent} </div> ); }
方案二:封装成独立的异步组件
创建单独的异步组件处理MDX渲染:
// app/components/PostContent.tsx import { MDXRemote } from "next-mdx-remote/rsc"; import type { MDXRemoteProps } from "next-mdx-remote/rsc"; export default async function PostContent(props: MDXRemoteProps) { return MDXRemote(props); }
然后在page.tsx中引入并使用这个组件:
import PostContent from '@/app/components/PostContent'; // ... export default async function BlogPage({ params, }: { params: { slug: string }; }) { const post = getPost(params.slug); return ( <div className="max-h-fit"> <PostContent components={components} source={post.content} /> </div> ); }
两种方案均能解决构建时的类型错误,它们都正确处理了异步组件的Promise返回值,符合Next.js Server Components的渲染规则。
内容的提问来源于stack exchange,提问作者robynico
相关产品推荐
相关产品推荐

