这里我们主要讲解babel7的相关方法。
首先第一点就是babel的三个核心包:@babel/core、@babel/cli、@babel/type。
如果要使用命令行来执行babel则需要安装@babel/cli,如果需要在js脚本中使用babel,那么就需要安装@babel/core、和@babel/type了。
这里要注意一下这个@这个符号,这个是只有babel7才特有的,babel6都木有,市面上大量代码都是基于6的所以要特别注意。
babel常用的库有以下几种:
@babel/cli
@babel/core
@babel/preset-env
@babel/polyfill
@babel/runtime
@babel/plugin-transform-runtime
@babel/plugin-transform-xxx。
这里需要注意@babel/cli依赖@babel/core。
babel转化js语法分为两部分一部分与语法结构如const、let一部分为api也就是内置函数如includes等。
而@babel/preset-env就是转化语法结构的,@babel/preset-env是一系列插件的集合,包含了我们在babel6中常用的es2015,es2016, es2017等最新的语法转化插件,允许我们使用最新的js语法,比如 let,const,箭头函数等等。
而@babel/polyfill的polyfill直译过来就是垫片的意思就是为了转化api的工具。
@babel/preset-env如何使用呢?
简单的使用如下:
代码语言:javascript复制{
"presets": [
[
"@babel/preset-env"
]
]
}
此时会根据只会转译语法而不会转译api,并且会根据另外一个配置来转译,这就是browserslist,这个配置有三种配置方式,一种是在.babelrc中的target参数中配置,一种是在.browserslistrc中配置,一种是在package.json中配置。
package.json中配置如下:
代码语言:javascript复制{
"browserslist": [
"last 1 version",
"> 1%",
"maintained node versions",
"not dead"
]
}
.browserslistrc配置如下:
代码语言:javascript复制# 注释是这样写的,以#号开头
last 1 version #最后的一个版本
> 1% #代表全球超过1%使用的浏览器
maintained node versions #所有还被 node 基金会维护的 node 版本
not dead
在.babelrc中的配置方式为:
代码语言:javascript复制{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"chrome": "58",
"ie": "11"
}
}
]
]
}
通过配置browserslist可以根据浏览器版本转译相应的语法,那api如何转译呢?也就是@babel/polyfill如何使用呢?答案就是配置babel/preset-env。babel/preset-env中有一个参数是开启@babel/polyfil的默认为false,也就是不开启垫片,默认如下:
代码语言:javascript复制{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": false
}
]
]
}
上面这种方式,即不开启垫片,不需要转译api。
第二种方式,参数值为entry,意思是在入口文件引入所有api,代码如下:
代码语言:javascript复制{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "entry",
"debug": true
}
]
]
}
使用这种方式,还需要在入口文件手动引入@babel/polyfill,如图:
上图展示了如何引入babel/polyfill和其转译后的结果,我们可以通过转译结果看到其弊端,有两个,1是覆盖全局变量,2是引入所有垫片,用这种方式第一个缺点是无法解决的,但是我们可以通过配置browserlistrc来限制引入的方法,代码如下:
代码语言:javascript复制// .browserslistrc
Chrome > 75
这样转译是会根据chrome的版本来适量引入,而不是全部。
第三种方式,参数为useage,此时代码中用到谁就引入谁,比较智能。
代码语言:javascript复制{
"presets": [
["@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3
}
]
]
}
corejs指定polyfill的版本。
但是此时还有两个问题:api转译是全局引入,一些helper函数也是会在编译时重复生成,例如如下代码:
这样就会生成无数重复代码,咋办呢?
此时需要@babel/plugin-transform-runtime 与@babel/runtime-corejs3,其中 @babel/plugin-transform-runtime 的作用是转译代码,转译后的代码中可能会引入 @babel/runtime-corejs3 里面的模块。所以前者运行在编译时,后者运行在运行时。类似 polyfill,后者需要被打包到最终产物里在浏览器中运行。最终代码如下:
代码语言:javascript复制{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"debug": true
}
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3 // 指定 runtime-corejs 的版本,目前有 2 3 两个版本
}
]
]
}
再看转译后的代码:
从上图可以看到,在引入了 transform-runtime 这个插件后:api 从之前的直接修改原型改为了从一个统一的模块中引入,避免了对全局变量及其原型的污染,解决了第一个问题,helpers 从之前的原地定义改为了从一个统一的模块中引入,使得打包的结果中每个 helper 只会存在一个,解决了第二个问题
babel 在转译的过程中,对 syntax 的处理可能会使用到 helper 函数,对 api 的处理会引入 polyfill。
默认情况下,babel 在每个需要使用 helper 的地方都会定义一个 helper,导致最终的产物里有大量重复的 helper;引入 polyfill 时会直接修改全局变量及其原型,造成原型污染。
@babel/plugin-transform-runtime 的作用是将 helper 和 polyfill 都改为从一个统一的地方引入,并且引入的对象和全局变量是完全隔离的,这样解决了上面的两个问题。
@babel/plugin-transform-runtime需要与@babel/runtime、@babel/runtime-corejs3结合使用。
以上便是babel使用时的一些注意事项,希望对你有所帮助。
参考:https://zhuanlan.zhihu.com/p/147083132
https://segmentfault.com/a/1190000021188054