(最近世界杯加疫情,只能窝在家写写文章,记录记录生活...)
最近对项目的 pdf.js
进行了版本升级。
事情的经过是这样的,有一个历史遗留的线上问题,当用户进入系统打开 pdf 文件进行预览的时候发现部分内容缺失。这个问题大概是今年 5 月份提出的,之前一直挂在我们老大头上,自从我入职了过后,兜兜转转 jira
就转到了我这里 ...
一个半年前的 bug
,比我入职还早几个月,感动...
我翻看了 jira
之前的备注信息,里面有业务的质疑、有后端同事的甩锅记录,但最有用的是前前端同事留下的一句话:pdf 文件有多层数,前端 pdf.js 工具在处理 pdf 文件时,未能解析出上高层的数据
,然后解决这个问题的前端同事没多久就离职了...
我一开始也百度、Google 和 stackoverflow 三件套,最后还去看了源码,奈何这个项目确实有点重 (zhòng),老大又追着我赶紧改好...
于是抱着试一试的态度,我本地创建了一个项目,然后安装了最新版本的 pdfjs-dist
包(pdf.js
的预构建版本),跑了一下,发现最新版本是已经修复了图层缺失问题的,于是本着最快修复的原则,我打算给项目的 pdfjs-dist
进行升级。
我执行 npm i pdfjs-dist@latest
安装了最新的依赖,重新启动项目,以为可以万事大吉,但一个经典的错误出现在我眼前:
最可恶的是这个错误是在编译期间,且后面没有说是什么 token,就只报了个 token 解析错误!
自认为"身经百战"的我当然知道是语法错误,但是不给任何提示,也没有文件定位信息打出来,真的是头大。这个问题是 pdfjs-dist
升级之后出现的,因此我快速锁定了 pdfjs-dist
,希望能从它身上找到突破口。但我去翻看了 github
源码发现,它们根本就没有打包 source map
出来!
于是我尝试了拉下项目来,仔细分析并修改其配置文件使其多个地方支持 source map
打包,然后安装各种依赖以及它需要的 java
环境进行打包 ... 最后发现打包生成的 source map 文件依然有一定问题(应该是中途文件还被执行了其它转换,但并没有这个过程的 source map
输出)。
宣告 source map
这条路失败!
于是只有第二条路,debug
编译过程。
调试编译过程
简单对调试环境进行了准备之后,开始了调试之旅...
在这个过程中,经过一个又一个的断点,我终于定位到了报错的地方:
这里看得出来是文件的第 22
行和 36522
列,很明显,这是一个压缩之后的文件。
而且由于文件内容太长,调试工具里面无法正常显示出来。另外由于是被 webpack 转换过后的文件,所以这个定位也无法应用于 pdfjs-dist
中的源文件进行定位。
但好在目前正处于调试工具中,我尝试将内容拷贝出来放到 vscode 中去然后通过 vscode 的 文件:行号:列号
进行定位,但是由于太长,vscode 也无法正常显示出来,出于性能考虑,多余的内容在显示的时候直接被截断。
就在一筹莫展的时候,我突然意识到完全没必要大费周章的去拷贝粘贴,既然还在调试工具内,那何不通过代码的方式来截断。于是我尝试截断文件内容:
发现最开始是 |=
,应该要往前一点截断才行:
罪魁祸首是 ||=
,这个操作符当时确实是第一次见到,不过很快我了解到它其实和 +=
、*=
这样的操作符一样,被称作逻辑赋值操作符( 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,自然是满足的!