由于在某些系统中对于新语法的支持比较差,经常会导致一些意想不到的问题,详见问题链接。而这种情况通常排查起来是相当困难的,因此,我们希望在代码上线前可以把我们平时用的一些高阶语法变成绝大多数机型和浏览器都支持的低阶语法。很好的是,babel可以完美的解决我们的问题。
我曾经在公司的项目中看到了很多关于babel的依赖,webpack中的babel-loader,babel-transform-runtime,babel-polyfill等等,不禁感慨,这是啥,这又是个啥,接下来我就说一下babel的作用和互相之间的关系。
babel配置
babel的配置方式有很多,官方文档上提供了很详细的解释,babel配置文档,通常来说,结合打包工具使用是比较常见的一种方式,比如在webpack中使用babel-loader进行es5+语法转换。
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [require('@babel/plugin-transform-object-rest-spread')]
}
}
}
]
}
结合webpack配置很简单,但是此时打包并不能实现我们想要的效果,因为此时babel并不知道你要转换哪些代码,转换成什么样子,所以,我们还需要一个类似于配置的文件来做这些事情。配置的方式有以下几种:
- package.json中设置babel字段。
- 添加.babelrc文件或者是.babelrc.js文件。
- 根目录下添加.babel.config.js文件。
如果是项目整体配置的话,官方建议是使用第3中方式,因为.babel.config.js是针对于项目整体的,就是一个项目只能有一个.babel.config.js,并且需要存在于项目根目录下。
而如果是针对于文件夹级别的配置,可以考虑使用第2种形式,配置.babelrc文件,同时,子文件夹中如果存在.babelrc文件,则会覆盖父级的配置,优先级也会高于.babel.config.js文件配置。
.babelrc文件配置
{
"presets": [...],
"plugins": [...]
}
plugins
从上面的配置文件中可以看到里面有两个key值,presets和plugins,因此,我们需要在配置文件中引入对应的插件。比如我们想要对箭头函数这个语法进行转换,就需要这边配置:
{
"plugins": [
'@babel/plugin-transform-arrow-functions',
],
}
这个时候就会有疑问,如果我们使用了很多的高阶语法,那我是不是需要在plugins中配置各种各样的插件呢?答案是不需要的。因为babel已经替我们做好了这种情况是解决方案。也就是上面提到的另一个key,presets(预设)。
presets
预设就是预先设定好一个插件列表,然后这个列表里面包含的东西可以让我们随意使用,比如使用@babel/presets-es2015,这样的话es2015中的语法都会被转换,比如刚刚的箭头函数,let of等。
{
"presets": [
"@babel/preset-es2015",
],
}
babel不仅支持高阶语法的转换,同时也支持vue,react等语法的转换,比如转换jsx语法就需要在presets中设置react。
preset-env
说来懒人才会创造更多的工具,presets已经很方便了,但是有人又坐不住了,说后面还会有es2016,es2017等等,然后一直预设下去吗?于是babel推出了一个preset-env,智能预设,意思就是只要安装了这个预设,然后设置目标浏览器,那么babel就会将项目中的新语法自动转换成目标浏览器支持的语法。
{
"presets": [
[
"env",
{
"targets": {
"browsers": '> 1% ios >= 5 Android >= 4.0',
// chrome: 60, 也可以这样写
}
}
]
],
}
这里的targets指的是目标环境,如果不设置的话babel会有一个默认的配置,规则为 > 0.5%, last 2 versions, FireFox ESR, no dead。
官方更推荐使用preset-env
stage
有些时候我们会在项目中看到有类似这样的配置
{
"presets": [
"stage-0",
],
}
这里的stage-0是什么意思呢?
stage系列是对es7的草案支持的插件,因为还没有正式发布,因此只能以插件的形式存在,网上有很多详解的例子,如stage系列解释,里面详细介绍了stage的作用和支持语法,在此不再赘述。
代码体积大小 babel-plugin-transform-runtime和babel-runtime
勤(wu)奋(liao)的人又再一次的发出疑问,babel在转换过程中,有时会依赖一些工具函数,如果项目中有很多这样的转换的时候,就会出现很多重复的代码,无端的增加代码体积。而plugin-transform-runtime就是为了解决这个问题的。配置如下:
{
"plugins": ["@babel/plugin-transform-runtime"]
}
具体区别就是在引入transform-runtime之后,编译后的代码中重复的代码变成了通过依赖包引入的形式来减小代码体积。
babel/runtime是项目生产依赖,而不是开发依赖,编译时使用了transform-runtime,项目就要依赖于babel/runtime,二者相辅相成。
babel-polyfill
es6中的一些新语法可以通过babel-loader来进行转换,那我如果想要用一些新的函数呢,或者array.includes,array.from等静态方法的时候,babel-loader就不能满足我们的需求了。这个时候就需要babel-polyfill登场了。
我曾经见过几种不同的引入babel-polyfill的方式,接下来我将比较一下这几种方式之间的不同。
- 暴力法
直接在入口文件中 import ‘@babel/polyfill’。 这种方式最为直接,将整体引入进来,但带来的弊端也很明显,这会明显增加代码体积,而且,整体引入的话会带来很多的变量,因此目前这种引入方式已经不再建议使用,更推荐使用preset-env来使用polyfill。
- 使用preset-env
{
"presets": [
[
"env",
{
// usage-按需引入
// entry-入口引入(整体引入)
// false-不引入polyfill(默认)
useBuiltIns: 'usage',
// 2-corejs@2
// 3-corejs@3
corejs: 2
}
]
],
}
其中useBuiltIns有三个选项值,默认为false,不对polyfill做任何操作;entry,根据target中浏览器的支持,将polyfill拆分引入,仅引入浏览器不支持的polyfill;usage,检测es6/7/8使用情况,加载代码中用到的polyfill。而corejs指使用的corejs的版本。
至此对于babel的配置实践基本就说完啦,配置的方式千奇百怪,但是其中的道理是不变的,只是配置的地方不同而已,可以放在webpack中,也可以放在packjson中,或者放在特定的配置文件中。
最后,感谢阅读,觉得写的不错点个赞吧~
参考: