youngwind / blog

梁少峰的个人博客
4.66k stars 385 forks source link

babel初学者的一些常见误区 #68

Open youngwind opened 8 years ago

youngwind commented 8 years ago

问题

使用babel有一段时间了,但是一直没有仔细研究。上回在前端使用async解决回调的时候出现问题,后来引入了babel-polyfill才解决,其实那时候不太懂为什么一定要这么搞。今天趁着有时间再次通读了一边babel官网的文档,觉得很多问题比原先想得明白了。

babel5 VS babel6

babel是一个转换器,或者准确的说,babel5是一个转换器,babel6是一个容纳其他转换插件的容器。因为从babel6开始babel本身就不完成任何转换功能,所有功能都插件化了,意味着你除了安装babel6以外,还需要安装其他插件才能干活。

语法与api

我以前一直以为装了babel之后所有es6的语法都可以使用了,但是后来才发现不是。因为es6作为新的标准,它的拓展包括语法和api。 什么是语法呢?比如箭头函数

// before
() => {}

// after
function(){}

babel会将这些语法转换成es5的格式,从而让es6的语法可以运行。 但是,对于es6拓展的api可不是单纯通过转换语法就可以实现的 比如说,

//before
() => {
  var demo = {
     name:"youngwind"
  }
  Object.assign({},demo,{age:24})
}

//after
function () {
  var demo = {
     name:"youngwind"
  }
  Object.assign({},demo,{age:24})
}

看,babel虽然把箭头函数转换了,但是还是得执行Object.assign,可是es5中没有这个方法啊,所以即便是转换之后的代码在es5的环境下执行还是会报错。如果我们脱离babel来观察这个问题的话,你就会发现,这不就是ployfill嘛!整个ployfill就好啦!是的,这就是babel的第二部分功能:polyfill babel对于这些兼容性api的处理有两个方法。

  1. 通过plugins插件,比如transform-object-assign解决object.assign
  2. 通过统一的polyfill,也就是babel-polyfill

    关于babel-polyfill

babel-polyfill本质上也只是一个polyfill,官方文档中提到,它包括一个定制的regenerator runtime(用于解决generator和yield的问题)和zloirock开发的core.js (一个用于解决es6、es7 polyfill的大集合)。所以这也解释了为什么之前在前端使用async的时候需要引入polyfill了,见 #62 。换句话说,如果你不喜欢babel-polyfill的话,你也可以使用其他polyfill来代替它,完全不用考虑babel的感受:-D。而且babel-polyfill的体积也不小(压缩后90多k呢),之后其实可以考虑一下只引入需要用到的polyfill。

关于preset与plugin

前面已经提到,babel是靠一系列plugins起作用的,但是如果每回都需要配置一大堆插件的话,那样显得太麻烦了,所以在plugin之上有一个preset的概念,其实preset也就是特定插件的集合。比如我们常用的es2015 preset,它就包含下面这些plugins,如图所示

2016-04-24 11 33 39

不仅preset之间也可以相互包含,你也可以很方便的自定义自己的preset,比如把公司项目常用的plugin集合弄到一个preset中,具体可以参考这儿

关于stage-X

一开始我也不知道为什么有些时候要使用stage-0啊,stage-1啊这些东西,后来搞明白了。这个还得从es这门语言的规范制定说起。es作为一门语音,它的规范制定是由某个委员会来统筹的。就像法律一样,一个标准的诞生是要经过很多次的讨论的:一开始是一些不成熟的想法(stage-0:Strawman),通过之后变成提议(stage-1:Proposal),再通过进入草案(stage-2: Draft),再通过进入候选(stage-3: Candidate),最后才能进入标准(stage-4:finished)。标准里面的每一条都得经过层层的筛选,并不是所有都能在最后进入标准的,所以使用stage-x里面的新特性是有一定风险的,比如我们用得很多的async和await,它就是属于stage3,还差一点就进入标准了。所以,如果你想使用还没有进入标准的一些新特性,你就需要包含相应的stage-x-preset或者plugins。

参考资料:

  1. babel中如何使用stage-X
  2. 现在的各个stage都包含哪些新特性呢?
  3. es标准化的流程是什么样子?

    开发环境与生产环境

babel是可以区分开发环境和生产环境的,就像webpack那样,具体可以参考这里

最后,这里有个很不错的babel中文手册,可供参考。

遗留问题

  1. 为了更深入得理解babel,计划自己写一个简单的babel插件。
  2. 把项目中常用的plugins抽象成preset(如果有必要的话)
  3. 寻找只引用需要的polyfill的解决方案,或许是时候研究rollup了。
mqliao commented 7 years ago

polyfill 确实太大了,对移动端web是个挑战

Thinking80s commented 7 years ago

那么配置的.babelrc文件中同时设置集合和插件也是一种兼容方式吧?{"presets": ["es2015", "stage-3"], "plugins": ["transform-runtime"]}