什么是 Babel
Babel 是一个 ECMAScript 编译器,可以将新一代的 ES 语法转为旧一代的 ES 语法,甚至是转换 ES 的超集语言(如 jsx, typescript 等)为 ECMAScript 代码。
截止发稿日期,Babel 的版本号为 7.4.x。在没有特殊说明的情况下,我将在此版本上进行介绍。
目前,所有的 Babel 7.x 版本的官方 npm 包都在 @babel 命名空间下。
常用 Babel 包及说明
@babel/coreBabel的核心组件,只要使用Babel就必须要安装此npm包。@babel/cliBabel的终端命令,如果想在终端中调用babel命令,需要安装此npm包。@babel/nodeBabel的交互式解释器,此包中带有babel-node命令,此命令可以像node一样使用,但在实际使用前会先进行代码转换。
但是,在babel-node中不支持let和const。@babel/register
在node中直接采用新的语法书写执行时,用于注册Require hook的npm包。@babel/plugin-*@babel/plugin-*为Babel的语法支持插件,主要包含下列三类:@babel/plugin-transform-*@babel/plugin-proposal-*@babel/plugin-syntax-*
三者的主要区别是:
@babel/plugin-syntax-*只提供给Babel的支持,但不提供转换,剩余两者都提供转换。@babel/plugin-transform-*是对ECMAScript中已定义的语法及超集语言的转换,而@babel/plugin-proposal-*是对草案中提到的语法进行转换,换句话说,@babel/plugin-proposal-*转换的语法,不能保证以后规则不会变。- 但如果转换插件是在草案阶段实现的,且称为
ECMAScript的标准语法后,实现没有改变,插件可能仍然保留@babel/plugin-proposal-*命名而不改变。
@babel/preset-*Babel的预置配置,不通的配置一般包含有不同的插件,并进行了适当地设置。Babel的预置配置使用最多的是@babel/preset-env,有较多的配置项,,常用选项按照选项名: 类型 = 默认值的格式给出:targets:string | Array<string> | { [string]: string }={}
描述您为项目支持/定位的环境, 如:"> 0.25%, not dead",{ "chrome": "58", "ie": "11" }, 默认情况下将转换所有ECMAScript 2015+代码modules:"amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false="auto"
启用将ES6模块语法转换为其他模块类型。 将此设置为false不会转换模块。 另请注意,这cjs只是一个别名commonjs。
其余选项可参考@babel/preset-env的选项
使用 Babel
配置及配置文件
配置为一个 object 对象,其主要有以下两个属性:
plugins: 插件列表,Array 类型。
每一项为一个插件,可以是以下几种格式'插件名称',直接为插件的名称,如@babel/plugin-transform-react-jsx, 如果插件名称以babel-plugin-开头,可以将其省略,如babel-plugin-my-plugin可以省略为my-plugin['插件名称', { /* 选项 */ }],使用插件,并设置选项pluginObject,使用插件对象,一般通过require导入的插件[pluginObject, { /* 选项 */ }],使用插件,并设置选项
插件会按照在列表中的顺序,被依次应用
presets: 预设列表,Array 类型。
每一项为一个预设,可以是以下几种格式'预设名称',直接为预设的名称,如@babel/preset-transform-react-jsx, 如果预设名称以babel-preset-开头,可以将其省略,如babel-preset-my-preset可以省略为my-preset['预设名称', { /* 选项 */ }],使用预设,并设置选项presetObject,使用预设对象,一般通过require导入的预设[presetObject, { /* 选项 */ }],使用预设,并设置选项
预设会按照在列表中的反向顺序,被依次应用。
预设会在插件之后引用。
根据使用的场景不同,可能需要将配置单独写入到配置文件中
Babel 目前支持两种配置文件:
.babelrc其本质为 JSON5 文件,其内容作为配置babel.config.js其本质为 nodejs 的 commonjs 模块文件,其导出作为配置
附 babel 配置举例
module.exports = {
plugins: [
'@babel/plugin-proposal-async-generators',
'@babel/plugin-proposal-async-to-generator',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-do-expressions',
'@babel/plugin-proposal-function-bind',
'@babel/plugin-proposal-logical-assignment-operators',
'@babel/plugin-proposal-numeric-separator',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-optional-catch-binding',
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-private-methods',
'@babel/plugin-proposal-throw-expressions',
['@babel/plugin-transform-typescript', {isTSX: true, jsxPragma: 'createElement'}],
['@babel/plugin-transform-react-jsx', {pragma: 'createElement', throwIfNamespace: false}],
]
};
在终端中进行编译
需要配置好配置文件,并安装以下两个必须的 npm 包及其他用到的插件及预置等:
@babel/core@babel/cli
之后可以使用 babel 命令进行编译,我一般会在 package.json 中配置命令,如下:babel src --out-dir lib -x .ts,.tsx -s
其中:
src为要编译的文件(或要编译文件所在的目录)--out-dir lib为设置编译结果的输出目录,其中 lib 为输出目录。如果是编译一个文件怎用--out outFileoutFile 为输出文件-x .ts,.tsx设置要编译的文件后缀,默认情况下只编译.es6,.js,.es,.jsx,.mjs五种后缀的文件,这里我还希望编译.ts,.tsx,所以我还使用了此选项-s选项表示生成独立的.map文件,便于后期调试
在终端中采用交互式执行
需要配置好配置文件,并安装以下两个必须的 npm 包及其他用到的插件及预置等:
@babel/core@babel/node
之后可以使用 babel-node 命令交互式执行,如果需要支持 .es6,.js,.es,.jsx,.mjs 五种后缀以为的文件通过 require 导入,需要使用 -x 选项,使用方式同 babel 命令
在 node 上下文中使用
需要配置好配置文件,并安装以下两个必须的 npm 包及其他用到的插件及预置等:
@babel/core@babel/register
之后在 node 的入口文件第一行前插入 require('@babel/register'); 如果是采用 ES6 的 import, 则是 import '@babel/register';
在 node 中调用 babel 进行转换
只需要安装 @babel/core,之后按照如下格式执行即可:require('babel-core').transform('code', options);
其中:
'code'是要转换的代码options是要 babel 的配置
常用 Babel 语法转换插件
以下按照 ES6+ 的常用特性及变成语言罗列,后面附相关插件,其中若未附带@babel/plugin-syntax-*且未特别说明则表示 Babel 默认支持此类语法的解析,部分后面附有常用选项,常用选项按照 选项名: 类型 = 默认值 的格式给出。
- 其他语言
这一组插件,主要是将其他扩展于ECMAScript的语言转换成ECMAScript。jsx@babel/plugin-syntax-jsx@babel/plugin-transform-react-jsx
常用选项:pragma:string="React.createElement"编译JSX表达式时使用的渲染函数pragmaFrag:string="React.Fragment"替换编译JSX片段时使用的组件useBuiltIns:boolean=false展开属性时,使用Object.assign,而不是使用Babel提供的函数throwIfNamespace:boolean=true使用XML命名空间标记名称时,是否抛出错误
typescript
Babel 只会移除 Typescript 中的类型和未使用的引入的包,所以不会加载tsconfig.json不支持namespace、const enum、export =、import =等,且不能生成.d.ts文件@babel/plugin-syntax-typescript@babel/plugin-transform-typescript
常用选项:isTSX:boolean=false是否为TSX,如果采用TSX则不支持<type>variable形式的断言。如果未采用TSX则不能与TSX相关的插件共同使用jsxPragma:string="React"编译TSX表达式时使用的渲染函数所属的变量。
- Module 转换
这一组插件,主要用于将ECMAScript模块转换为其他类型的模块。 - 语法糖
这一组插件针对的特性,一般被称为语法糖,除非转换后的语法需要版本要求,一般可以放心使用。ES2015箭头函数p => r@babel/plugin-transform-arrow-functionsES2015块级作用域与let/const@babel/plugin-transform-block-scoping
常用选项throwIfClosureRequired:boolean=false碰到无法转换的情况时抛出错误
ES2015类class C{ /* ... */ }@babel/plugin-transform-classesES2015解构var [, b, c, d , ...other] = array,var {a , b: c } = obj@babel/plugin-transform-destructuring
常用选项:useBuiltIns:boolean=false展开属性时,使用Object.assign,而不是使用Babel提供的函数
ES2015参数解构function({a, b: c}, [d, e, ...f], ...g) { /* ... */ }@babel/plugin-transform-parametersES2015展开运算var a = [b, c, ...d, e],f(b, c, ...d, e)@babel/plugin-transform-spread
常用选项:loose:boolean=false是否将所有要类似数组展开的变量均按照普通数组方式展开
ES2015简写属性var a = { b, c, d}@babel/plugin-transform-shorthand-propertiesES2015计算属性var a = {[x + y] : z}@babel/plugin-transform-computed-propertiesES2015模板字符串`${a}+${b}=${a+b}`@babel/plugin-transform-template-literalsES2015字面量0o23,0b101,0b101,'Hello\u{000A}\u{0009}!'@babel/plugin-transform-literalsES2015生成器函数function *f() { /* ... */ }@babel/plugin-transform-regeneratorES2016幂运算符a ** b@babel/plugin-syntax-exponentiation-operator@babel/plugin-transform-exponentiation-operatorES2017异步函数async function f() { /* ... */ }@babel/plugin-syntax-async-functions@babel/plugin-transform-async-to-generatorES2018异步生成器函数async function* f() { /* ... */ }@babel/plugin-syntax-async-generators@babel/plugin-proposal-async-generator-functionsES2018可选 catch 绑定try { /* ... */ } catch { /* ... */ }@babel/plugin-syntax-optional-catch-binding@babel/plugin-proposal-optional-catch-bindingES2018对象解析赋值var { x, y, ...z } = obj@babel/plugin-syntax-object-rest-spread@babel/plugin-proposal-object-rest-spread
常用选项:useBuiltIns:boolean=false展开属性时,使用Object.assign,而不是使用Babel提供的函数
草案类属性class { prop = 'value'; }@babel/plugin-syntax-class-properties@babel/plugin-proposal-class-properties草案do 表达式do {/* ... */ }@babel/plugin-syntax-do-expressions@babel/plugin-proposal-do-expressions草案export default fromexport name from 'mod'@babel/plugin-syntax-export-default-from@babel/plugin-proposal-export-default-from草案export namespace fromexport * as name from 'mod'@babel/plugin-syntax-export-namespace-from@babel/plugin-proposal-export-namespace-from草案绑定运算符obj::func,obj::func(),::obj.func,::obj.func()@babel/plugin-syntax-function-bind@babel/plugin-proposal-function-bind草案逻辑赋值运算符a ||= b,a &&= b@babel/plugin-syntax-logical-assignment-operators@babel/plugin-proposal-logical-assignment-operators草案空结合运算符a ?? b@babel/plugin-syntax-nullish-coalescing-operator@babel/plugin-proposal-nullish-coalescing-operator草案数字分隔符12_3456_7890@babel/plugin-syntax-numeric-separator@babel/plugin-proposal-numeric-separator草案数字分隔符12_3456_7890@babel/plugin-syntax-numeric-separator@babel/plugin-proposal-numeric-separator草案可选链运算符a?.b@babel/plugin-syntax-optional-chaining@babel/plugin-proposal-optional-chaining草案局部应用f(?, p1, p2),f(p0, ?, p2),f(p0, p1, ?),?.f(p0, p1, p2)@babel/plugin-syntax-partial-application@babel/plugin-proposal-partial-application草案管道运算符a |> f@babel/plugin-syntax-pipeline-operator@babel/plugin-proposal-pipeline-operator草案类的私有方法class C{ #method() { /* ... */ }}
类的私有方法暂时单纯的私有方法@babel/plugin-proposal-private-methods草案throw 表达式throw error@babel/plugin-syntax-throw-expressions@babel/plugin-proposal-throw-expressions
- 底层实现
这一组插件,转换后可以运行在低版本平台上,但可能会丧失部分功能,如正则表达式的修饰符。ES2015for-of 循环for (var val of variable) { /* ... */ }@babel/plugin-transform-for-of
常用选项:assumeArray:boolean=false是否假定所有被循环对象均为数组
ES2015typeof symboltypeof variable === 'symbol'@babel/plugin-transform-typeof-symbolES2015正则表达式 Unicode 模式修饰符u@babel/plugin-transform-unicode-regexES2018正则表达式 dotAll 模式修饰符s@babel/plugin-transform-dotall-regexES2018正则表达式命名捕获组@babel/plugin-transform-named-capturing-groups-regexES2018正则表达式 Unicode 特性项@babel/plugin-proposal-unicode-property-regex
常用属性:runtime:boolean=true开启此选项时,将需要最低的ES2015的正则表达式支持;禁用此选项时,需要导入适当的polyfill,但输出不仅支持捕获组命名。