feat(pdf-viewer): add postinstall script for pdfjs worker and simplify pdf rendering

This commit is contained in:
2025-11-17 11:20:20 +08:00
parent 3118fa4f1b
commit 3ab77361a1
4 changed files with 68 additions and 29 deletions

View File

@@ -8,7 +8,8 @@
"dev:ragflow": "pnpm -r --filter ragflow_web run dev",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
"preview": "vite preview",
"postinstall": "node scripts/copy-pdfjs-worker.mjs"
},
"dependencies": {
"@emotion/react": "^11.14.0",

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,15 @@
import fs from 'node:fs';
import path from 'node:path';
const src = path.resolve('node_modules/pdfjs-dist/build/pdf.worker.min.mjs');
const destDir = path.resolve('public/pdfjs-dist');
const dest = path.join(destDir, 'pdf.worker.min.mjs');
try {
fs.mkdirSync(destDir, { recursive: true });
fs.copyFileSync(src, dest);
console.log(`[pdfjs-dist] Worker copied to: ${dest}`);
} catch (err) {
console.error('[pdfjs-dist] Failed to copy worker:', err);
process.exitCode = 1;
}

View File

@@ -1,15 +1,13 @@
import React, { useState, useEffect, useRef } from 'react';
// 使用 pdf.js 在左侧容器中渲染 PDF 页面,支持自由滑动与页码定位
import * as pdfjsLib from 'pdfjs-dist';
// 使用 Vite 的资源 URL 解析,将 pdf.js 的模块 worker 转成可访问 URL
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import pdfjsWorkerUrl from 'pdfjs-dist/build/pdf.worker.min.mjs?url';
// 采用模块 Worker避免经典 worker 的 MIME/路径问题
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
const PDFJS_WORKER_MJS = '/pdfjs-dist/pdf.worker.min.mjs';
// @ts-ignore
pdfjsLib.GlobalWorkerOptions.workerPort = new Worker(pdfjsWorkerUrl, { type: 'module' });
pdfjsLib.GlobalWorkerOptions.workerSrc = PDFJS_WORKER_MJS;
// @ts-ignore
pdfjsLib.GlobalWorkerOptions.disableWorker = true;
import { useSearchParams } from "react-router-dom";
import {
Box,
@@ -161,17 +159,11 @@ function ChunkParsedResult() {
}
try {
const arrayBuffer = await documentFile.arrayBuffer();
const container = pdfContainerRef.current;
if (!container) return;
const renderWithDoc = async (disableWorker: boolean) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const task = pdfjsLib.getDocument({ data: arrayBuffer, disableWorker });
const pdfDoc = await task.promise;
const container = pdfContainerRef.current;
if (!container) return;
const renderPages = async (pdfDoc: any) => {
container.innerHTML = '';
// 根据容器宽度自适应缩放
const containerRect = container.getBoundingClientRect();
const containerWidth = Math.max(1, Math.floor(containerRect.width || container.clientWidth || 800));
@@ -215,23 +207,26 @@ function ChunkParsedResult() {
}
};
// 尝试使用 Worker优先模块其次经典
try {
// 优先使用 Worker 渲染
await renderWithDoc(false);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const task = pdfjsLib.getDocument({ data: arrayBuffer });
const pdfDoc = await task.promise;
await renderPages(pdfDoc);
setPdfRendered(true);
} catch (err1) {
console.error('PDF.js Worker 渲染失败,降级为主线程渲染。错误: ', err1);
try {
// Worker 不可用时,禁用 Worker 在主线程渲染
await renderWithDoc(true);
setPdfRendered(true);
} catch (err2) {
console.error('PDF.js 主线程渲染失败: ', err2);
setPdfRendered(false);
}
console.error('第一次渲染失败,尝试主线程渲染:', err1);
// 失败则回退主线程
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const fallbackTask = pdfjsLib.getDocument({ data: arrayBuffer, disableWorker: true });
const pdfDoc2 = await fallbackTask.promise;
await renderPages(pdfDoc2);
setPdfRendered(true);
}
} catch (err) {
console.error('读取 PDF 文件数据失败: ', err);
console.error('渲染 PDF 过程中发生错误: ', err);
setPdfRendered(false);
}
};