谈谈Babel配置和babel-preset-env


1.Babel是什么

​ “The compiler for writing next generation JavaScript”
​ 简单翻译下就是“用于编写下一代JavaScript的编译器”。随着时间推移,JavaScript也在慢慢进化,新的特性和语法随之出现,然而各个浏览器厂商并没有完全的支持,所以要有个工具,把新的特性和语法翻译成浏览器都认可的标准语法,Babel应运而生,它就是这个工具,ES6/ES7/ES8 => Babel => ES5。
babel-compile

2.Babel preset & plugin & stage-x

​ preset、stage-x都是plugin的范畴,只不过所覆盖的范围不同。如果你要用ES2015(ES6)语法,一下是plugin和preset的不同引入方式

(1)plugin

1
2
3
4
5
6
7
8
// .babelrc
{
plugins: [
'transform-class-properties',
'es2015-arrow-functions',
'transform-decorators-legacy'
]
}

(2)preset

​ 为了大家引入方便,Babel团队将ES2015的很多个transform plugin集成到babel-preset-es2015,所以你这需要引入es2015,大大降低了引入成本

1
2
3
4
// .babelrc
{
"presets": [ "es2015" ]
}

(3)stage-x

stage-x分别代表的是stage-0、stage-1、stage-2、stage-3进入EMAC标准之前的4个阶段

(4)plugin和preset运行顺序

  • plugin 会运行在preset之前
  • plugin 会从第一个开始顺序执行
  • preset 的顺序则刚好相反(从最后一个逆序执行)

3.babel-preset-es2015/es2016/es2017

(1)es2015(ES6)

4.babel-preset-stage-x

​ 语言的变化需要一个过程来发展,stage-x提供了将一个想法进化为一种完善规范的指导原则,stage-0包含stage-1/2/3,stage-1包含stage-2/3,stage-2包含stage-3,TC39工作流:https://tc39.github.io/process-document/
TC39 Process

(1)stage-0

  • transform-do-expressions
  • transform-function-bind
    除了上述插件还包含stage-1,stage-2,stage-3的插件

    (2)stage-1

  • transform-class-constructor-call (Deprecated)
  • transform-export-extensions
    除了上述插件还包含stage-2,stage-3的插件

    (3)stage-2

  • syntax-dynamic-import
  • transform-class-properties
  • transform-decorators disabled pending proposal update (can use the legacy transform in the meantime)
    除了上述插件还包含stage-3的插件

    (4)stage-3

  • transform-object-rest-spread
  • transform-async-generator-functions

5.babel-polyfill

Babel编译时只编译语法,并不会编译BOM不兼容的API,如:async ,Set,Symbol,Promise等,babel-polyfill会把这些没有的API全部挂载到全局对象,也就是所谓的“垫片”。

(1)优点

如果你代码中大量引用上述API,引入babel-polyfill将是一劳永逸

(2)缺点

babel-polyfill比较简单粗暴,在引入的同时,也污染了全局对象,导致无效增加了很多用不到的polyfill,也可能会污染子模块的变量引用,可能导致不必要的冲突。

  • 如果你要使用babel-polyfill,你需要你其他代码或者模块被引用前引入,入口JS顶部(目前跟多情况下是在Node中使用):
1
2
3
4
// ES5
require("babel-polyfill");
// ES6
import "babel-polyfill";

6. babel-tuntime和babel-plugin-transform-runtime

(1)babel-runtime

​ babel-runtime和babel-polyfill有点类似,都是去兼容新API的“垫片”,它和babel-polyfill最大的不同就是可以做到按需引用,哪里需要什么就用什么,比如我需要Promise。一般在生成环境,首先安装依赖,然后引入:

1
npm install --save babel-runtime
1
import Promise from 'babel-runtime/core-js/promise';

(2)babel-plugin-transform-runtime

​ 问题来了,如果用babel-runtime,如果我10个文件要引用Promise,难道每个文件都得写个babel-runtime的Promise引入么,显然很麻烦。那么babel-plugin-transform-runtime就是用来解决这个问题的,无论你多少个文件引入了相关新的API,它只会存在一份,babel-plugin-transform-runtime本质上依赖于babel-runtime的core-js,在编译的时候会帮你自动处理,在开发环境安装依赖:

1
npm install --save-dev babel-plugin-transform-runtime

你只需要配置.babelrc:

1
2
3
4
5
6
// .babelrc
{
"plugins": [
"transform-runtime"
]
}

7.babel-preset-env

相信没升级过babel-preset-env的,在安装babel-preset-es2015/es2016/es2017,会遇到下面的提示
babel-preset-env
​ babel-preset-env将基于你的实际浏览器及运行环境,自动的确定babel插件及polyfill,编译ES2015及此版本以上的语言,在没有配置项的情况下,babel-preset-env表现的同babel-preset-latest一样(或者可以说同babel-preset-es2015, babel-preset-es2016, and babel-preset-es2017结合到一起,表现的一致)。 babel-preset-env详细配置

1
npm install babel-preset-env --save-dev

(1)不用babel-preset-env

1
2
3
4
5
6
7
8
{
"presets": ["react", "es2015", "stage-1"],
"plugins": [
"transform-remove-strict-mode",
"transform-class-properties",
"transform-flow-strip-types",
]
}

(2)用babel-preset-env

​ 你不在需要根据兼容的语法和API去引入对应的plugin,babel-preset-env会根据你对应的配置帮你自动引入依赖的插件

1
2
3
{
"presets": ["react", "env", "stage-1"]
}

8.webpack配置babel-present-env

webpack以配置兼容chrome 44 版本及以上,IE 9 及以上为例,配置如下:

  • webpack.config.js文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// webpack v3.x module配置
module: {
rules: [{
test: /\.html$/,
loader: 'html-loader?minimize=false'
}, {
test: /\.json$/,
loader: 'json-loader'
}, {
test: /\.(?:jpg|gif|png)$/,
loader: 'url-loader?limit=10240&name=../images/[name]-[hash:10].[ext]'
}, {
test: /\.js$|\.jsx$/,
exclude: /(node_modules|bower_components)/,
use: [{
loader: 'babel-loader'
}]
}]
}
  • .babelrc文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    {
    "presets": [
    [
    "env", {
    "targets": {
    "browsers": [
    "last 2 versions",
    "chrome >= 44",
    "ie >= 9"
    ]
    }
    }
    ],
    "react",
    "stage-1"
    ]
    }