详解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弹出div并显示遮罩层
Feb 12 Javascript
js 动态修改css文件用到了cssRule
Aug 20 Javascript
javascript实现鼠标移到Image上方时显示文字效果的方法
Aug 07 Javascript
jQuery实现模仿微博下拉滚动条加载数据效果
Dec 25 Javascript
jQuery 选择同时包含两个class的元素的实现方法
Jun 01 Javascript
javascript 广告移动特效的实现代码
Jun 25 Javascript
JavaScript实现经典排序算法之插入排序
Dec 28 Javascript
javascript中BOM基础知识总结
Feb 14 Javascript
vue.js之vue-cli脚手架的搭建详解
May 05 Javascript
微信小程序实现传参数的几种方法示例
Jan 10 Javascript
JS实现为动态创建的元素添加事件操作示例
Mar 17 Javascript
js实现全选和全不选功能
Jul 28 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为什么选mysql作为数据库? Mysql 创建用户方法
2007/07/02 PHP
php相当简单的分页类
2008/10/02 PHP
destoon实现调用当前栏目分类及子分类和三级分类的方法
2014/08/21 PHP
php使用ftp远程上传文件类(完美解决主从文件同步问题的方法)
2016/09/23 PHP
一个高效的JavaScript压缩工具下载集合
2007/03/06 Javascript
use jscript List Installed Software
2007/06/11 Javascript
iframe 父窗口和子窗口相互的调用方法集锦
2010/12/15 Javascript
Jquery中显示隐藏的实现代码分析
2011/07/26 Javascript
用jquery方法操作radio使其默认选项是否
2013/09/10 Javascript
完美解决AJAX跨域问题
2013/11/01 Javascript
jquery实现图片滚动效果的简单实例
2013/11/23 Javascript
jquery prop的使用介绍及与attr的区别
2013/12/19 Javascript
jQuery动态添加、删除元素的方法
2014/01/09 Javascript
JQuery插件iScroll实现下拉刷新,滚动翻页特效
2014/06/22 Javascript
JavaScript中的函数(二)
2015/12/23 Javascript
JavaScript中创建对象的模式汇总
2016/04/19 Javascript
Angularjs自定义指令实现三级联动 选择地理位置
2017/02/13 Javascript
对于js垃圾回收机制的理解
2017/09/14 Javascript
Vue在页面右上角实现可悬浮/隐藏的系统菜单
2018/05/04 Javascript
解决vue项目打包后提示图片文件路径错误的问题
2018/07/04 Javascript
浅析JavaScript 函数防抖和节流
2020/07/13 Javascript
Vue自动构建发布脚本的方法示例
2020/07/24 Javascript
关于python之字典的嵌套,递归调用方法
2019/01/21 Python
python异常处理之try finally不报错的原因
2020/05/18 Python
使用分层画布来优化HTML5渲染的教程
2015/05/08 HTML / CSS
Melijoe英国官网:法国儿童时尚网站
2016/11/18 全球购物
曼联官方网上商店:Manchester United Direct
2017/07/28 全球购物
监理员的岗位职责
2013/11/13 职场文书
开工仪式主持词
2014/03/20 职场文书
学生干部培训方案
2014/06/12 职场文书
学校花圃的标语
2014/06/18 职场文书
教师查摆问题及整改措施
2014/10/11 职场文书
青岛导游词
2015/02/12 职场文书
工程项目合作意向书
2015/05/08 职场文书
如何书写读后感?(附范文)
2019/07/26 职场文书
pytorch 运行一段时间后出现GPU OOM的问题
2021/06/02 Python