3

这两天研究了一下babel这个工具,因为平时项目基本都是脚手架生成的babel配置文件,真正自己想写点东西的时候,亲自去配却是一脸懵逼,写下这篇博客记录一下我的认知范围内的babel总结。
首先,先看几个平时常见的babel配置
图片描述
图片描述
图片描述
图一:vue的webpack-template生成的babel配置
图二:react的create-react-app脚手架eject模式生成的babel配置
图三:一个常见的普通配置,有presets和plugins
这三张图看完文章应该都可以理解了

babel-core

首先什么是babel?
官网的介绍是:Use next generation JavaScript, today.
简单的说,就是让你可以在此时此刻此地使用下一代JavaScript语法和API,babel可以帮助你转换成浏览器可以运行的稳定的版本,因为各大浏览器对es6+的支持并不都很好。
且从babel6以及更高版本,babel自身不负责转换工作,具体的转换工作由插件来实现,babel只提供babel-core来把JavaScript代码分析为AST(抽象语法树),供插件做转换。

如何使用babel

通用的方式是在项目中写 .babelrc文件,或者在package.json中配置"babel"选项(图二react脚手架就是这么做的)

plugins、presets、transform-runtime、stage-X、env和babel-polyfill

npm install babel-core --save-d
写一个这样的例子

let a = 'a';
let assign = Object.assign({name: 'jack'}, {name: 'bob'});
let f = () => {
  console.log('arrow func');
}
let i = [].includes;
let p = new Promise();
var q = async function q() {
  console.log('async');
};

这是一段典型的es6语法的代码,为了将它转换为es5代码,我们需要使用插件来转换。
图片描述
可以看到这有许多的插件供选择,只需要挑选合适的插件即可,
.babelrc文件配置如下:

{
  "plugins": [
    "some plugin",
    "some plugin",
    ...
  ]
}

但是如果需要很多很多插件的话,一个一个写是很费力的
所以,presets可以拯救我们,presets可以理解为plugin的集合
继续配置.babelrc文件:

{
  "presets": [
    "es2015",
  ],
  "plugins": [
  ]
}

编译完的结果为
图片描述
可以看到只转换了let箭头函数这样的语法,assign、includes、Promise、async被原样输出
这个时候就需要transform-runtime了

{
  "presets": [
    "es2015"
  ],
  "plugins": [
    "transform-runtime"
  ]
}

编译完的结果为:
图片描述

可以看到let、箭头函数、Object.assign、Promise都被正确编译,但是async、includes依然没有变化
此时可以引入stage-X的概念了,Stage-x preset 中的任何转换都是对未被批准为 JavaScript 版本一部分的语言的变化,大白话就是还未被发布的版本中的语法,比如现在JavaScript的最新规范版本的es6,所以es7的一些语法我们就需要引入stage-X来使用,比如async这样的语法。
不成熟的想法(stage-0:Strawman)——>通过之后变成提议(stage-1:Proposal)——>通过进入草案(stage-2: Draft)——>通过进入候选(stage-3: Candidate)——>进入标准(stage-4:finished)可以看到这里面有个层层筛选的过程,所以stage-0包含的功能最多,要是不知道哪个阶段的功能,直接stage-0
至于stage-0、stage-1、stage-2、stage-3分别具体的使用,看文档babel-stage
继续配置.babelrc

{
  "presets": [
    "es2015"
    "stage-0"
  ],
  "plugins": [
    "transform-runtime"
  ]
}

编译结果:
图片描述
图虽然没截全,但是可以看到async方法被转换过来了,然而includes方法依然没有转换。
此时就要使用babel-polyfill了,babel-polyfill会仿效一个完整的 ES2015+ 环境,这意味着你可以使用新的内置对象比如 Promise 或者 WeakMap, 静态方法比如 Array.from 或者Object.assign, 实例方法比如 Array.prototype.includes 和生成器函数。简言之,babel-polyfill就像lodash这种库一样,引入之后可以随心所欲的使用es6+的方法。
使用方法:

import "babel-polyfill"

module.exports = {
    entry: ["babel-polyfill", "./index.js"]
};

最后,env是什么意思呢?它是environment的缩写,根据你支持的环境自动决定适合你的 Babel 插件的 Babel presets,其实就是根据你的环境来自动决定插件集合。

总结

plugin:真正做转换工作的,写在plugins数组中,实现一些语法的转换
presets:一组插件
stage-X:转换一些还未正式发布的语法,例如async
presets-env:根据你支持的环境自动决定适合你的 Babel 插件的 Babel presets
transform-runtime:转换一些对象以及方法,例如Promise、Set,并且它动态提供你所使用的插件,且不会强行的修改全局对象的prototype,但是runtime不会转换实例方法,只会转换静态方法。最后,写工具库的时候考虑使用transform-runtime,不会冲突
babel-polyfill:这是一个库,安装的时候我们需要让它成为一个 dependency, 而不是一个 devDependency,且它直接在全局对象上扩展,可以很自由的使用es6+,可以转换实例方法和静态方法,使用它可以取代transform-runtime和presets。但是它的问题是体积较大回带来许多我们并用不到的东西以及可能会带来冲突,需要兼容平台和环境较多时考虑使用

参考:
https://juejin.im/entry/5a290...
https://github.com/youngwind/...
https://segmentfault.com/a/11...


耳东
766 声望51 粉丝

知乎专栏:[链接]