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

NextJS 14+AWS Amplify项目中react-pdf渲染S3 PDF报错求助

解决NextJS 14 + AWS Amplify环境下react-pdf
return (<Document />)
组件的canvas.node加载错误

你遇到的canvas.node模块解析错误,本质是react-pdf依赖的Node端canvas二进制模块,在NextJS的Webpack配置中没有对应的loader处理,尤其是NextJS 14默认的App Router环境下,需要针对性调整配置或使用react-pdf的浏览器适配版本。以下是可行的解决方案:

方案一:改用react-pdf浏览器专用入口

react-pdf提供了跳过Node端依赖的浏览器版本,直接修改导入路径即可:

// 替换原导入语句
import { Document, Page } from 'react-pdf/dist/esm/entry.webpack';

配合你已成功获取的Blob URL使用:

'use client'; // 必须添加,标记为客户端组件

import { useState, useEffect } from 'react';
import { Document, Page } from 'react-pdf/dist/esm/entry.webpack';

async function getPdfBlobUrl(id) {
  const { body } = await downloadData({key: id}).result;
  const responseBlob = new Blob([await body.blob()], {type: "application/pdf"});
  return URL.createObjectURL(responseBlob);
}

export default function PdfViewer({ id }) {
  const [blobUrl, setBlobUrl] = useState(null);

  useEffect(() => {
    const fetchPdf = async () => {
      const url = await getPdfBlobUrl(id);
      setBlobUrl(url);
    };
    fetchPdf();
    
    return () => {
      if (blobUrl) URL.revokeObjectURL(blobUrl); // 清理内存,避免泄漏
    };
  }, [id]);

  if (!blobUrl) return <div>加载中...</div>;

  return (
    <Document file={blobUrl}>
      <Page pageNumber={1} />
    </Document>
  );
}

方案二:调整NextJS Webpack配置

如果需要保留react-pdf的默认导入方式,可修改next.config.js配置,让Webpack正确处理二进制模块:

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config, { isServer }) => {
    // 服务端构建时排除canvas模块,避免二进制文件解析错误
    if (isServer) {
      config.externals.push('canvas');
    }
    // 客户端添加file-loader处理.node二进制文件
    config.module.rules.push({
      test: /\.node$/,
      loader: 'file-loader',
      options: {
        publicPath: '/_next/static/files/',
        outputPath: 'static/files/',
        name: '[name].[hash].[ext]',
      },
    });
    return config;
  },
};

module.exports = nextConfig;

安装依赖的loader:

npm install file-loader --save-dev

重启开发服务器后,即可用你之前尝试的签名URL或Uint8Array方式传递给<Document />:

'use client';

import { useState, useEffect } from 'react';
import { Document, Page } from '@react-pdf/renderer';

// 使用签名URL的示例
async function getSignedUrl(id) {
  const url = (await getUrl({ key: id })).url.toString();
  return url;
}

export default function PdfViewer({ id }) {
  const [pdfUrl, setPdfUrl] = useState(null);

  useEffect(() => {
    getSignedUrl(id).then(setPdfUrl);
  }, [id]);

  if (!pdfUrl) return <div>加载中...</div>;

  return (
    <Document file={pdfUrl}>
      <Page pageNumber={1} />
    </Document>
  );
}

关键注意事项

  • 所有使用react-pdf的组件必须添加'use client'指令,确保在浏览器环境运行(NextJS 14 App Router默认是服务端组件)。
  • 用Blob URL时记得在组件卸载时调用URL.revokeObjectURL()释放内存,避免内存泄漏。
  • 若使用签名URL,需确保AWS Amplify存储的CORS配置允许当前域名访问,否则react-pdf会因跨域无法加载PDF。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:16:30