You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 11:57:55