vue 项目中 babel 的最佳实践
前言
https://juejin.cn/post/7208510421676982329
上文的最后,我们提到了 babel 配置的最佳实践
没有最佳,只有最适合
那么业内常用的脚手架是怎么配置的呢?
我们以一次线上白屏问题的排查为切入点一步步探讨。
问题描述
我们的项目是以 vue-cli3 脚手架生成的 vue2.6.11 的 SPA 项目
某华为 P10 手机打开页面忽然白屏,由于是 app 内嵌页,且是线上环境,无法抓包
我们找到同款测试机,通过 google 抓包工具发现 JS 代码在报错
定位到代码行,是 crypto.js/enc-base64url.js 在报错
问题排查
当看到低版本手机上,三方库报错时,第一反应是 babel 是不是配置的不对。
当打开报错代码,定位到上述代码第一行,一时间竟没有发现哪里有错,朴实无华,平平无奇的代码怎么浏览器引擎就无法识别呢?
后来看到 urlSafe = true 这段给函数参数默认值的写法。
想起来这是 ES6 新增的语法,详情可以看下面的教程
https://es6.ruanyifeng.com/#docs/function
理想状况应该是这样
那么问题来了。
为什么这段代码没哟被转译成 ES3,ES5 的语法呢?
为什么我业务代码中的函数参数默认值的写法就没有出现任何问题呢?
vue-cli 脚手架是对 babel 怎么配置的呢?
带着这三个问题,我打开了项目中的 babel.config.js
vue/app
项目中的 babel.config.js 配置如下
预设的插件集合是 @vue/app
plugins 中是对两个组件库的自动引入
@vue/app 是什么?
@vue/app 是 @vue/babel-preset-app 的缩写
一个默认的 Vue CLI 项目会使用 @vue/babel-preset-app
通过查看 node_modules 源码,我们在 readme 中发现
这个插件内部引用的是经典插件库 babel/preset-env
它通过 @babel/preset-env 和 browserslist 配置来决定项目需要的 polyfill。
browserslist
配置源从以下位置读取
package.json 文件中的 browserslist 字段
.browserslistrc 配置文件
browserslist.config.js 配置文件
运行环境变量 BROWSERSLIST
默认如下
useBuiltIns
这个属性的配置的默认值是 usage
它会根据源代码中出现的语言特性自动检测需要的 polyfill,确保了最终包里 polyfill 数量的最小化
意思是仅仅会为我们引入目标浏览器中不支持并且我们在代码中使用到的内容,会剔除没有使用到的 polyfill 内容。
但是并不会处理 我们的 npm 依赖包中的 不被浏览器识别的 ES6+ 的语法
这就导致了 文章开头提到的问题, 三方库函数是 crypto.js/enc-base64url.js 中 ES6 语法在报错,直接导致页面白屏幕。
解决方案
思路一
修改 useBuiltIns 为 entry
在入口文件引入 polyfill
优点:一劳永逸,所有的 JS 新语法都会进行转译,再也不用担心浏览器兼容问题
缺点:无论这个语法有没有被使用,相应的转译包都被引入了,导致代码体积变大
思路二
transpileDependencies: true
这是 vue-cli 暴露给开发者的一个属性,默认值为 false
大意就是,如果配置为 true,会对 node_modules 在的包进行转译,但是会因为遍历了所有的 node_modules 会导致构建速度变慢
思路三
transpileDependencies: ['crypto.js']
哪个有问题配置哪个
兼顾兼容性和构建速度
我们依赖的很多包,其实已经是使用 babel 编译之后的包了,所以不需要全量编译,如果能提前预知哪些包需要编译,我们提前配置进去就好。
当然,这是一种最理想的状态,随着项目的迭代,我们也很难知道哪些包需要转译,哪些包不需要转译。
采纳方案
经过讨论,我们最终使用了思路二,对所有包进行遍历
transpileDependencies: true
对使用的 JS 语法进行转译
修复之后依旧白屏?
配置 transpileDependencies: true 之后
我们在测试环境构建打包后,用有问题的机器再次打开,依然白屏
难道是配置项没生效?
我们在浏览器打开 console 平台,发现是 vConsole 在报错
vConsole.log
这个工具库相信前端开发们都不陌生,测试环境调试抓包利器,每想到在这个包竟然翻了车。
我们代码中引 vconsole.log 的方式是
但是报错的地方是 vConsole 的三方依赖包
经过调研,我们发现 transpileDependencies: true 只会广度遍历编译三方依赖
对于依赖的依赖则不会处理
这就导致了上述的问题
对于此类问题,我们可以通过正则进行匹配
但是依赖引用依赖,无穷无尽,配置的复杂度大大增加
现在想来还不如一开始就全量入口引入,简单粗暴,无后顾之忧
解决方案
本着遇到问题解决问题的思路
我们最后采用了在 html 入口引入 vConsole.min.js 文件的方式,来规避了这个问题
这个文件是使用 babel 转译过的,不存在兼容性问题。
详情可参考项目
https://github.com/Yinzhuo19970516/vue-template/tree/main/public
方案总结
最后我们项目中的 babel 配置如下
使用 vue-cli 中对默认配置,加 transpileDependencies: true
当然没有最佳的,只有最合适的
如果项目对兼容性要求较高,多人维护,我更建议你配置,useBuiltIns 为 entry
牺牲项目体积,保证兼容性。
最后这是我们一次线上问题排查的过程中,记录的 babel 在实际项目中的具体实践,如果想看原理可以看我上一篇文章
十问 babel,用最简单的话说清楚 babel
https://juejin.cn/post/7208510421676982329
如果您都读到这里了,请给个免费的赞吧!
版权声明: 本文为 InfoQ 作者【虎妞先生】的原创文章。
原文链接:【http://xie.infoq.cn/article/8a6b44e2b8eb21211fb04af90】。文章转载请联系作者。
评论