当前位置: 首页 > news >正文

react-pdf(pdfjs-dist)如何兼容老浏览器(chrome 49)

之前都是使用react-pdf来渲染pdf文件,这次有个需求是要兼容xp环境,xp上chrome最高支持到49,虽然说iframe或者embed都可以实现预览pdf,但为了后续的定制化需求,还是需要使用js库来渲染。

chrome 49测试环境

能用的测试环境是关键,这里使用chrome 49,是为了兼容xp。

我使用vmware安装了windows10虚拟机,再安装chrome 49来模拟。

pdf.js

一开始我觉得既然react-pdf不能用,那我们就找它封装的原始库pdf.js。

首先参考利用pdf.js在线展示PDF文档 - 老码识途呀 - 博客园,找到能用的pdf.js版本(pdfjs-2.5.207-es5-dist),重点是要支持es5。

使用umi搭建测试Demo

3.1. umi4

第一次我用的umi4搭建的,主要代码如下:

//package.json
"dependencies": {"pdfjs-dist": "2.5.207","umi": "^4.4.11"
},
//index.tsx
import { useEffect, useRef } from "react";
import * as pdfjs from 'pdfjs-dist';
//重点是要用es5
import pdfjsWorker from 'pdfjs-dist/es5/build/pdf.worker.entry.js';pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;const pdfUrl = 'http://xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx.pdf';const PdfTest = () => {const pdfContainer = useRef();useEffect(() => {// Loading a document.var loadingTask = pdfjs.getDocument(pdfUrl);loadingTask.promise.then(function (pdfDocument) {// Request a first pagereturn pdfDocument.getPage(1).then(function (pdfPage) {// Display page on the existing canvas with 100% scale.var viewport = pdfPage.getViewport({ scale: 1.0 });var canvas = document.getElementById("theCanvas");canvas.width = viewport.width;canvas.height = viewport.height;var ctx = canvas.getContext("2d");var renderTask = pdfPage.render({canvasContext: ctx,viewport: viewport,});return renderTask.promise;});}).catch(function (reason) {console.error("Error: " + reason);});}, [])return (<canvasid="theCanvas"ref={pdfContainer}/>);
}export default PdfTest;

另外umi4打包时还支持添加兼容性配置:

//.umirc.ts
export default defineConfig({targets: {chrome: 49,},legacy: {},
});

实测是可以访问的。

3.2. umi2 + react-pdf

由于项目比较老,还在用umi2,不支持legacy配置,光使用umi4是不够的。

另外既然pdf.js可以,理论上react-pdf也是支持的,只要找到对应的版本号。我找到的是react-pdf@5.2.0。

//reactPdf.js
import React, { useState } from 'react';
import { Document, Page, pdfjs } from 'react-pdf';
import pdfjsWorker from 'pdfjs-dist/es5/build/pdf.worker.entry.js';pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;const pdfUrl = 'http://xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx.pdf';function ReactPdf() {const [numPages, setNumPages] = useState(null);const [pageNumber, setPageNumber] = useState(1);function onDocumentLoadSuccess({ numPages }) {setNumPages(numPages);}return (<div><Document file={pdfUrl} onLoadSuccess={onDocumentLoadSuccess}><Page pageNumber={pageNumber} /></Document><p>Page {pageNumber} of {numPages}</p></div>);
}export default ReactPdf;
//config.js
export default {targets: { //配置浏览器最低版本,比如兼容ie11chrome: 49, ie: 9},
}

然而实测报错:

错误排查

这里有一个很重要的点,那就是如何找到出错的代码

umi2是支持不压缩代码的:

所以我修改了打包命令:

//package.json
"build": "cross-env COMPRESS=none umi build",

重新发布后可以看到出错的地方:

定位到源码:

这里可以明显看到出错的原因是不支持async,也就是es6的功能。

报错的这段代码其实出自pdf.js:

//pdf.js@2.5.207/src/display_utils.js
async fetch({ name }) {if (!this.baseUrl) {throw new Error('The CMap "baseUrl" parameter must be specified, ensure that ' +'the "cMapUrl" and "cMapPacked" API parameters are provided.');}if (!name) {throw new Error("CMap name must be specified.");}

所以我们的目标是打包时把pdf.js的源码转换为es5

我试了很多方案,比如修改react-pdf源码,把所有pdfjs-dist的引入改成es5:

//react-pdf@5.2.0/src/Document.jsx// import * as pdfjs from 'pdfjs-dist';
import * as pdfjs from 'pdfjs-dist/es5/build/pdf';

改完以后重新打包并替换node_modules下的文件夹:

实测仍然报错:

另外在本地开发时定位到:

打断点自动跳转到源码:

说明就算我把react-pdf中的所有引入都改成了es5,pdfjs-dist还是会有一些工具类会使用es6的方法。

实际上我们需要的是把pdfjs-dist转换为es5

我试了很多,比如配置@babel/preset-env、@babel/plugin-transform-runtime等,都没用。

我认为umi默认不会对node_modules下的文件做转换,因此需要把pdfjs-dist加入到umi自身的babel转换中:

//config.js
extraBabelIncludes: [/[\\/]pdfjs-dist[\\/]/,  // 匹配 node_modules/pdfjs-dist]

此时打包后,可以看到async已经被转换了:

在chrome 49上也能正常访问了:

至此我们完美兼容了老版本浏览器,在此记录下,主要是排查过程。

http://www.xdnf.cn/news/949717.html

相关文章:

  • 大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
  • 篇章二 论坛系统——系统设计
  • C/C++ 面试复习笔记(5)
  • nuclio的配置文件yaml和docker compose的yaml的区别
  • 依赖注入(Dependency Injection)
  • 关于YOLOV5—Mosaic数据增强
  • 电源滤波器:不起眼却如何保障电子设备电源?
  • 1091 Acute Stroke (30)
  • 2025年全国I卷数学压轴题解答
  • 大模型链路调试平台之LangSmith实战指南
  • Web 架构之 API 安全防护:防刷、防爬、防泄漏
  • SpringBoot整合SSM
  • React中子传父组件通信操作指南
  • 使用VBA嵌套字典快速转换BOM表格
  • 鸢尾花分类(KNN)
  • 【AI News | 20250609】每日AI进展
  • 测试微信模版消息推送
  • 开源:FTP同步工具
  • 【粤语克隆】粤语声音,一秒克隆:如何用AI为岭南文化按下快进键
  • composer init
  • LeetCode - 647. 回文子串
  • 具身智能之人形机器人核心零部件介绍
  • 教程:PyCharm 中搭建多级隔离的 Poetry 环境(从 Anaconda 到项目专属.venv)
  • 重启Eureka集群中的节点,对已经注册的服务有什么影响
  • 深入理解JavaScript设计模式之单例模式
  • AirPosture | 通过 AirPods 矫正坐姿
  • 安科瑞户储ADL200N-CT:即插即用破解家庭光伏安装困局
  • HBase学习:通俗易懂的实例解析
  • K8S认证|CKS题库+答案| 10. Trivy 扫描镜像安全漏洞
  • Java中HashMap底层原理深度解析:从数据结构到红黑树优化