Babel作为构建工具广泛采取的Javascript编译器,其转换编译、静态类型检查、动态polyfill等功能通过编写自定义插件来满足特定业务需求是工程化进阶必学知识点,此文章主要记录babel内置功能包和插件的使用
预设
预设是指根据配置加载对应插件的特定配置集合,每个预设在进行语法解析时会分别加载对应的转换插件而不用手动安装很多插件并配置
babelpreset-react
babelpreset-flow
babelpreset-typescript
babelpreset-env
此预设是在开发中最常用的,包含了 ES3-ES2022 的所需插件,通常设置presets > useBuiltIns: "usage"搭配core-js实现动态polyfill
{
"targets": "> 0.25%, not dead",
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": "3"
}
]
]
}
<Callout>useBuiltIns默认为false,可使用usage和entry.usage时会根据当前浏览器targets支持注入polyfill,entry标识需要像老版本一样手动引入@babel/polyfill相对比较繁琐</Callout>
集成包
和工具包绑定使用的功能包,从Babel7以后所有单包的使用都需要提前安装@babel/core
babelcli
多用于命令行操作
pnpm add @babel/core @babel/cli
// 文件内容输出到stdout
npx babel src/index.js
// 文件编译输出
npx babel src/index.js -o dist/index.js
// 整个目录编译输出(-d: --dir)
npx babel src -d dist
// 编译附带sourcemap(-s: --sourcemap)
npx babel src/index.js -o dist/index.js -s
附带参数如下:
- <Primary>--extensions</Primary>
.ts,.js,.tsx,.jsx,.cjs,.mjs指定babel要处理的文件后缀 - <Primary>--ignore</Primary>
src/**/*.test.js指定babel要忽略的文件后缀 - <Primary>--copy-files</Primary> 复制文件,默认不复制被
--ignore忽略的文件可以通过--no-copy-ignored禁止 - <Primary>--no-babelrc</Primary> 指定不使用
.babelrc或.babelrc.json配置文件 - <Primary>--config-file</Primary> 指定配置文件路径
- <Primary>--out-file-extension</Primary>
.mjs指定输出文件后缀 - <Primary>--keep-file-extension</Primary> 指定保留原有文件后缀
- <Primary>--presets</Primary>
=@babel/preset=typescript,...指定babel要应用的预设 - <Primary>--plugins</Primary>
=@babel/proposal-class-properties,...指定babel要应用的插件
使用npm script
{
"scripts": {
"build:dir": "pnpm babel src -d dist"
}
}
babelregister
结合require钩子将babel注册到Node模块系统中并自动编译文件,在最细版本可以使用实验性功能 experimental-worker 替换
pnpm add @babel/core @babel/register
console.log('this is index.js')
require('@babel/register')({
plugins: [],
presets: []
})
// 后续所有的引入都将会被babel编译
require('./index.js')
node register.js
// console.log('this is index.js')
babelpolfill
v7已弃用,推荐@babel/transform-runtime搭配@babel/runtime复用帮助函数减少代码体积
babelruntime
包含了babel运行时所需的帮助函数被@babel/transform-runtime按需注入
babeltransform-runtime
此转换插件主要做了3件事:
- 使用
core-js配置选项是否自动注入对应polyfill - 使用
helpers配置选项是否自动注入对应@babel/runtime/helpers来替代行内帮助函数 - 使用
regenerator配置选项指定是否自动注入@babel/runtime/renerator来转换generator/async语法
{
"targets": "> 0.25%, not dead",
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3,
"helpers": true,
"regenerator": true
}
]
]
}
var sym = Symbol();
var promise = Promise.resolve();
var check = arr.includes("yeah!");
console.log(arr[Symbol.iterator]());
// 转换后
import _getIterator from "@babel/runtime-corejs3/core-js/get-iterator";
import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
import _Promise from "@babel/runtime-corejs3/core-js-stable/promise";
import _Symbol from "@babel/runtime-corejs3/core-js-stable/symbol";
var sym = _Symbol();
var promise = _Promise.resolve();
var check = _includesInstanceProperty(arr).call(arr, "yeah!");
console.log(_getIterator(arr));
babelstandalone
独立适用于浏览器和非node环境,不推荐生产环境使用。暂略
工具包
babelcore
多用于函数式变成方式操作都包含同/异步形式,所有转换操作将使用 本地配置文件
const babel = require('@babel/core')
const codeStr = `
function foo(a, b) {
return a + b;
}
`
代码转换
/**
* @param code: string, options?: Object, callback: Function
*/
babel.transform(codeStr, { babelrc: true }, (err, result) => {
console.log(result); // { configOoptions, code, map, ast }
})
// 异步形式
babel.transformAsync(codeStr, { babelrc: true }).then(result => {
console.log(result); // { configOoptions, code, map, ast }
})
文件转换
根据传入文件路径进行编译
const indexJs = path.resolve(__dirname, './index.js')
const fileResult = babel.transformFileSync(indexJs, {})
console.log(fileResult)
babel.transformFile(indexJs, {}, (err, result) => {
//...
})
代码解析
根据传入代码字符串返回对应ast
// babel.parse
const astSyncRes = babel.parseSync(codeStr)
console.log(astSyncRes) // ast
babel.parse(codeStr, {}, (err, res) => {
// do somthing with ast
})
ast转换
const parseAst = babel.parseSync(codeStr, {})
babel.transformFromAst(parseAst, codeStr, {}, (err, res) => {
const { code, map, ast } = res;
})
const astTransform = babel.tansformFromAstSync(parseAst, codeStr, {})
console.log(astTransform)
babel.parseAsnyc(codeStr)
.then(parseAst => {
return transformFromAstAsync(parseAst, codeStr, {})
})
.then(({ code, map, ast }) => {
//...
})
babelparser
根据源码转换ast
import { parse } from "@babel/parser"
const source = `
function foo() {
console.log(222)
}
`
console.log(parse(source, { sourceType: 'module' }))
babelgenerator
根据ast转换代码
import { parse } from "@babel/parser"
import generate from "@babel/generator"
const source = `
function foo() {
console.log(222)
}
`
const ast = parse(source, {
sourceType: 'module'
})
console.log(generate(ast, {}, source));
babelcode-frame
获取源码中的具体位置,一般用于错误抛出具体位置
import { codeFrameColumns } from "@babel/code-frame"
const rawLines = `class Foo {
constructor() {
console.log("hello");
}
}`
const location = { start: { line: 2, column: 16 } }
const result = codeFrameColumns(rawLines, location, {
/* options */
})
console.log(result)
babeltemplate
用于操作字符串模版和对应类型ast生成,暂略
babeltraverse
结合parser遍历和更新节点,暂略
babeltypes
各种访问及断言方法的工具库,暂略