babel 总共分为三个阶段:解析,转换,生成。
插件总共分为两种:
- 当我们添加 语法插件 之后,在解析这一步就使得 babel 能够解析更多的语法。
- 当我们添加 转译插件 之后,在转换这一步把源码转换并输出。这也是我们使用 babel 最本质的需求。
比起语法插件,转译插件其实更好理解,比如箭头函数 (a) => a
就会转化为 function (a) {return a}
。完成这个工作的插件叫做 babel-plugin-transform-es2015-arrow-functions
。
同一类语法可能同时存在语法插件版本和转译插件版本。如果我们使用了转译插件,就不用再使用语法插件了。
preset
一组插件的集合 官方内容,目前包括 env, react, flow, minify 等。这里最重要的是 env。
env 的核心目的是通过配置得知目标环境的特点,然后只做必要的转换。例如目标浏览器支持 es2015,那么 es2015 这个 preset 其实是不需要的,于是代码就可以小一点(一般转化后的代码总是更长),构建时间也可以缩短一些。
实际上这些 babel-*
大多是不同的入口(方式)来使用 babel,下面来简单介绍一下。
babel-cli
安装了 babel-cli
就能够在命令行中使用 babel
命令来编译文件。
babel-node
babel-node
是 babel-cli
的一部分,它不需要单独安装。
它的作用是在 node 环境中,直接运行 es2015 的代码,而不需要额外进行转码
babel-node
= babel-polyfill
+ babel-register
babel-register
babel-register 模块改写 require
命令,为它加上一个钩子。此后,每当使用 require
加载 .js
、.jsx
、.es
和 .es6
后缀名的文件,就会先用 babel 进行转码。
babel-polyfill
babel 默认只转换 js 语法,而不转换新的 API,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign
)都不会转码。
举例来说,es2015 在 Array 对象上新增了 Array.from
方法。babel 就不会转码这个方法。如果想让这个方法运行,必须使用 babel-polyfill
。(内部集成了 core-js
和 regenerator
)
babel-runtime 和 babel-plugin-transform-runtime (重点)
babel-plugin-transform-runtime:把 helpers 抽离并统一起来,避免重复代码的工作
从定义方法改成引用,那重复定义就变成了重复引用,就不存在代码重复的问题了。
在使用 babel-plugin-transform-runtime
的时候必须把 babel-runtime
当做依赖。
babel-loader
在 uglify 之前就加入 babel 处理
有了 babel 插入到构建工具内部这样的需求
和 babel-cli
一样,babel-loader
也会读取 .babelrc 或者 package.json 中的 babel
段作为自己的配置,之后的内核处理也是相同。唯一比 babel-cli
复杂的是,它需要和 webpack 交互,因此需要在 webpack 这边进行配置