vue-cli脚手架下.browserslist解决移动端代码兼容问题过程记录

876 阅读5分钟

一、问题背景和描述:

背景:在Android系统中进行Hybrid混合开发,脚手架是通过vue-cli2.0搭建。整体框架做了个性化调整,添加了eslint代码校验、prettier代码风格统一、引入postcss解决CSS前缀问题、Babel配置、browserslist配置等。框架搭建好之后,在各个主流浏览器和市面主流手机中测试都正常。然而。。。

问题:在某款2018年购买的手机和IE11中显示异常。 IE11报错如下:

image.png 同事打电话找到我,由于工位距离和忙于本职工作的原因,就通过电话沟通解决了。根据同事的描述,基本可以判断是代码向下兼容的问题导致的,另外,还提到工程中引入了vant,如果不使用Button按钮就正常。过程像极了中医里的“望闻问切”,当然还没到切的那一步。问题的原因知道了,就相当于解决了一半。解决方案立刻就确定到了Babel的转码上了。

二、问题解决方案一: 初步解决

在Babel中默认是不会对node_modules里的代码做转义的,解决方案:

1.babel的配置文件为babel.config.js。引用官方:

  • You want to compile node_modules?

  • babel.config.json is for you!

  • You have a configuration that only applies to a single part of your project?

  • .babelrc.json is for you!

2.babel.config.js配置中include:

{ 
    include: [path.resolve('src'), path.resolve('node_modules/xxx')], 
}

或者 在vue.config.js里配置transpileDependencies:

transpileDependencies:true // 默认情况下 `babel-loader` 会忽略所有 `node_modules` 中的文件。你可以启用本选项,以避免构建后的代码中出现未转译的第三方依赖。

问题似乎很so easy!把解决方案给同事说了下,同事回复“transpileDependencies”的方案尝试过,然而木有用!!!有点尴尬了!但我坚信方向是对的~~~

三、问题解决方案二: “切”

将源代码下载到本地,直接进行代码问题分析。通过浏览器里的DevTools工具的“切换设备方针”进行查看,并没有报异常。页面有个vconsole按钮引起我的好奇(很多年未开发h5页面了),点击后可以弹出调试窗口。好奇有会“害死猫”,但有时候会帮你解决问题!找到vconsole使用相关代码:

代码问题1:
// 问题代码
const VConsole = require("vconsole/dist/vconsole.min")
if(process.env.NODE_ENV !== "production"){
  new VConsole()
}

代码的目的是想在本地开发中使用vconsole这个插件。再仔细一想,为什么在production模式中也要加载呢?代码是否应该如下:

// 修改后的代码
if(process.env.NODE_ENV !== "production"){
  const VConsole = require("vconsole/dist/vconsole.min")
  new VConsole()
}

IE浏览器里跑一下,还是报错,但是报错内容变了!!!:

image.png

看来:“细节决定成败!” 对代码负责,代码也会对你好!窃喜~~

代码问题2:

在调试过程中发现,针对生产环境打的包和测试环境打的包“报错结果不同”。理论上应该是一样的,为什么会不同?好奇心驱使我一探究竟。 通过查看.env.testing配置文件发现:

NODE_ENV = testing

package.json里构建测试环境的命令是:

build_test: "vue-cli-service build --mode testing

然后翻看了vue-cli的官方文档:

当你运行 vue-cli-service build 命令时,无论你要部署到哪个环境,应该始终把 NODE_ENV 设置为 "production" 来获取可用于部署的应用程序。

修改了NODE_ENV的环境变量值,导致了代码问题1中测试环境打包仍然出现vconsole的问题。另外,NODE_ENV = production,vue-cli会默认开启一些生产构建功能,针对测试环境不应该修改变量值。还有,--mode 制定的值和NODE_ENV之间的关系也应该要梳理清楚,这一点在学习官方文档的时候也是有点模糊。这一次逻辑清晰了!好奇心,似乎又一次帮助了我!

四、解决方案三:还得死磕Babel

在主流浏览器中运行正常,部分浏览器执行异常。原因肯定是代码兼容性问题,而解决代码兼容性问题,首要考虑就必须是babel。代码向下兼容设计的解决方案有:babel的targets配置和.browserslist

1.Babel的targets配置解决方案:

Babel官方对targets的解释:

Describes the environments you support/target for your project.

Babel官方对于no targets的解释:

When no targets are specified: Babel will assume you are targeting the oldest browsers possible. For example, @babel/preset-env will transform all ES2015-ES2020 code to be ES5 compatible.

目前代码工程中属于no targets,因此,代码最终被转义为ES5。

2. .browserslist解决方案:

框架搭建过程中,容易被忽视的一个配置。查看代码工程中确实存在.browserslist的配置文件,但内容就是脚手架初始化的状态。 browserlist的官方解释是:

Shared browser compatibility config for popular JavaScript tools like Autoprefixer, Babel, ESLint, PostCSS, and Webpack

browserslist的配置是给Babel用的。我先解决下IE 11再说:

> 1%
last 2 versions
not dead
IE 11

重新构建运行,IE 11运行结果正常了,如图所示:

image.png

What!!! so easy!有点小确幸~~

注意:

代码向下兼容,需要babel-polyfill的支持,在代码工程发现main.js文件中已经引入了,在babel.config.js中也设置了 'useBuiltIns':'entry' // usage的用法更值得推荐。这里只能选entry,因为不确定是哪个语法导致的问题。Babel-polyfill的作用需要梳理清楚~~

3. 剩下任务就是确定出问题手机的浏览器内核了,查看android的webview的浏览器内核方法如下图所示:

image.png

同事告诉了具体的版本号之后,问题又来了,.browserslist中具体哪个关键字是用来兼容android手机内核的呢? 以前,对.browserslist真的不熟悉,趁此机会搞清楚~~

a. npx .browserslist命令可以查看当前代码工程支持的默认兼容的浏览器版本,具体可以自行尝试
b. 貌似对android的浏览器起作用的有and_开头的关键字和android,进一步核实后是android

最后:

> 1%
last 2 versions
not dead
IE 11
android >= 68

放到测试环境运行后,问题解决了~~~

五、总结:

  1. 良好的编程习惯,会产生高杠杆受益。
  2. 好奇心+行动力,往往会得到惊喜
  3. 解决bug真的会带来乐趣~~