Babel是什么
官网:Babel 是一个工具链,主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。一般都是和webpack配合使用
使用
安装
npm install @babel/core @babel/cli @babel/preset-env -D
@babel/core
Babel 的核心功能包含在 @babel/core 模块中,所有的转译都将使用本地配置文件。
配置文件
Babel 有两种并行的配置文件格式,可以一起使用,也可以独立使用。
- 全项目配置
babel.config.json文件,具有不同的扩展名 ( .js, .cjs, .mjs)
Babel 7.x是新的,Babel有一个“根”目录的概念,默认为当前工作目录。对于项目范围的配置,Babel将在此根目录中自动搜索babel.config.json文件,或使用受支持扩展名的等效文件 - 文件相关配置
.babelrc.json文件,具有不同的扩展名 ( .babelrc, .js, .cjs, .mjs)或者package.json里设置babel字段
Babel通过从正在编译的“文件名”开始搜索目录结构(受以下注意事项限制)来加载.babelrc.json文件,或使用受支持扩展名的等效文件
一旦找到包含package.json的目录,搜索将停止,因此相对配置仅适用于单个软件包
配置文件示例
{
"presets": [
[
"@babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3.6.5"
}
]
]
}
@babel/cli
@babel/cli 是一个能够从终端(命令行)使用的工具。可以通过 --help 参数来查看命令行工具所能接受的所有参数列表
npx babel src --out-dir dist
上面命令表示将src目录下所有的js文件进行转译,然后输出到dist文件夹下
插件和预设(preset)
Babel的代码转换是通过将插件(或预置)应用于配置文件来实现的。代码转换功能以插件的形式出现,插件是小型的 JavaScript 程序,用于指导 Babel 如何对代码进行转换。
预设(preset)
预设是指预先在babel内部设置好的插件,可以直接使用
官方提供的预设
- @babel/preset-env 用于编译 ES2015+ 语法
- @babel/preset-typescript for TypeScript 编译ts,替代了ts-loader
- @babel/preset-react for React
- @babel/preset-flow for Flow
使用预设
在配置文件中添加presets字段,该字段是一个数组,执行顺序是从右到左
{
"presets": ["@babel/preset-env"]
}
@babel/preset-env 的使用
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"ie": "8",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3.26.0"
}
]
]
}
targets
是需要兼容的浏览器版本 可以用这些属性 android, chrome, deno, edge, electron, firefox, ie, ios, node, opera, rhino, safari, samsung
也可以设置成一个string,比如 > 0.5%, last 2 versions, not dead
意思是有大于百分之零点五的人使用,前两个版本,并且没有废弃
useBuiltIns
有几个值
false
默认值,不做任何语法转换usage
Babel 将检查你的所有代码,以便查找targets
环境中缺失的功能,然后只把必须的 polyfill 包含进来entry
引入所有的polyfill包,必须在入口文件加入import "core-js/stable"
才会生效
使用useBuiltIns
useBuiltIns 需要搭配 core-js,并且需要在配置文件里面声明。目前core-js最新版本是3.x,也可以指定2.x,这里用最新版本
npm i core-js -S
先用usage
看下
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"ie": "8",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage", // 用usage
"corejs": "3.26.0" // 配置了useBuiltIns ,corejs必须要配置,不然不生效,值是刚才安装core-js的版本号
}
]
]
}
编译index.js 文件
运行
npx babel index.js --out-dir babel
可以看到编译到了babel/index.js,const
编译成了var
,class
语法也编译了,并且引入了对应的polyfill包
用entry
看下
"useBuiltIns": "entry", // 注意这里用entry,其他的不变
index.js需要加上 import 'core-js/stable'
重新编译下,看编译后的结果
不配置useBuiltIns和corejs
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"ie": "8",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
}
}
]
]
}
编译下
因为兼容了ie8,所以一些语法 const
class
箭头函数编译了,针对API promise
并没有引入polyfill包
上面的编译可以看到这几行,创建了三个函数
这是对class
语法对转译,这几个函数可以称为辅助函数,如果有好几个文件用了这个语法,那么每个编译的js文件都会有这几个辅助函数,js体积肯定会增大。解决方法是可以把辅助函数提取出来,哪里需要的话引用就好。@babel/runtime
这个包实现了这个功能,它包含了所有的辅助函数。
@babel/preset-env 是直接修改原型上的方法,例如 Array.from 等静态方法,直接在 Array 上添加;对于例如 includes 等实例方法,直接在 Array.prototype 上添加。项目中这么使用是没问题的,但如果代码是打算发布供其他人使用的库,或者无法完全控制代码将在其中运行的环境,会污染全局范围。
想要解决上面说的问题,可以使用@babel/runtime
搭配@babel/plugin-transform-runtime
插件
npm i @babel/plugin-transform-runtime -D
npm i @babel/runtime -S
在babel.config.json中
{
// 其它配置不变
"plugins": ["@babel/plugin-transform-runtime"] // 使用 @babel/plugin-transform-runtime
}
编译看下
可以看到辅助函数是从插件引入进来的。提取辅助函数解决了,全局污染的问题需要如下操作
安装 @babel/runtime-corejs3 包,和core-js 包的区别是不会污染全局,安装了@babel/runtime-corejs3就不需要安装@babel/runtime
npm install --save @babel/runtime-corejs3
在babel.config.json中
{
// 其它配置不变
"plugins": [["@babel/plugin-transform-runtime", { "corejs": 3 }]] // 配置 corejs
}
创建预设
自定义预设需要导出配置对象,只能返回一系列插件
module.exports = function() {
return {
plugins: ["pluginA", "pluginB", "pluginC"],
};
};
// 也可以包含其他预设和带选项的插件
module.exports = () => ({
presets: [require("@babel/preset-env")],
plugins: [
[require("@babel/plugin-proposal-class-properties"), { loose: true }],
require("@babel/plugin-proposal-object-rest-spread"),
],
});
预设选项
插件和预置都可以通过将名称和选项对象包装在配置内的数组中来指定选项。
对于不指定选项,这些都是等价的:
{
"presets": [
"presetA", // bare string
["presetA"], // wrapped in array
["presetA", {}] // 2nd argument is an empty options object
]
}
要指定选项,请传递以键作为选项名称的对象
{
"presets": [
[
"@babel/preset-env",
{
"loose": true,
"modules": false
}
]
]
}