babel 编译的阶段
babel 总共分为三个阶段:解析,转换,生成。
我们需要知道现在 babel 本身是不具备这种转化功能,提供这些转化功能的是一个个 plugin。所以我们没有配置任何 plugin 的时候,经过 Babel 输出的代码是没有改变的。
Plugin —— transform 的载体
Babel 自 6.0 起,就不再对代码进行转换。现在只负责图中的 parse 和 generate 流程,转换代码的 transform 过程全都交给插件去做。
@babel/preset-env(按需加载)
Preset 是什么? Preset 插件套餐,每个套餐里打包了不同的插件,这样安装套餐就等于一次性安装各类 babel 插件。
首先在项目下安装:
$ npm install --save-dev @babel/preset-env
然后修改 .babelrc:
{
"presets": ["@babel/preset-env"]
}
plugins 与 presets 同时存在的执行顺序
-
先执行 plugins 的配置项,再执行 Preset 的配置项;
-
plugins 配置项,按照声明顺序执行;
-
Preset 配置项,按照声明逆序执行。
列入以下代码的执行顺序为:
-
transform-es2015-template-literals
-
stage-2
-
env
// .babelrc 文件
{
"plugins"
: [
"transform-es2015-template-literals"
,
// 转译模版字符串的 plugins
],
"presets"
: [
[
"env"
, {
// 是否自动引入 polyfill,开启此选项必须保证已经安装了 babel-polyfill
// “usage” | “entry” | false, defaults to false.
"useBuiltIns"
:
"usage"
}],
"stage-2"
]
}
useBuiltIns 配置
我们可能在全局引入 babel-polyfill,这样打包后的整个文件体积必然是会变大的。
但是通过设置 "useBuiltIns":"usage"
能够把 babel-polyfill 中你需要用到的部分提取出来,不需要的去除。
useBuiltIns 参数说明:
-
false: 不对 polyfills 做任何操作
-
entry: 根据 target 中浏览器版本的支持,将 polyfills 拆分引入,仅引入有浏览器不支持的 polyfill
-
usage(新):检测代码中 ES6/7/8 等的使用情况,仅仅加载代码中用到的 polyfills
@babel/polyfill(完整模拟es2015+,体积庞大)
babel 编译过程处理第一种情况 - 统一语法的形态,通常是高版本语法编译成低版本的,比如 ES6 语法编译成 ES5 或 ES3。而 babel-polyfill 处理第二种情况 - 让目标浏览器支持所有特性,不管它是全局的,还是原型的,或是其它.
安装 babel-polyfill
$ npm install --save @babel/polyfill
使用 babel-polyfill
我们需要在程序入口文件的顶部引用 @babel-polyfill
:
require('@babel/polyfill')
[].findIndex('babel')
或者使用 ES6 的写法:
import '@babel/polyfill'
[].findIndex('babel')
需要注意的是,babel-polyfill 不能多次引用。如果我们的代码中有多个 require('@babel/polyfill')
,则执行时会报告错误;
@babel/plugin-transform-runtime(按需引入,打包体积小,不能兼容实例方法)
我们首先安装插件:(@babel/plugin-transform-runtime需要依赖
@babel/runtime)
$ npm install --save-dev @babel/plugin-transform-runtime
然后再安装 babel-runtime:
$ npm install @babel/runtime
最后在 .babelrc
中配置:
{
"plugins": [
"@babel/plugin-transform-object-assign", //如果我们要使用object.assign()对于@babel/plugin-transform-runtime这样配置,而babel-polyfill引入即可
"@babel/plugin-transform-runtime"
]
}
这样,我们不需要 babel-polyfill 也一样可以在程序中使用 Object.assign
,编译后的代码最终能够正常运行在 IE 11 下。
提问:在经过
@babel/plugin-transform-runtime
的处理后,IE 11 下现在有Object.assign
吗?
答案是,仍然没有。
这正是 babel-polyfill 与 babel-runtime 的一大区别,前者改造目标浏览器,让你的浏览器拥有本来不支持的特性;后者改造你的代码,让你的代码能在所有目标浏览器上运行,但不改造浏览器。