记 webpack babel 打包后 ie 不兼容问题处理

3,119 阅读6分钟

最近在做项目过程中,发现项目打包后,ie 不兼容,存在 js 报错,定位报错代码后,发现存在 es6 语法,通过一波原始的代码搜索后,发现是使用的开源库里存在 es6 语法,没有被解析到。

这篇文章主要是记录:

  1. 问题出在哪?
  2. 怎么解决?
  3. 如何保证后续不出现类似问题?(毕竟随着业务的增长,不可能每次发布都要ie把所有业务都走一遍)

问题出在哪

为什么都使用 webpack babel-loader ,而且 browserlist 配置正确,代码里还有 es6 代码没被解析到。

通过搜索 ie 报错代码,定位到没有被解析的代码都是依赖库的代码,查阅了相关文档,代码编译解析是相对耗时的操作,vue-cli 为了优化打包时间,默认情况下设置 babel-loader 忽略 node_modules 下的所有文件。所以依赖库没有被解析到,只要自己添加例外即可。

怎么解决

找到哪些依赖库存在 es6 代码,在 babel-loader 中 include 进来即可。

不排除 node_modules?除非你的项目很小,外部依赖的库特别少,才可以考虑放开,否则 webpack 编译过程会特别慢。

如何保证后续不出现类似问题

那么如何保证后续不出现类似问题呢?

  1. 由于技术选型、新功能,需要新增一个依赖库;
  2. 依赖库 feat bugfix update,引入 es6 代码;

相对于1,我们可以在技术选型时,就检查库代码是否包含 es6 代码,从而决定是否需要编译;但是2,有时候小版本的非破坏性更新,我们并不会注意到,可能发布后用户反馈才知道 ie 已经挂了;

另外,在现今,前端模块化拆分越来越细,一个库的功能都会尽量保持单一独立,经常会依赖其他优秀的开源底层库,这样的层层依赖,加大了排查是否存在 es6 代码的难度。

而且靠肉眼去检查 es6 代码,难免会有眼花的情况,况且谁愿意去做这样机械化的事情呢...


分割线:下面才是本文最想表述的内容

es-check

工具越来越发达的今天,检查这种事情必须交给靠谱的工具

es-checkwhy-es-check),它使用 acorn(babel 内部也是使用该库) 解析指定 ECMAScript 版本代码,如果解析失败,则说明可能存在 该版本+ 的代码(当然也可能是代码语法错误),然后抛出错误的代码信息。

有了工具后,我们可以指定解析 es5 版本代码,来排查是否有 es5+ 代码,有的话再定位具体是哪个库:

  1. 扫描依赖库的代码

优点:可以很清楚知道是哪个依赖库;

缺点:这个指定难度比较大,扫描整个 node_modules,那还不如不用 exclude;选型时就扫描,那必须指定版本,库的bugfix更新就很难响应到。

  1. 扫描最后项目打包出来的代码

优点:保持跟生产代码一致;代码集中,好扫描,如果整合到发布流程中,发布过程中有依赖包更新出问题就能立马查知了;

缺点:打包的代码经过压缩、common chunk 后,依赖包的代码基本集中在 chunk-vendor 中,很难定位到源文件。

尝试了下 es-check 扫描打包后的文件,的确扫描到了错误,但是错误信息却很难定位到是哪个库

es-check result
如图,16行 820387列,怎么找到是那个代码,怎么定位到源文件

明显不能满足我的项目场景,我想要的东西是这样的:

  1. 配合自动化发布流程,在发布编译打包后扫描打包代码,判断是否有不符合版本的代码存在
  2. 如果存在不符合版本的代码,需要输出所有不符合代码的
  • 源文件:知道源文件,才能知道哪个依赖包,做 include 处理
  • 位置:找到问题代码
  • 源码:判断是否是使用了高版本代码,还是语法错误
  1. 根据扫描结果,可以轻松添加例外,避免上线秋后算账

1. 首先,从 es-check 下手,实现满足要求的扫描库

需要做两件事情:

  1. 格式化错误输出,得到想要的结果 因为要找到源文件,只能通过 sourcemap 文件溯源,所以找到了 source-map 库来根据打包后代码的报错位置去查找源代码。
  2. 不仅提供 CLI 模式,还要提供 API,方便库直接使用 将扫描的核心逻辑抽离成底层 API,供 CLI 和 外部库 使用。

因此,就有了 es-check-format 这个库

es-check-format
定位到了strict-uri-encode这个包存在箭头函数,这个包不是项目主动依赖的;找到了源文件和代码,这样就可以轻松的 include 了

注意

  • 项目中使用 webpack 打包时,主要解析不到的文件是外部依赖包(参考why-es-check),而一般外部依赖包会被统一打包到 common-chunk 中,由于 acorn 只要解析失败就会退出,所以不管是 es-check-format 还是 es-check 都没法遍历到一个文件所有的问题,暂时只能查到一个解决后再继续查。(如果哪个同学有好的办法,烦请留言)

2. 集成到自动化发布中

之前的文章 -- 前端自动化发布实战总结中,我们遵循开发、发布流程,使用 node 实现一套自动化发布机制,现在只要在流程中 代码编译打包 后添加 es-check,如果扫描到不合法代码,就中断发布,输出错误日志,开发者清楚问题后添加例外,可以本地编译打包,CLI 方式自行扫描,再发布即可。

总结

到这里,终于又可以放心地发布了。在这个过程中

  • 更深入地了解了 babel
  • 因为原需求是判断是否包含 es5+ 代码,所以一开始想的是是不是要通过 babel 解析的 AST 遍历扫描出是否包含 es5+ 关键字,可是这个关键字会随着 ECMAScript 新规范不能变化,成本挺高;所以感谢 es-check 提供的思路,acorn 通过指定版本解析,解析出错就可能存在高版本
  • 进一步完善了发布流程,保障线上的稳定