背景
最近项目中遇到再安卓5.0以下的兼容问题,最后查了资料发现没有引入babel-polyfill的原因导致。后来就详细了解并整理了一下babel相关的知识点。
Babel包的构成
核心包
- babel-core:是babel转译器本身,提供转译的API,例如babel.transform等,webpack的babel-loader就是调用这些API完成转译的
- babylon:js的词法解析器
- babel-traverse:用于对AST(抽象语法树Abstract Syntax Tree)的遍历
- babel-generator:根据AST生成代码
其他
- babel-cli:用于命令行转码
- babel-types:用于检验,构建和变更AST的节点
- babel-helpers:一系列预制的babel-template函数,用于提供给一些plugins使用
- babel-template:辅助函数,用于从字符串形式的代码来构建AST树节点
- babel-code-frame:用于生成错误信息,打印出错误点源代码帧以及指出出错位置
- babel-register:通过绑定node.js的require来完成自动编译
- babel-polyfill:JS标准新增的原生对象和API的shim,实现上仅仅是core-js和regenerator-runtime两个包的封装
- babel-runtime:类似于polyfill,但是不会污染全局变量
babel的配置
一般常见的还是直接通过编写.babelrc,也推荐这么用,当然你也可以使用命令行的形式。
配置字段(这里以vue的官方架子里面的字段为例)
env:可以对BABEL_ENV或者NODE_ENV指定的不同的环境变量,进行不同的编译操作,优先获取BABEL_ENV环境变量,然后NODE_ENV,最后默认development
plugins:使用的插件列表
presets:使用的preset列表,常见的es20xx,stage-x,以及env等
comments:编译过程是否产生注释,默认为true
配置文件的查找
babel会从当前转译的文件所在目录下查找配置文件,如果没有找到,就顺着文档目录树一层层往上查找,一直到.babelrc文件存在或者带babel字段的package.json文件存在为止。
babel的工作原理
|
|
babel转译有一点需要注意:babel只是转译新标准引入的语法,比如ES6的箭头函数转译成ES5的函数;而新标准引入的新的原生对象,部分原生对象新增的原型方法,新增的API等(如Proxy、Set等),这些babel是不会转译的。需要用户自行引入polyfill来解决。
polyfill
polyfill其实就是对core-js和regenerator runtime进行了包装,为es2015+提供了一个环境垫片,让你可以使用新标准引入的各种新特性
polyfill的使用方法
|
|
这里的方法会将全部的环境都导入,但是polyfill的文件比较大,即便是压缩后也可能达到80kb,在移动端我们是不希望引入这么大的辅助文件(比vue大得多),所以我们希望实现按需引入,如果我们明确知道自己需要转译哪些API,我们可以借助于core-js实现按需引入。
core-js的使用
1、类似于polyfill,将所有的特性添加到全局环境,默认方式
2、库的形式引入,这种也是引入所有的特性,只是不会污染全局变量
3、只引入shim,只包含标准特性,其实和polyfill一样
core-js按需引入的使用方法
|
|
|
|
polyfill与runtime的区别
最主要的区别就是polyfill引入后,会将新的原生对象、API这些都直接引入到全局环境,这样就会污染全局变量,这也是polyfill的缺陷。所以就轮到babel-runtime上场了。
transform-runtime和babel-runtime
transform-runtime是将js中使用到新的原生对象和静态方法转译成对babel-runtime的引用,而其中babel-runtime的功能其实最终也是由core-js来实现的,其实真正的核心是上面所讲的core-js,其他的都是包装。
总结
babel的使用其实不难,只需要理解各个依赖关系就可以了,明白各个包以及插件分别用来干嘛就可以啦。