详解Vue Cli浏览器兼容性实践


Posted in Javascript onJune 08, 2020

浏览器市场占有率

在处理浏览器兼容性问题之前,我们先来看一下现在的浏览器市场份额是怎样的,?下面是来自statCounter的数据,基本上覆盖了全世界浏览器市场份额的统计,而且前端er经常使用的caniuse所拉取的浏览器数据就是来自statCounter。

世界范围

详解Vue Cli浏览器兼容性实践

天朝范围

详解Vue Cli浏览器兼容性实践

Plus移动端

详解Vue Cli浏览器兼容性实践

分析

从统计数据可以看出,对于国内的PC端浏览器,QQ浏览器以及Sogou的占比还是挺高的,所以在做兼容性处理的时候也需要多考虑这两款浏览器。不过QQ浏览器和Sogou都是封装了Chrome的内核,而它们的更新通常也就是随着Chrome的版本更新而更新,但是这两款浏览器通常不会和Chrome的最新版本同步,而是会有一定的滞后性,所以通常我们兼容的时候要去考虑它们所使用的Chrome内核版本来处理。

Vue CLI3

简述

随着尤大最新力作-Vue CLI3的发布,团队也将项目的脚手架升级为最新的CLI3了,CLI3带来了很多新的特性,比如支持webpack4、支持可视化化地配置项目、封装了很多官方的插件降低了上手的成本等。其中还有对浏览器兼容性的支持-结合了社区最新的工具以及现代模式。而CLI 3.0的浏览器兼容性处理,主要分为三个部分。browserlist、polyfill以及modern mode(现在模式)。

Broserslist

指定项目的目标浏览器范围,这个值会被@babel/preset-env和Autoprefixer等工具用来确定需要转译的JS特性以及需要添加前缀的CSS特性。

{
 "browserslist": [
  "last 1 version", //表示最新一个版本
 ]
}

Browserslist本质是对一系列浏览器的queries,查询浏览器的版本, 它会从caniuse中拉取数据来查询!它的好处是给予了开发者一个标准的地方存放项目支持的浏览器版本,他们可以在配置中找到这个支持版本。

下面是用法解释

详解Vue Cli浏览器兼容性实践

Transpile

下面要要介绍的是Vue CLI3所用到的Babel预设- @Babel/preset-env,它是在CLI3中指导Babel进行转译的一个工具,说起Babel就不得不提一下转译,和其他语言中的编译不同,转译是类似如下图所示的一个过程:

详解Vue Cli浏览器兼容性实践

总的来说,静态语言的编译比如Java是将源代码编译为字节码,这两种通常是处于不同抽象层次的语言,而Transpile的两端本质上是相同层次上的抽象,它一般是从一种支持更高级特性的比如ES2017的实现,转为一种语言特性较少的比如ES5的实现。在解决浏览器兼容性时,很大程度上是需要依赖Babel转译来解决低版本浏览器不支持某些新特性的情况。

CLI3如何使用browserslist以及babel进行转译

babel是一个编译JS文件的和工具。用于编译新JS新特性到支持的目标浏览器。babel/preset-env从browserlistrc文件中加载目标浏览器:

"babel": {
 "presets": [
  [
   "@babel/preset-env"
  ]
 ]
}

然后babel会把新标准中的JS语法特性编译到当前目标浏览器支持的代码:

const array = [1, 2, 3];
const [first, second] = array;

output:

const array = [1, 2, 3];
const first = array[0],
  second = array[1];

此处的const特性,因为该目标浏览器支持了,所以不需要降级处理。

** Babel的转译可以简单地用以下三个阶段概括: **

  • parser: 通过babel-parser,基于babel-AST-format将JS代码转译成AST。
  • transform: 所有的插件/presets进一步做语法等自定义转译,仍然为AST
  • generator: 最后通过generator生成转译后的字符串。

不同的特性,结合Browserslist以及@Babel/preset-env会根据当前的目标浏览器支持的特性的情况来转译,不支持的特性再去降级处理。Babel本身是个复杂的话题,后续有余力结合编译原理再去深挖一下。

Polyfills

Polyfill通常是在特性检测后,来决定是否需要引入的一段JS代码,它是用基于目标浏览器支持的代码编写的。

if(browserSupportAllFeatures()) {
 main();
} else {
 loadScript('polyfills.js', main);
}

