(回忆录)升级项目 pdfjs 版本记录

446 阅读5分钟

img

(最近世界杯加疫情,只能窝在家写写文章,记录记录生活...)

最近对项目的 pdf.js 进行了版本升级。

事情的经过是这样的,有一个历史遗留的线上问题,当用户进入系统打开 pdf 文件进行预览的时候发现部分内容缺失。这个问题大概是今年 5 月份提出的,之前一直挂在我们老大头上,自从我入职了过后,兜兜转转 jira 就转到了我这里 ...

一个半年前的 bug,比我入职还早几个月,感动...

我翻看了 jira 之前的备注信息,里面有业务的质疑、有后端同事的甩锅记录,但最有用的是前前端同事留下的一句话:pdf 文件有多层数,前端 pdf.js 工具在处理 pdf 文件时,未能解析出上高层的数据,然后解决这个问题的前端同事没多久就离职了...

image-20221127162224234

我一开始也百度、Google 和 stackoverflow 三件套,最后还去看了源码,奈何这个项目确实有点重 (zhòng),老大又追着我赶紧改好...

兔子表情很无奈- 做表情- 在线装逼、照片装饰、表情包制作

于是抱着试一试的态度,我本地创建了一个项目,然后安装了最新版本的 pdfjs-dist 包(pdf.js的预构建版本),跑了一下,发现最新版本是已经修复了图层缺失问题的,于是本着最快修复的原则,我打算给项目的 pdfjs-dist 进行升级。

我执行 npm i pdfjs-dist@latest 安装了最新的依赖,重新启动项目,以为可以万事大吉,但一个经典的错误出现在我眼前:

image-20221127163333641

最可恶的是这个错误是在编译期间,且后面没有说是什么 token,就只报了个 token 解析错误!

自认为"身经百战"的我当然知道是语法错误,但是不给任何提示,也没有文件定位信息打出来,真的是头大。这个问题是 pdfjs-dist 升级之后出现的,因此我快速锁定了 pdfjs-dist,希望能从它身上找到突破口。但我去翻看了 github 源码发现,它们根本就没有打包 source map 出来!

无奈的表情图片郁闷苦笑很无奈的搞笑表情图片_搞笑头像_美头网

于是我尝试了拉下项目来,仔细分析并修改其配置文件使其多个地方支持 source map 打包,然后安装各种依赖以及它需要的 java 环境进行打包 ... 最后发现打包生成的 source map 文件依然有一定问题(应该是中途文件还被执行了其它转换,但并没有这个过程的 source map 输出)。

宣告 source map 这条路失败!

于是只有第二条路,debug 编译过程。

调试编译过程

简单对调试环境进行了准备之后,开始了调试之旅...

在这个过程中,经过一个又一个的断点,我终于定位到了报错的地方:

image-20221127164856668

这里看得出来是文件的第 22 行和 36522 列,很明显,这是一个压缩之后的文件。

image-20221127165432731

而且由于文件内容太长,调试工具里面无法正常显示出来。另外由于是被 webpack 转换过后的文件,所以这个定位也无法应用于 pdfjs-dist 中的源文件进行定位。

但好在目前正处于调试工具中,我尝试将内容拷贝出来放到 vscode 中去然后通过 vscode 的 文件:行号:列号 进行定位,但是由于太长,vscode 也无法正常显示出来,出于性能考虑,多余的内容在显示的时候直接被截断。

就在一筹莫展的时候,我突然意识到完全没必要大费周章的去拷贝粘贴,既然还在调试工具内,那何不通过代码的方式来截断。于是我尝试截断文件内容:

image-20221127170032839

发现最开始是 |=,应该要往前一点截断才行:

image-20221127170146937

罪魁祸首是 ||= ,这个操作符当时确实是第一次见到,不过很快我了解到它其实和 +=*= 这样的操作符一样,被称作逻辑赋值操作符( logical assignment operators),不过真正令我没想到的是这个操作符其实目前还处于草案阶段,而 pdfjs-dist 的打包结果中竟然没有对它进行转换,直接就原样输出了出来(个人觉得是有点不太负责任的做法)!毕竟大部分项目打包都是忽略了 node_modules 中的依赖包。

定位到问题就好办了,项目是通过 Vue Cli 创建的 vue2 老项目,其 @vue/cli-plugin-babel 版本较低,从而引入的 babel 版本也不高,导致 preset 无法智能判断是否解析该语法特性,因此需要手动添加对应的依赖。在 babel 中,这个插件的名字叫做 @babel/plugin-proposal-logical-assignment-operators,使用方式参考官方文档即可。

加入了 babel 插件,还需要放开对 pdfjs-dist 依赖的打包,使这些新的语法特性被转换成 ES5 版本的写法。由于项目是 Vue Cli 创建的,需要修改 vue.config.js 中的配置,加入了一个配置项 transpileDependencies: [/pdfjs-dist/],使的 vue 项目能够正常打包 pdfjs-dist 中的内容。

改好之后重新启动项目,错误消失,完美解决!

总结

按道理作为如此通用的第三方库, pdfjs-dist 不应该直接在其打包好的 dist 目录中出现当前时间段还处于草案的语法。不过那是人家的自由。

通过对 pdf.js 官方文档的反复浏览,在本次升级过程中还发现项目中对 pdfjs worker 的使用是有问题的,因此也做了相关的优化,调整了项目中对 pdfjs-dist 使用的方式。这里就不去细说了。

最后...

哎呀,解决了一个 "年龄" 比我还大的 bug,自然是满足的!

image-20221127173656843