Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浅谈Babel #28

Open
Quickeryi opened this issue Aug 14, 2017 · 0 comments
Open

浅谈Babel #28

Quickeryi opened this issue Aug 14, 2017 · 0 comments
Labels

Comments

@Quickeryi
Copy link
Owner

Quickeryi commented Aug 14, 2017

虽然目前所有的主流浏览器都支持了大部分ES6特性,但是为了能让ES6代码完美的运行在各个沙箱中,我们还是不得不借助Babel这样强大的转码器

关于Babel

Babel是一个转码器,它把源码作为输入,输出的也是源码,下图可以很明确的说明这个原理
d39bf2be-918d-46e4-a61f-861e6b573cc6

Babel5 vs Babel6

Babel主要有两个版本,Babel5Babel6,那么两者到底区别何在呢?下面主要说一下主要的区别:

  1. Babel5属于开箱即用型,开发人员只要安装后就可以使用,因为它将所有的转译功能集成到了一起,属于一个大熔炉;而Babel6则恰恰相反,它将所有功能分散到了各个插件中,Babel6本身只是一个空的插口容器,需要什么功能需要开发者自行下载相应的插件然后配置
  2. 两者区别还在于一些API的用法,这里就不细谈了
  3. 下面用一幅图说明一下两者的区别

b08666f4-5d03-4b67-b440-af9312b3edc7

关于配置(针对Babel6)

使用过Babel需要依赖于配置项,不管是使用babel-cli还是依赖于像webpack这样的打包工具,配置项都类似于下面这样:

{
    presets: [
       'es2015',
       'stag-0'
    ],
    plugings: [
      'babel-runtime',
      'transform-runtime'
    ]
}

下面主要说一下presetsplugings的区别:

  1. presets意思为预设集,它是建立在plugings之上的,在上面讲babel5babel6的区别时就说到过,babel6的使用依赖于一系列插件,而为了简化配置流程,Babel官方就提供了一系列预设集,每一个预设集其实就是包含了一些列插件的集合而已,这样我们只需要安装一个预设集,而不用安装几十个插件。所以开发者完全可以根据自己的业务封装自己的预设集。
  2. plugings顾名思义就是插件集合,每一个插件都包含一个独立的功能,开发者可以自己开发属于自己的插件
  3. 执行顺序:有人可能会想,同时配置两者,那么在转译时到底是怎样读取配置文件的呢?答案是:先扫描plugings内的配置,而且方向是从上往下,再扫描presets内的配置,方向是从下往上

关于Stage-X预设集:

设置过预设集的人都知道在Babel6中提供了stag-0stag-1stag-2stag-3四种这样的预设集,那么到底是什么意思呢?其实这个要从ECMAScript制定规范来说,一个规范从提出开始到最后发布要经历下面5个阶段:

  1. Stage 0 - Strawman(展示阶段)
  2. Stage 1 - Proposal(征求意见阶段)
  3. Stage 2 - Draft(草案阶段)
  4. Stage 3 - Candidate(候选人阶段)
  5. Stage 4 - Finished(定案阶段)

所以上述所说四个预设集分别对应前四个阶段,但是为何没有stage-4呢,其实很简单,因为这个阶段已经是正式定案阶段,那它已经被包含在es2015这样的预设集当中了,所以完全没有必要。还需要注意的是,阶段越靠前包含的特性越多,这同样很好理解,因为在推进过程中可能会删除某些特性,如果用一个图表示上述四个预设集的关系,应该如下:
4eb2fde5-fede-4a2f-af0b-411f554353cb

深入转译(语法与API)

许多开发者有一个误解,就是使用Babel转译后就可以使用ES6的所有新特性了。其实这是错误的,因为ES6的新特性包括两部分,语法API,所以有时候会发现普通转译后还是会出现JS执行错误的现象

  1. 语法:比如说箭头函数等,这一部分Babel提供的预设集会进行转译
  2. API:比如说GeneratorPromise,这一部分则需要使用类似于polyfill 插件完成

babel-polyfill vs babel-runtime

babel-polyfillbabel-runtime就是为转译API而催生出来的插件,需要注意的是两者的功能几乎相同,但是两者又有不同的地方~

  1. babel-polyfill:它的做法是将全局对象通通污染一遍,比如想在用Promise,调用babel-polyfill就会往global对象挂上Promise对象,对于普通的业务代码没有关系,但如果用在模块上就有问题了,会把模块使用者的环境污染掉
  2. babel-runtime:它解决了上述 babel-polyfill产生的问题,它的原理是引入helper函数,比如如下例子
// es6 source code
Promise.resolve(true)

// output es5 code
const Promise = require('babel-runtime/core-js/promise')
Promise.resolve(true)

是的,问题也暴露了,就是Promise不能共享,如果有多个模块需要使用,则要在每一个模块头部引用helper,这样就会存在重复打包的情况。问题总能得到解决,所以babel-plugin-transform-runtime又应运而生了。

babel-plugin-transform-runtime

Externalise references to helpers and builtins, automatically polyfilling your code without polluting globals

上述是它官方的解释,其实翻译出来就是外部全局引入helper,然后重写代码。简化后的意思就是它只会在全局引入一次helper,然后重写我们的代码,比如Promise重写为_Promise_,然后使用_Promise_引用helper,这样就不会造成全局污染,如下图所示:
7181774b-a9c5-4295-97df-eaf4f7aaee48
所以为了方便,我们一般只需要在plugings中配置transform-runtime即可,需要注意的是babel-plugin-transform-runtime依赖于babel-runtime所以我们不需要手动安装babel-runtime

写在最后

我们在实际开发中可以封装自己的presets也可以开发自己的pluging,关于这两部分的内容有时间会写一些记录

课外阅读

  1. Babel的使用
  2. Babel 用户手册
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant