Appearance
Babel 的原理
Babel 是一个 JavaScript 编译器,其提供对于 ES6 语法编写的代码转换成向后兼容的 JS 语法,从而可以运行的旧的环境或者浏览器中
其主要流程分为三个步骤: Parser 解析 -> 转换(transform) -> generate(生成)
在解析的流程中一般分为两个步骤: 语法分析 和 词法分析
- Parser 解析
在解析的过程中,通过分词将代码分为 空格、注释、字符串、数字、标识符、括号等,同时在词法分析的过程中对其进行语法分析从而构建成一个 AST 语法树。
- transform
这个阶段主要是通过一个个插件将上面的 AST 语法书按照对应的要求进行转换、删减、报错等
- generate
最后将转换后的 AST 语法树转换成源代码
@babel/core
babel 的核心提供 babel 整个转换流程的控制
@babel/preset-env
其是根据配置的目标环境或者开发框架提供对应的插件集合
- @babel/preset-react
- @babel/preset-typescript
json
{
"presets": [
[
"@babel/preset-env",
{
// 指定兼容的浏览器版本
"targets": {
"ie": "11"
},
// 基础库 core-js 的版本,一般指定为最新的大版本
"corejs": 3,
// Polyfill 注入策略
"useBuiltIns": "usage",
// 不将 ES 模块语法转换为其他模块语法
"modules": false
}
]
]
}targets : 这是根据 broswerlist 的写法,表示兼容 ie11。而 ie11 是不支持 Object.entries 这个 api 与箭头函数语法的,所以我们要通过@babel/preset-env 去转换。更多浏览器版本兼容写法可以参考 browserslist
corejs: 3, 表示使用哪个版本的 corejs 进行 polyfill, 可选值 2、3、false;其中版本 2 会有一些在原型上的 api 缺失,比如 Array.prototype.includes(),false 就是不进行 polyfill,这明显不符合我们的预期。
"useBuiltIns": "usage", 表示按需加载 polyfill, 比如上面我只用到了 Object.entries,那么打包时就只把这个 Object.entries 的 polyfill 注入到全局 window 上面,其他没有用到 polyfill 就不注入,大大减少打包后 bundle 的体积。
"modules": false ,意思是不将 ES 模块语法转换为其他模块语法,可选值有 'commonjs', 'amd', 'umd', 'systemjs' 'auto' ,我的 index.js 的写法是 esm 写法,这里 false 关闭就是保持 esm 写法,不然就会自动给你转 commonjs 写法。
其中一个最大的问题就是 preset-env 中 useBuildIns 配置的按需加载 polyfill 是会注入到全局的 window 上面的, 所以如果我们不需要全局注入那就使用
@babel/plugin-transform-runtime
json
{
"plugins": [
// 添加 transform-runtime 插件
[
"@babel/plugin-transform-runtime",
{
"corejs": 3
}
]
],
"presets": [
[
"@babel/preset-env",
{
"targets": {
"ie": "11"
},
"corejs": 3,
// 关闭 @babel/preset-env 默认的 Polyfill 注入
"useBuiltIns": false,
"modules": false
}
]
]
}