原理默认情况下,它会把useBuiltIns: 'usage' 传递给 babel/preset-env,这样它会根据源代码中出现的语言特性自动检测需要的polyfill。 确保了最终包里的polyfill数量最小化。然而,这也意味着如果其中一个依赖需要特殊的polyfill,默认情况下babel无法检测出来。

// 源代码
var a = new Promise();
// 输出
import 'core-js/modules/es6.promise';
var a = new Promise();

依赖需要Polyfills如果有依赖需要polyfill,你有几种选择:(来自babel-preset-app)

如果该依赖基于一个目标环境不支持的ES版本撰写,将其添加到vue.config.js中的 traspileDependcies选项。这会为该依赖同时开启语法转换和根据使用情况检测polyfill。默认情况下,babel-loader会忽略所有node_modules中的文件。如果想要通过Babel显式转译一个依赖,可以在这选项中列出:

trasnpileDependencies: [lodash,...]

如果该依赖交付了ES5代码并显式列出了需要的polyfill: 你可以使用@vue/babel-preset-app 的polyfills选项 预包含所需要的polyfill。( 注册es6.promise将被默认包含,因为现在的库依赖Promise非常普遍。)

// babel.config.js
module.exports = {
 presets: [
  ['@vue/app', {
   polyfills: [
    'es6.promise',
    'es6.symbol'
   ],
   useBuiltIns: 'entry'
  }]
 ]
}

推荐这种方式添加polyfills而不是在源代码中直接导入它们,因为如果这里列出的polyfill在browserflist的目标不需要,则它会被自动排除。 3. 如果该依赖交付了ES5 代码,但使用了ES6+ 特性且没有显式列出需要的polyfill,请使用useBuiltIns: 'entry' 然后在入口文件添加 import '@babel/polyfill'。 这会根据browserlist 目标导入所有polyfill,这就不需要担心依赖的polyfill问题了, 缺点:但是包含了一些没有用到的polyfill所以最终的包可能会增加。(这也没办法,因为依赖没有显式列出需要的polyfill)

// 源代码
import '@babel/polyfill'
// 输出
import 'core-js/modules/es7.string.pad-start';
import 'core-js/modules/es7.string.pad-end';

Modern mode(现代模式)

什么是现代模式?现代模式是Vue CLI3提出的,为了解决支持更老的浏览器而为它们交付笨重的代码的问题,使用官方所给的脚手架搭建好项目后,可以像下面这样运行:

vue-cli-service build --modern

CLI3内置的Service服务会调用webpack构建编译生成两种类型的包,一种是现代版的包,它不会引入额外的polyfill。 一种是旧版的包,面向不支持的旧版浏览器,它会根据browserslist以及babel-preset-env的配置引入额外的polyfill。

  • 现代的包会通过 <script type="module"> 在被支持的浏览器中加载;它们还会使用 <link rel ="modulepreload"> 进行预加载。
  • 旧版的包通过 <script nomodule> 加载,会被支持ESM的浏览器忽略。

输出对比未使用现代模式:

详解Vue Cli浏览器兼容性实践

Vue CLI 3 现代模式:

详解Vue Cli浏览器兼容性实践

使用了modern的方式,会在目录下生成了两种包:

详解Vue Cli浏览器兼容性实践

解释

<script src="/xx/sxx.js" nomodule></script>

script标签中声明了nomodule特性的,会告诉支持ES2015 Module的浏览器,不要去执行这个脚本。这种标签通常就是在老旧浏览器中使用的,引用的是带有legacy标识的脚本。

<script type="module" src="/xxx/sss/a.js"></script>

当script标签中声明了type特性的值为module时,浏览器就会把里面的代码视作一整个JS模块,脚本内容的处理不受charset和defer属性的影响,代码的行为可能会与不指定为module时表现得不同。 (以前type的值一般是JS MIME值,在符合HTML5的浏览器,表示脚本为JS。但现在H5规范要求开发者省略这个属性而不提供冗余的MIME类型。)

小结

Vue CLI 3提供了一整套的解决方案,里面提供了社区以及Vue官方的工具,包含Browserslist、Babel、@Babel/preset-env以及现代模式来共同处理浏览器兼容性这个大坑。CLI3构建出的工程会利用Browserslist去进行浏览器查询(包括类型和版本),然后结合预设对Babel进行配置共同来针对目标环境对源代码进行转译或引入Polyfills来解决兼容性问题。Moreover,现代模式同样会根据这些设定以及目标环境去构建出适合运行在支持项目所有新特性的浏览器以及不支持特性的浏览器的两种包。最后,预告一下,下一篇文章会结合Modernizr和CLI3来进行实践 ---- 《浏览器兼容性实践-Mondernizr篇》

