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

Next.js 14.2中使用react-pdf遇CommonJS模块导入错误求助

Next.js 中 react-pdf 的 CommonJS 模块兼容错误解决

问题描述

在 Next.js 项目中使用 @react-pdf/renderer 时触发模块加载错误,提示需将对 react-pdf.js 的 require 调用替换为动态 import()。错误栈显示问题出现在服务器端渲染阶段,涉及 CreateAppointmentPdf.tsx 组件对 @react-pdf/renderer 的直接导入。

错误信息

⨯ Instead change the require of react-pdf.js in C:\Users\TCET
 ADMIN\Desktop\next\.next\server\app\(client)\page.js to a dynamic
 import() which is available in all CommonJS modules.
     at @react-pdf/renderer (C:\Users\TCET ADMIN\Desktop\next\.next\server\app\(client)\page.js:110:18)
     at __webpack_require__ (C:\Users\TCET ADMIN\Desktop\next\.next\server\webpack-runtime.js:33:43)
     at eval (_components/CreateAppointmentPdf.tsx:7:77)
     at (ssr)/./app/(client)/_components/CreateAppointmentPdf.tsx (C:\Users\TCET
 ADMIN\Desktop\next\.next\server\app\(client)\page.js:419:1)
     at __webpack_require__ (C:\Users\TCET ADMIN\Desktop\next\.next\server\webpack-runtime.js:33:43)
     at eval (_components/downloadbutton.tsx:10:79)
     at (ssr)/./app/(client)/_components/downloadbutton.tsx (C:\Users\TCET
 ADMIN\Desktop\next\.next\server\app\(client)\page.js:463:1)
     at __webpack_require__ (C:\Users\TCET ADMIN\Desktop\next\.next\server\webpack-runtime.js:33:43)
     at eval (_components/create-schedule-dialog.tsx:38:74)
     at (ssr)/./app/(client)/_components/create-schedule-dialog.tsx (C:\Users\TCET
 ADMIN\Desktop\next\.next\server\app\(client)\page.js:452:1)
     at __webpack_require__ (C:\Users\TCET ADMIN\Desktop\next\.next\server\webpack-runtime.js:33:43)
     at eval (_components/left-calendar.tsx:10:81)
     at (ssr)/./app/(client)/_components/left-calendar.tsx (C:\Users\TCET
 ADMIN\Desktop\next\.next\server\app\(client)\page.js:496:1)
     at __webpack_require__ (C:\Users\TCET ADMIN\Desktop\next\.next\server\webpack-runtime.js:33:43)
     at eval (page.tsx:9:83)
     at (ssr)/./app/(client)/page.tsx (C:\Users\TCET ADMIN\Desktop\next\.next\server\app\(client)\page.js:540:1)
     at Object.__webpack_require__ [as require] (C:\Users\TCET ADMIN\Desktop\next\.next\server\webpack-runtime.js:33:43)
     at JSON.parse (<anonymous>) digest: "2904845551"

原组件代码

MainComponent.tsx

<DownloadButton
    disabledButton={!confirmAgreement}
    onClick={form.handleSubmit(onSubmit)}
    isPending={isPending}
    form={form} />
</DialogClose>

DownloadButton.tsx

'use client'
import React from 'react'
import CreateDocumentPDF from './CreateAppointmentPdf'
import dynamic from 'next/dynamic'

const DownloadButton = ({ form, onClick, disabledButton, isPending }: any) => {
    const [isClient, setIsClient] = useState(false)

    const PDFDownloadLink = dynamic(
        () => import("@react-pdf/renderer").then((mod) => mod.PDFDownloadLink),
        {
          ssr: false,
          loading: () => <p>Loading...</p>,
        }
      );

    useEffect(() => {
        setIsClient(true)
    }, [])

    return (
        <PDFDownloadLink
            fileName='Appointment'
            document={
                <CreateDocumentPDF form={form} />
            }
        >
            <Button>
                    
            </Button>
        </PDFDownloadLink>
    )
}

export default DownloadButton

CreateAppointmentPdf.tsx

import { Document, Font, Page, Text, View } from '@react-pdf/renderer'

const CreateDocumentPDF = ({
    form
}: any) => {
    return (
        <Document>

        </Document>
    )
}

export default CreateDocumentPDF

解决方法

问题根源是服务器端渲染时加载了仅兼容浏览器环境的 @react-pdf/renderer 模块。需要确保所有涉及 react-pdf 的组件都仅在客户端加载:

1. 修改 DownloadButton.tsx

将 CreateDocumentPDF 也改为动态导入,并添加客户端渲染判断:

'use client'
import React, { useState, useEffect } from 'react'
import dynamic from 'next/dynamic'
import Button from 'your-button-component-path' // 替换为实际的Button组件路径

// 动态导入PDF文档组件,关闭SSR
const CreateDocumentPDF = dynamic(() => import('./CreateAppointmentPdf'), {
  ssr: false,
  loading: () => <p>加载中...</p>,
})

// 动态导入PDF下载链接组件,关闭SSR
const PDFDownloadLink = dynamic(
  () => import("@react-pdf/renderer").then((mod) => mod.PDFDownloadLink),
  {
    ssr: false,
    loading: () => <p>加载中...</p>,
  }
);

const DownloadButton = ({ form, onClick, disabledButton, isPending }: any) => {
  const [isClient, setIsClient] = useState(false)

  useEffect(() => {
    setIsClient(true)
  }, [])

  // 服务器端渲染时显示占位按钮
  if (!isClient) {
    return <Button disabled={disabledButton || isPending}>生成PDF</Button>
  }

  return (
    <PDFDownloadLink
        fileName='Appointment'
        document={<CreateDocumentPDF form={form} />}
    >
        {({ loading }) => (
          <Button 
            disabled={disabledButton || isPending || loading}
            onClick={onClick}
          >
            {loading ? '生成中...' : '下载PDF'}
          </Button>
        )}
    </PDFDownloadLink>
  )
}

export default DownloadButton

2. 修改 CreateAppointmentPdf.tsx

添加 'use client' 指令,明确标记为客户端组件:

'use client'
import { Document, Page, Text, View } from '@react-pdf/renderer'

const CreateDocumentPDF = ({ form }: any) => {
    return (
        <Document>
            <Page size="A4">
                <View style={{ padding: 20 }}>
                    <Text style={{ fontSize: 18, fontWeight: 'bold' }}>预约详情</Text>
                    {/* 根据form数据渲染内容,示例: */}
                    <Text>姓名: {form?.getValues('name')}</Text>
                    <Text>日期: {form?.getValues('date')}</Text>
                </View>
            </Page>
        </Document>
    )
}

export default CreateDocumentPDF

原理说明

Next.js 的 SSR 会在服务器端解析所有同步导入的模块,而 @react-pdf/renderer 依赖浏览器环境的 API(如 canvas),且其模块结构在 CommonJS 下需要动态导入才能避免加载错误。通过将所有 react-pdf 相关组件设为动态导入并关闭 SSR,确保这些代码仅在客户端执行,彻底解决模块兼容问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 20:05:54