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

Next.js+TypeScript集成react-pdf-viewer遇canvas.node编译错误求助

问题:Next.js+TypeScript集成react-pdf-viewer编译报错及功能实现需求

编译错误信息

Failed to compile
./node_modules/canvas/build/Release/canvas.node
Module parse failed: Unexpected character '�' (1:2)
You may need an appropriate loader to handle this file type.
Currently, no loaders are configured to process this file.
(Source code omitted for this binary file)
This error occurred during the build process and can only be dismissed by fixing the error.

已执行步骤

  • 进入项目目录并打开终端
  • 执行npm install react-pdf-viewer命令下载包
  • 按照文档步骤将包引入项目
  • 编译项目时出现上述错误

项目情况

  • 使用Next.js和TypeScript
  • 其他包运行正常,仅react-pdf-viewer出现问题
  • 不确定是否需手动调整Webpack配置

ReaderPdf组件代码

import React from 'react';
// Import Worker
// Import the main Viewer component
import {Viewer, Worker} from "@react-pdf-viewer/core";
// Import the styles
import "@react-pdf-viewer/core/lib/styles/index.css";
// default layout plugin
// @ts-ignore
import {defaultLayoutPlugin} from "@react-pdf-viewer/default-layout";
// Import styles of default layout plugin
import "@react-pdf-viewer/default-layout/lib/styles/index.css";


const ReaderPdf = () => {
    const defaultLayoutPluginInstance = defaultLayoutPlugin();
    const pdfFile = "/public/upload/pdf/198727.pdf"
    return (
        <>
            {pdfFile && (
                <Worker workerUrl="https://unpkg.com/pdfjs-dist@3.4.120/build/pdf.worker.min.js">
                    <Viewer
                        fileUrl={pdfFile}
                        plugins={[defaultLayoutPluginInstance]}
                    ></Viewer>
                </Worker>
            )}
        </>
    )
};

export default ReaderPdf;

需求说明

目标是借助react-pdf-viewer实现PDF页面展示及文本提取,但不清楚具体实现步骤,希望获得示例代码或分步指导。


解决方案与实现指导

一、编译错误问题根源及解决方法

问题根源

canvas.node是二进制文件,Next.js默认Webpack配置未配置处理这类文件的loader,导致编译时无法解析。该文件来自react-pdf-viewer依赖的canvas包,主要用于服务端渲染或底层PDF渲染,但浏览器环境下无需加载此二进制文件。

可行解决方案

方案1:配置Webpack处理二进制文件(推荐)

在项目根目录创建或修改next.config.js,添加以下配置:

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config) => {
    // 用raw-loader处理.node二进制文件
    config.module.rules.push({
      test: /\.node$/,
      use: 'raw-loader',
    });
    return config;
  },
}

module.exports = nextConfig;

然后安装依赖:

npm install raw-loader --save-dev

方案2:浏览器环境排除canvas包

若无需服务端渲染PDF,可让Webpack在浏览器环境中不引入canvas:

const nextConfig = {
  webpack: (config, { isServer }) => {
    if (!isServer) {
      config.resolve.fallback = {
        ...config.resolve.fallback,
        canvas: false,
      };
    }
    return config;
  },
}

module.exports = nextConfig;

二、PDF页面展示优化

组件中fileUrl路径错误,Next.js中public目录下的文件无需前缀/public,修改为:

const pdfFile = "/upload/pdf/198727.pdf"

三、文本提取功能实现步骤及示例代码

react-pdf-viewer未直接提供文本提取API,可借助其依赖的pdfjs-dist实现,步骤如下:

1. 安装依赖

npm install pdfjs-dist

2. 组件完整实现(含文本提取)

import React, { useState, useEffect } from 'react';
import { Viewer, Worker } from "@react-pdf-viewer/core";
import "@react-pdf-viewer/core/lib/styles/index.css";
import { defaultLayoutPlugin } from "@react-pdf-viewer/default-layout";
import "@react-pdf-viewer/default-layout/lib/styles/index.css";
import * as pdfjsLib from 'pdfjs-dist';

// 配置pdfjs的worker路径
pdfjsLib.GlobalWorkerOptions.workerSrc = "https://unpkg.com/pdfjs-dist@3.4.120/build/pdf.worker.min.js";

const ReaderPdf = () => {
    const defaultLayoutPluginInstance = defaultLayoutPlugin();
    const pdfFile = "/upload/pdf/198727.pdf";
    const [extractedText, setExtractedText] = useState<string>('');
    const [isExtracting, setIsExtracting] = useState<boolean>(false);

    // 提取PDF文本逻辑
    const extractPdfText = async () => {
        setIsExtracting(true);
        try {
            const pdf = await pdfjsLib.getDocument(pdfFile).promise;
            let fullText = '';
            // 遍历所有页面提取文本
            for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
                const page = await pdf.getPage(pageNum);
                const textContent = await page.getTextContent();
                const pageText = textContent.items.map((item: any) => item.str).join(' ');
                fullText += `第${pageNum}页:\n${pageText}\n\n`;
            }
            setExtractedText(fullText);
        } catch (err) {
            console.error('文本提取失败:', err);
        } finally {
            setIsExtracting(false);
        }
    };

    // 组件加载时自动提取文本,也可绑定按钮点击触发
    useEffect(() => {
        extractPdfText();
    }, []);

    return (
        <>
            {pdfFile && (
                <Worker workerUrl="https://unpkg.com/pdfjs-dist@3.4.120/build/pdf.worker.min.js">
                    <Viewer
                        fileUrl={pdfFile}
                        plugins={[defaultLayoutPluginInstance]}
                    ></Viewer>
                </Worker>
            )}
            {/* 文本提取展示区域 */}
            <div style={{ marginTop: '24px', padding: '16px', border: '1px solid #e5e7eb', borderRadius: '8px' }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
                    <h3>提取的PDF文本</h3>
                    <button 
                        onClick={extractPdfText} 
                        disabled={isExtracting}
                        style={{ padding: '6px 12px', cursor: 'pointer' }}
                    >
                        {isExtracting ? '提取中...' : '重新提取'}
                    </button>
                </div>
                <pre style={{ whiteSpace: 'pre-wrap', maxHeight: '400px', overflowY: 'auto', marginTop: '0' }}>
                    {extractedText || '暂无提取内容'}
                </pre>
            </div>
        </>
    )
};

export default ReaderPdf;

功能说明

  • 文本提取通过pdfjs-dist的getDocument和getPage方法实现,遍历每一页拼接文本内容;
  • 添加了加载状态提示,避免重复触发提取操作;
  • 可根据需求调整文本提取的触发时机(如绑定按钮点击而非组件加载时自动执行)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 08:45:57