来自 软件资讯 2019-10-04 13:46 的文章
当前位置: 威尼斯国际官方网站 > 软件资讯 > 正文

大前端的活动化学工业厂

奥门威尼斯网址 1
奥门威尼斯网址 2

我们为什么会使用babel?因为我们会使用很多es的新语法。但浏览器的支持却还不完善。所以我们只能使用babel编译器来帮助我们。
如果我们还使用了webpack的话,我们会在webpack中增加babel-loader

一. 关于babel

babel是ES6+语法的编译器,官方网址:www.babeljs.io,用于将旧版本浏览器无法识别的语法和特性转换成为ES5语法,使代码能够适用更多环境。

最初的babel使用起来是非常方便的,几乎仅使用少量的配置就可以使用,但随着工具的快速升级和代码架构的转变,babel已经裂变成非常多的部分,每个部分各司其职,这样做的好处是可以缩小生产环境的正式包的代码体积(因为可以按需引用)而加重了开发环境(开发阶段需要引入更多碎片化的插件),但劣势就是将其使用门槛提得非常高,对软件架构不熟悉的开发者难以使用。

比如babel官方网站在webpack配置的章节,提及了babe-loader,babel-corebabel-preset-env三个插件,而当开发者在webpack中实际进行配置时除了上述三个基本插件外,又会遇到babel-polyfill,babel-runtime,babel-plugin-transform-runtime等等一系列插件,或许通过查看插件说明能够理解插件的功能,但开发者却很难判断自己是否该使用这个功能或者什么时候使用。

      {
        test: /.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test')]
      },

二. 基本需求推演

我们从工具设计的角度,通过问题推演的方式来看看babel的变化。

ES6标准推出时,浏览器还不能很好地支持,但ES6的许多特性和语法又很诱人,所以大家想了个办法,那就是用ES6编写代码,然后出包的时候拿个工具转换一下,变成能被更多浏览器识别的ES5语法不就行了么,于是,Babel基本模型就出现了:

奥门威尼斯网址 3

babel奥门威尼斯网址 ,的功能被定义为编译工具,那么理论上来说它就可以使用编译器的通用代码框架,通过ASTparser --> traverse --> stringify 的步骤实现编译功能,在关键的traverse环节,是需要一个规则集合的,可是转码所参考的ES6的标准并不是一个定案的标准,其中每一个特性都需要经过从stage0stage4这样5个阶段才能正式定稿,只有stage-2草案(draft)阶段以上的特性才会在未来被支持,而处于这个阶段以下的标准是有可能被废的,如果一味地全部转换,不仅会降低工具效率,也会为代码未来的维护造成隐患。

那如果我们有一个工厂函数,接受数字0-4作为参数,然后返回所有经历了stage-x的规则集(是ES6规则的子集)作为规则集合,那么就可以在最终生成生产环境的代码时减小代码体积,假如在项目中通过babel_get_es6_by_stage(2)这样一个函数返回了规则集,那么正式代码中就不需要stage-0stage-1的实现代码了。基于以上的考虑,我们对Babel工具进行第一次功能剥离:

奥门威尼斯网址 4

推演继续,在对规则集进行了一次体积缩减后,我们得到了一个相对精简的规则集,它包含了诸多新的语法和方法,如果直接使用那的确很爽,毕竟引入了一个工具后就可以毫无后顾之忧地使用新特性,但对于生产环境的代码包来说,这种做法造成的代码冗余确是非常难以接受的。

用大家都熟悉的bootstrap为例,bootstrap.min.css的体积大约为120k,可你会发现很多人引入它完全是出于心里惯性,而在最后仅仅使用了非常基础的btn相关的样式类,或者仅仅为了使用col-md-4这种响应式布局的样式,所有使用到的样式可能只占了20k-30k的空间,但是却不得不为项目引进一个120k大的库,当然并不是所有的项目都会在意20k和120k之间的差别的。

那么我们就需要一个能够按更小粒度组合的方法babel_get_es6_by_rules([rule , ...]),让使用者可以选择自己所使用到的语法和方法,从而达到缩小引用库体积的目的:

奥门威尼斯网址 5

推演继续进行。处理过兼容性问题的开发者都知道,浏览器是存在版本区分的,许多特性在不同浏览器中的实现和表现都不一样,对于ES6也是这样,较高版本的浏览器对于ES6中的一些特性是已经逐步实现支持了的,如果我们的目标用户所使用的运行环境对某些ES6特性已经提供了原生支持,或者目标用户的运行环境根本就是由开发者直接封装好的,那么原先“一锅端”的转码方式里就会存在很多没有必要的部分。

比如你在规则集中选择了对Class关键字来定义类这个特性进行转码,那么babel就需要将其转码成为使用functionprototype的ES5的实现方式,但如果你的目标用户全都是程序员,几乎全都是使用高版本的chrome作为项目环境,那么上面的转码可能就是画蛇添足了。

综上所述,我们就需要为babel提供一个判断目标环境是否需要转码的方法babel_get_rule_as_need( rule_set , env_info),将经过第一次筛选后的规则集和目标用户的环境信息传入方法,对规则集进行再一次的精简,那么我们需要再次对babel进行优化:

奥门威尼斯网址 6

至此,babel便具备了针对不同的使用环境进行必要转码的能力,可这并不是问题的全部,ES6的新特性除了语法的更新外,还增加了很多原生方法或类型,例如Map,Set,Promise等这类新的全局对象,或是Array.from这类静态方法等等,语法转义并不能完成对这些特性的识别,因为无论在ES5环境还是ES6环境你都是这么写的,只有运行的时候,浏览器才会报错,告诉你某个对象或者某个方法不存在。

比如下面的代码:

function addAll() {
  return Array.from(arguments).reduce((a, b) => a + b);
}

转义后会变为:

function addAll() {
  return Array.from(arguments).reduce(function(a, b) {
    return a + b;
  });
}

然而,它依然无法随处可用因为不是所有的 JavaScript 环境都支持 Array.from。对于这一类非语法层面的特性,我们希望在工具中能够自动提供支持,这项工作有一个专有的称谓,叫做【polyfill】(或称为垫片)。

我们既可以主动提供一个polyfill列表指明需要添加的垫片插件数组,也可以采用被动的方式,在转码过程中遇到的这种API类型的新特性放进一个数组,通过babel_add_polyfill ( polyfill_list )为根据安装相应的垫片,需要注意的是,polyfill相当于为浏览器进行功能扩展,需要优先于项目业务逻辑代码运行,那么babel的逻辑框架就变成了:

奥门威尼斯网址 7

推演继续。在上面的逻辑结构中,我们只是简单地将polyfill库添加至全局变量,而全局变量是很有可能被重写而失效或是与其他第三方库发生代码冲突的。那么如果不将polyfill添加至全局,就需要将其剥离为一个具有同等功能的独立模块,通过类似于lodash或是underscore那样的方式调用,我们对逻辑结构进行再一次拆分:

奥门威尼斯网址 8

至此,我们已经完成了babel工具集基本功能的*逻辑层划分*,通过传说中的多退少补(也就是语法超前了就回退,方法不够了就打补丁)的方式来实现代码编译。

在babel5的时代,babel属于全家桶型,只要安装babel就会安装babel相关的所有工具,
即装即用。
但是到了babel6,具体有以下几点变更:
移除babel全家桶安装,拆分为单独模块,例如:babel-core、babel-cli、babel-node、babel-polyfill等;
使用babel的会自动识别.babelrc文件。
该文件用来设置转码规则和插件,基本格式如下。

三. 模块划分

根据上述业务逻辑层的划分结果,我们需要对Babel工具进行代码层的模块划分:

奥门威尼斯网址 9奥门威尼斯网址 10

{
  "presets": [], // 设定转码规则
  "plugins": [], // 
}

四. 真正的babel

如果你能够理解上述的需求推演和模块划分的章节,那么恭喜你已经掌握了babel的基本结构,我们将原本模块图中的信息更换成实际的名称或是插件,并进行一些组件划分,就可以看到真正的babel工具集的基本架构:

奥门威尼斯网址 11

当然真正的babel功能远不止这样,它为各种环境,编辑器和自动化工具提供了接口,也开放了插件开发的API给开发者,感兴趣的读者可以继续深入了解。

plugin:,插件,通过配置不同的插件才能告诉babel,我们的代码中有哪些是需要转译的。
preset:babel5会默认转译ES6和jsx语法,babel6转译的语法都要在perset中配置,preset简单说就是一系列plugin包的使用。
为什么我们经常会看到Stage 2这种插件?
ES即ECMAScrip。被纳入到ES标准的语法必须要经过如下五个阶段:
Stage 0: strawman
Stage 1: proposal
Stage 2: draft - 必须包含2个实验性的具体实现,其中一个可以是用转译器实现的,例如Babel。
Stage 3: candidate - 至少要有2个符合规范的具体实现。
Stage 4: finished

五. 使用babel

babel8.0以上的版本将许多插件移入官方仓库,安装方式发生了改变,例如babel-preset-env地址变为了@babel/preset-env,使用时请参考babel官网进行配置。

除了已经正式纳入规范 (ES2015/6/7) 的特性,还有许多处于不同讨论阶段的特性提案 (stage 1/2/3/4)。这些讨论中的特性严格来说还不算是标准,尤其是 stage 1/2 的特性,完全有可能被改动甚至是撤销提案。因此从 babel 的角度来说,显然不能够默认启用这些特性,而需要有可配置的选项让用户自行衡量风险,决定是否使用。

本文由威尼斯国际官方网站发布于软件资讯,转载请注明出处:大前端的活动化学工业厂

关键词: