NextJS 14+AWS Amplify项目中react-pdf渲染S3 PDF报错求助
解决NextJS 14 + AWS Amplify环境下react-pdf
组件的canvas.node加载错误return (<Document />)
你遇到的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
相关产品推荐
相关产品推荐

