详解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单页面手势滑屏切换原理详解
Mar 21 Javascript
深入剖析javascript中的exec与match方法
May 18 Javascript
什么是JavaScript注入攻击?
Sep 14 Javascript
javascript 利用arguments实现可变长参数
Nov 21 Javascript
JavaScript中创建对象的7种模式详解
Feb 21 Javascript
微信小程序教程系列之设置标题栏和导航栏(7)
Jun 29 Javascript
Angular实现的日程表功能【可添加及隐藏显示内容】
Dec 27 Javascript
微信小程序switch组件使用详解
Jan 31 Javascript
详解处理bootstrap4不支持远程静态框问题
Jul 20 Javascript
微信小程序云开发实现数据添加、查询和分页
May 17 Javascript
javascript实现倒计时提示框
Mar 02 Javascript
浅谈Web Storage API的使用
Jun 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
为百度UE编辑器上传图片添加水印功能
2015/04/16 PHP
符合W3C网页标准的iframe标签的使用方法
2007/07/19 Javascript
FF IE兼容性的修改小结
2009/09/02 Javascript
javascript下对于事件、事件流、事件触发的顺序随便说说
2010/07/17 Javascript
nodejs入门详解(多篇文章结合)
2012/03/07 NodeJs
原生javascript获取元素样式
2014/12/31 Javascript
js与jquery实时监听输入框值的oninput与onpropertychange方法
2015/02/05 Javascript
jquery获取多个checkbox的值异步提交给php
2015/07/07 Javascript
深入浅析JSON.parse()、JSON.stringify()和eval()的作用详解
2016/04/03 Javascript
Bootstrap CSS组件之下拉菜单(dropdown)
2016/12/17 Javascript
完美实现js焦点轮播效果(二)(图片可滚动)
2017/03/07 Javascript
Windows下使用Nodejs运行js的方法
2017/09/02 NodeJs
详解node单线程实现高并发原理与node异步I/O
2017/09/21 Javascript
利用Node.js检测端口是否被占用的方法
2017/12/07 Javascript
node.js多个异步过程中判断执行是否完成的解决方案
2017/12/10 Javascript
jQuery动态添加元素无法触发绑定事件的解决方法分析
2018/01/02 jQuery
Vue图片浏览组件v-viewer用法分析【支持旋转、缩放、翻转等操作】
2019/11/04 Javascript
如何处理Python3.4 使用pymssql 乱码问题
2016/01/08 Python
Python实现重建二叉树的三种方法详解
2018/06/23 Python
Python实现的简单读写csv文件操作示例
2018/07/12 Python
Python拼接微信好友头像大图的实现方法
2018/08/01 Python
pycharm修改文件的默认打开方式的步骤
2019/07/29 Python
python pygame实现球球大作战
2019/11/25 Python
pycharm新建Vue项目的方法步骤(图文)
2020/03/04 Python
Python ArgumentParse的subparser用法说明
2020/04/20 Python
sklearn和keras的数据切分与交叉验证的实例详解
2020/06/19 Python
如何理解python对象
2020/06/21 Python
利用python下载scihub成文献为PDF操作
2020/07/09 Python
美国领先的家居装饰和礼品商店:Kirkland’s
2017/01/30 全球购物
医疗保健专业人士购物网站:Scrubs & Beyond
2017/02/08 全球购物
求职信的要素有哪些呢
2013/12/26 职场文书
市场营销专业毕业生求职信
2014/03/26 职场文书
煤矿安全演讲稿
2014/05/09 职场文书
贷款担保申请书
2014/05/20 职场文书
自动化专业毕业生求职信
2014/06/18 职场文书
自主招生自荐信格式范文
2015/03/25 职场文书