详解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 相关文章推荐
JS 有名函数表达式全面解析
Mar 19 Javascript
Jquery的Tabs内容轮换效果实现代码,几行搞定
Feb 12 Javascript
jquery操作checkbox实现全选和取消全选
May 02 Javascript
avascript中的自执行匿名函数应用示例
Sep 15 Javascript
innerHTML属性,outerHTML属性,textContent属性,innerText属性区别详解
Mar 13 Javascript
一步步教大家编写酷炫的导航栏js+css实现
Mar 14 Javascript
JS中dom0级事件和dom2级事件的区别介绍
May 05 Javascript
jQuery 选择符详细介绍及整理
Dec 02 Javascript
angular.js+node.js实现下载图片处理详解
Mar 31 Javascript
javascript实现二叉树遍历的代码
Jun 08 Javascript
javascript删除数组元素的七个方法示例
Sep 09 Javascript
vue-cli3中配置alias和打包加hash值操作
Sep 04 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的栏目导航程序
2006/10/09 PHP
php adodb连接mssql解决乱码问题
2009/06/12 PHP
Fatal error: Call to undefined function curl_init()解决方法
2010/04/09 PHP
php设计模式之单例模式使用示例
2014/01/20 PHP
php判断输入是否是纯数字,英文,汉字的方法
2015/03/05 PHP
PHP获取本周所有日期或者最近七天所有日期的方法
2018/06/20 PHP
PHP MVC框架中类的自动加载机制实例分析
2019/09/18 PHP
Laravel的Auth验证Token验证使用自定义Redis的例子
2019/09/30 PHP
PHP实现计算器小功能
2020/08/28 PHP
Tab页界面 用jQuery及Ajax技术实现(php后台)
2011/10/12 Javascript
JavaScript监听和禁用浏览器回车事件实例
2015/01/31 Javascript
纯javascript实现四方向文本无缝滚动效果
2015/06/16 Javascript
纯JS代码实现一键分享功能
2016/04/20 Javascript
让你一句话理解闭包(简单易懂)
2016/06/03 Javascript
浅谈toLowerCase和toLocaleLowerCase的区别
2016/08/15 Javascript
react.js 翻页插件实例代码
2017/01/19 Javascript
angularjs指令之绑定策略(@、=、&amp;)
2017/04/13 Javascript
angularjs $http实现form表单提交示例
2017/06/09 Javascript
原生js中ajax访问的实例详解
2017/09/19 Javascript
详解vue-cil和webpack中本地静态图片的路径问题解决方案
2017/09/27 Javascript
jQuery实现html双向绑定功能示例
2017/10/09 jQuery
详解JS模块导入导出
2017/12/20 Javascript
实战node静态文件服务器的示例代码
2018/03/08 Javascript
微信小程序传值以及获取值方法的详解
2019/04/29 Javascript
微信小程序利用云函数获取手机号码
2019/12/17 Javascript
解决vue单页面应用进入页面加载所有 js 的问题
2020/08/12 Javascript
python类装饰器用法实例
2015/06/04 Python
详解duck typing鸭子类型程序设计与Python的实现示例
2016/06/03 Python
python爬虫获取京东手机图片的图文教程
2017/12/29 Python
VSCode下好用的Python插件及配置
2018/04/06 Python
Python 中字符串拼接的多种方法
2018/07/30 Python
python实现在函数中修改变量值的方法
2019/07/16 Python
pytorch 准备、训练和测试自己的图片数据的方法
2020/01/10 Python
鞋类设计与工艺专业销售求职信
2013/11/01 职场文书
五四青年节优秀演讲稿范文
2014/05/28 职场文书
pytorch 如何把图像数据集进行划分成train,test和val
2021/05/31 Python