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

Next.js部署Vercel遇Page导出类型错误,本地正常求解决

问题分析与解决方案

核心问题

你遇到的类型错误根源是Next.js App Router的page.tsx页面组件有固定的props类型规则:

  • 页面组件(Server Component)默认仅能接收params和searchParams作为顶层props,不能自定义info、exp这类非标准props。
  • 你的代码里定义了FormProps并让AdminAbout组件接收这两个props,违反了Next.js页面组件规范,导致Vercel部署时类型校验失败(本地可能因类型校验宽松未触发报错)。

另外,组件内部已经通过Prisma查询了完整数据,但传给子组件的却是外部传入的未定义props,逻辑上存在冗余。

修复步骤

  1. 移除自定义的FormProps,让页面组件遵循Next.js默认的页面props规则(如果不需要params/searchParams,可直接不接收)。
  2. 调整子组件传参逻辑:使用组件内部查询到的数据传给子组件,而非外部未定义的props。

修改后的代码示例

import prisma from '@/lib/prisma'; // 确保正确导入Prisma客户端

const AdminAbout = async () => { // 不再接收自定义props
  const infos = await prisma.info.findMany();
  const experiences = await prisma.experience.findMany();

  // 根据业务逻辑,取查询结果的第一条作为表单默认值(如果是新增表单可省略)
  const currentInfo = infos[0];
  const currentExp = experiences[0];

  return (
    <div>
      <div className="max-w-7xl px-10 mx-auto space-y-5 md:ml-[17rem] pt-20 min-h-screen">
        <div className=" flex items-center space-x-2 mb-2 shadow-md rounded-lg bg-primary p-4">
          <h1 className="font-bold pl-5 text-primary-foreground">
            Description Form
          </h1>
        </div>
        {/* 传入查询到的数据,而非外部props */}
        {currentInfo && <InfoForm info={currentInfo} />}
        <Table>
          <TableCaption>Description Form</TableCaption>
          <TableHeader>
            <TableRow>
              <TableHead className="w-[100px]">Resume</TableHead>
              <TableHead>Description</TableHead>
              <TableHead className="text-right">Action</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {infos.map((info) => (
              <TableRow key={info.id}>
                {info.public_id && (
                  <TableCell className="font-medium">
                    <CldImage
                      className="aspect-video"
                      width={100}
                      height={100}
                      src={info.public_id}
                      alt="pdf"
                    />
                  </TableCell>
                )}
                <TableCell className="font-medium">
                  {info.description.length > 50
                    ? `${info.description.substring(0, 50)}...`
                    : info.description}
                </TableCell>
                <TableCell className="font-medium">
                  <EditInfoForm info={info} />
                </TableCell>
                <TableCell className="font-medium">
                  <DeleteInfoButton id={info.id} />
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>

        {/* EXPERIENCE TABLE */}
        <div className=" flex items-center shadow-md rounded-lg bg-primary p-4 ">
          <h1 className="font-bold pl-5 text-primary-foreground">
            Experience Form
          </h1>
        </div>
        {/* 传入查询到的数据,而非外部props */}
        {currentExp && <ExperienceForm exp={currentExp} />}
        <Table>
          <TableCaption>Experience Form</TableCaption>
          <TableHeader>
            <TableRow>
              <TableHead className="w-[100px]">Job Title</TableHead>
              <TableHead>Company</TableHead>
              <TableHead>Year</TableHead>
              <TableHead className="text-right">Action</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {experiences.map((experience) => (
              <TableRow key={experience.id}>
                <TableCell className="font-medium">
                  {experience.jobtitle}
                </TableCell>
                <TableCell>{experience.company}</TableCell>
                <TableCell>
                  {experience.year.toLocaleString("default", { month: "long" })} {" "}
                  {experience.year.getFullYear()}
                </TableCell>
                <TableCell className="text-right">
                  <EditExperienceForm exp={experience} />
                </TableCell>
                <TableCell className="text-right">
                  <DeleteExperienceButton id={experience.id} />
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </div>
    </div>
  );
}

export default AdminAbout

额外说明

  • 如果InfoForm/ExperienceForm是用于新增数据,而非编辑现有数据,可直接渲染表单,无需传入info/exp props,提交时再写入数据库。
  • 确保Vercel部署时已配置好数据库环境变量,Prisma客户端能正常连接数据库。

内容的提问来源于stack exchange,提问作者Akinola

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 03:05:57