Reference

Stat Counter

浏览器对H5、CSS3特性支持

目标浏览器配置表

browserlist

Vue CLI3

Babel

Babel AST format

到此这篇关于详解Vue Cli浏览器兼容性实践的文章就介绍到这了,更多相关Vue Cli浏览器兼容性内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
javascript 清除输入框中的数据
Apr 13 Javascript
JavaScript Array Flatten 与递归使用介绍
Oct 30 Javascript
JS跨域总结
Aug 30 Javascript
遍历DOM对象内的元素属性示例代码
Feb 08 Javascript
jQuery学习笔记之toArray()
Jun 09 Javascript
jQuery中:animated选择器用法实例
Dec 29 Javascript
iscroll.js的上拉下拉刷新时无法回弹的解决方法
Feb 18 Javascript
jQuery validate+artdialog+jquery form实现弹出表单思路详解
Apr 18 Javascript
神级程序员JavaScript300行代码搞定汉字转拼音
May 20 Javascript
npm 下载指定版本的组件方法
May 17 Javascript
Vue实现双向绑定的原理以及响应式数据的方法
Jul 02 Javascript
从零搭一个自用的前端脚手架的方法步骤
Sep 23 Javascript
解决微信授权成功后点击按返回键出现空白页和报错的问题
Jun 08 #Javascript
微信h5静默和非静默授权获取用户openId的方法和步骤
Jun 08 #Javascript
基于javascript处理二进制图片流过程详解
Jun 08 #Javascript
vue-router的hooks用法详解
Jun 08 #Javascript
Vue自定义render统一项目组弹框功能
Jun 07 #Javascript
用云开发Cloudbase实现小程序多图片内容安全监测的代码详解
Jun 07 #Javascript
Electron整合React使用搭建开发环境的步骤详解
Jun 07 #Javascript
You might like
用php实现让页面只能被百度gogole蜘蛛访问的方法
2009/12/29 PHP
小文件php+SQLite存储方案
2010/09/04 PHP
浅谈PHP检查数组中是否存在某个值 in_array 函数
2016/06/13 PHP
js中字符替换函数String.replace()使用技巧
2011/08/14 Javascript
jQuery实现简洁的导航菜单效果
2015/11/23 Javascript
ECMAScript6 新特性范例大全
2017/03/24 Javascript
node.js 用socket实现聊天的示例代码
2017/10/17 Javascript
解决使用vue.js路由后失效的问题
2018/03/17 Javascript
解决LayUI加上form.render()下拉框和单选以及复选框不出来的问题
2019/09/27 Javascript
如何在Vue中使localStorage具有响应式(思想实验)
2020/07/14 Javascript
原生js滑动轮播封装
2020/07/31 Javascript
解决vue prop传值default属性如何使用,为何不生效的问题
2020/09/21 Javascript
Vue项目利用axios请求接口下载excel
2020/11/17 Vue.js
js调用网络摄像头的方法
2020/12/05 Javascript
python多线程扫描端口示例
2014/01/16 Python
Python实现程序的单一实例用法分析
2015/06/03 Python
Python实现调度算法代码详解
2017/12/01 Python
Python代码实现KNN算法
2017/12/20 Python
python破解zip加密文件的方法
2018/05/31 Python
python: 自动安装缺失库文件的方法
2018/10/22 Python
在Python中获取两数相除的商和余数方法
2018/11/10 Python
朴素贝叶斯Python实例及解析
2018/11/19 Python
python实现微信防撤回神器
2019/04/29 Python
scrapy-redis分布式爬虫的搭建过程(理论篇)
2020/09/29 Python
css3新增颜色表示方式分享
2014/04/15 HTML / CSS
美国最流行的男士时尚网站:Touch of Modern
2018/02/05 全球购物
Lululemon加拿大官网:加拿大知名体育服装零售商
2019/04/12 全球购物
九月份红领巾广播稿
2014/01/22 职场文书
搞笑创意广告语
2014/03/17 职场文书
绿色小区申报材料
2014/08/22 职场文书
2014年大学生预备党员思想汇报1000字
2014/09/13 职场文书
银行柜员与客户起冲突检讨书
2014/09/27 职场文书
2015年市场营销工作总结
2015/07/23 职场文书
python函数指定默认值的实例讲解
2021/03/29 Python
如何设计高效合理的MySQL查询语句
2021/05/26 MySQL
python简单验证码识别的实现过程
2021/06/20 Python