Babel介绍
Babel是一套主要用来将使用ECMAScript2015+语法编写的代码转换成纯ES5的Javascript代码的工具,以兼容任何老式浏览器与运行环境。
Babel可以用来编译ES6+的语法,它使所有ES6+规范新增的语法糖都可用,包括:类(class),箭头函数(arrow function),多行字符串等等。它的功能包括但不限于:
1.Javascript语法转换;
2.使用ployfill特性使你的浏览器兼容各类全局web api(例如:promise,async await);
3.源代码转换;
@babel/core作为Babel的核心包,主要负责代码的转换工作。其内部使用了@babel/parser,@babel/traverse,@babel/generator三个工具来负责代码的转译过程。
parser:内部依赖acorn和acorn-jsx,将js代码解析为抽象语法树;
traverse:修改parser解析后的抽象语法树;
generator:解析traverse编辑后的抽象语法树,生成对应的es5语法;
Babel的代码转换其实是一个线性的流程,依次经历解析,转换,生成三个阶段。
Plugin是Babel提供的用来帮助代码转换的工具,它主要在抽象语法树的转换阶段发挥作用,也就是traverse阶段。如果我们不使用任何plugins,源代码经过babel编译后会原样输出(不会保留原有代码格式)。Plugin则会告知babel如何转换我们的代码。
Babel提供了很多的plugins用来转换代码,其细粒度精确到每一种ECMAScript2015+语法,例如@babel/plugin-transform-arrow-functions负责转换箭头函数,@babel/plugin-proposal-object-rest-spread用来转换对象扩展运算符。同时babel的plugin还做了对框架语法的兼容,比如对react的jsx的转换。我们可以根据项目需求自行选定不同的插件。
上面提到了babel的plugins,plugins虽然功能丰富,但是es5+新出的语法还是比较多的,如果一个一个安装的话未免太麻烦,幸好babel提供了另外一种工具——presets。
如果把一个plugin比作一种工具,则presets则是工具箱。Presets是一组plugins的集合,用来转换一类语法。在实际项目中最常用preset便是@babel/preset-env了,它非常聪明可以帮助我们转换所有最新的Ecmascirpt标准语法。因此再也不需要去根据项目中使用到的语法而一个一个的安装插件,非常方便并且可以减小打包体积。
笔者曾经在开发的时候遇到过一个问题,webpack和babel都已经配置好,并且项目也可以在chrome中正常运行,但是在ie浏览器中却一直报错。找了一圈后来发现是项目中使用promise和async await的问题。于是我回头看了项目内babel配置,该用的插件也都用了,那么问题到底出在哪里呢?后来回顾了一个babel文档,才发现promise和async并不属于ES规范语法,而是全局api。
Polyfill就是babel提供的可以帮助我们兼容这些内建api的工具。这意味着您可以使用新的内置函数(例如Promise或WeakMap),静态方法(例如Array.from或Object.assign),实例方法(例如Array.prototype.includes)和生成器函数(前提是您使用了regenerator插件)。 为了做到这一点,polyfill将诸如String之类的本地原型添加到了全局范围。
Babel的配置可以说是非常简单了。Babel官方提供了两种配置文件以供选择:
babel.config.js: 使用编程的方式来进行配置;
module.exports = function (api) { api.cache(true); const presets = [ ... ]; const plugins = [ ... ]; return { presets, plugins };
.babelrc:静态配置,仅适用于单个程序包;
{ "presets": [...], "plugins": [...] }
如果项目中使用了webpack,则需要在webpack配置文件内配置babel-loader以启用babel配置
//webpack.config.js module: { rules: [ { test: /\.js$/, exclude: /node_modules/, loader: ‘babel-loader‘, } ] }, //.babelrc { "presets": [ ["@babel/preset-env"], ["@babel/preset-react"] ] }
或者
//webpack.config.js module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: ‘babel-loader‘, options: { presets: [‘@babel/preset-env‘, "@babel/preset-react"], } } } ] }, (此种配置方式无需配置babel配置文件)
如果项目中需要用到polyfill,可以将其在项目入口文件顶部引入或者加入到webpack配置文件的入口配置:
//index.js require(‘@babel/polyfill‘); or import ‘@babel/poltfill‘;
//webpack.config.js entry: [‘@babel/polyfill‘, ‘./index.js‘],
注意在babel7.4.0之后的版本polyfill将会被弃用,建议您直接使用polyfill包含的core-js/stable和regenerator-runtime/runtime。
//index.js import "core-js/stable"; import "regenerator-runtime/runtime";
如果您觉得直接引入core-js会增大打包体积,也可以使用按需引入的方式:
//index.js import ‘core-js/features/promise‘; import ‘core-js/features/array/from‘;