Babel内容总览:
- 以Babel为例,讲述插件的机制 (本期)
- 以Babel为例,讲述浏览器的兼容性
Babel 是一个 JavaScript 编译器
Babel 是一个工具链,主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。下面列出的是 Babel 能为你做的事情:
- 语法转换
- 通过 Polyfill 方式在目标环境中添加缺失的功能(通过引入第三方 polyfill 模块,例如 core-js)
- 源码转换(codemods)
Babel 和 AST 的关系
- 核心关系:Babel 通过生成和操作 AST 来实现代码的转换和编译。AST 作为 Babel 处理代码的中间表示,是 Babel 工作流程中不可或缺的一部分。
- 插件系统:Babel 的强大之处在于其插件系统,这些插件通过分析和修改 AST 来实现具体的语法转换和优化。开发者可以根据需要选择或创建插件,以支持新的语言特性或实现特定的编译任务。
AST 抽象语法树定义
webpack和Vite等很多的工具和库的核心都是通过Abstract Syntax Tree抽象语法树这个概念来实现对代码的检查、分析等操作的,这些工具的原理都是通过JavaScript Parser把代码转化为一颗抽象语法树(AST),这颗树定义了代码的结构,通过操纵这颗树,我们可以精准的定位到声明语句、赋值语句、运算语句等等,实现对代码的分析、优化、变更等操作
在计算机科学中,抽象语法树(abstract syntax tree或者缩写为AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。
Javascript的语法是为了给开发者更好的编程而设计的,但是不适合程序的理解。所以需要转化为AST来使之更适合程序分析,浏览器编译器一般会把源码转化为AST来进行进一步的分析等其他操作。
抽象语法树用途
- 代码语法的检查、代码风格的检查、代码的格式化、代码的高亮、代码错误提示、代码自动补全等等
- 如JSLint、JSHint对代码错误或风格的检查,发现一些潜在的错误
- IDE的错误提示、格式化、高亮、自动补全等等
- 代码混淆压缩
- UglifyJS2等
- 优化变更代码,改变代码结构使达到想要的结构
- 代码打包工具webpack、rollup等等
- CommonJS、AMD、CMD、UMD等代码规范之间的转化
- CoffeeScript、TypeScript、JSX等转化为原生Javascript
3.babel插件
- 访问者模式Visitor 对于某个对象或者一组对象,不同的访问者,产生的结果不同,执行操作也不同
- @babel/core Babel 的编译器,核心 API 都在这里面,比如常见的 transform、parse
- [@babel/parser] Babel 的解析器
- babel-types 用于 AST 节点的 Lodash 式工具库, 它包含了构造、验证以及变换 AST 节点的方法,对编写处理 AST 逻辑非常有用
- babel-traverse用于对 AST 的遍历,维护了整棵树的状态,并且负责替换、移除和添加节点
- babel-types-api
- Babel 插件手册
- babeljs.io babel可视化编译器
转换箭头函数
转换前
const sum = (a,b)=>a+b
转换后
var sum = function sum(a, b) {
return a + b;
};
let babel = require('@babel/core');
let t = require('babel-types');
const code = `const sum = (a,b)=>a+b`;
let transformArrowFunctions = {
visitor: {
ArrowFunctionExpression: (path) => {
let node = path.node;
let id = path.parent.id;
let params = node.params;
let body=t.blockStatement([
t.returnStatement(node.body)
]);
let functionExpression = t.functionExpression(id,params,body,false,false);
path.replaceWith(functionExpression);
}
}
}
const result = babel.transform(code, {
plugins: [transformArrowFunctions]
});
console.log(result.code);
Babel 在真实项目中遇到的问题有哪些 ?
{
test: /\.js$/, // 匹配 JavaScript 文件
exclude: /node_modules/, // 排除 node_modules 文件夹
use: {
loader: 'babel-loader', // 使用 babel-loader 转译 ES6/ES7 语法
options: {
cacheDirectory: true, // 开启缓存,提高编译速度
presets: [ // 预设环境
'@babel/preset-env', // 转译ES6+语法
{
useBuiltIns: 'usage', // 按需引入polyfill
corejs: 3, // 指定core-js版本
targets: { // 指定目标浏览器
chrome: '49', // 例如,Chrome 49版本
},
},
'@babel/preset-react', // 转译React JSX
'@babel/preset-typescript', // 支持TypeScript
],
plugins: [ // 插件列表
'@babel/plugin-proposal-nullish-coalescing-operator', // 支持空值合并运算符
'@babel/plugin-transform-optional-chaining', // 支持可选链式调用
],
},
},
}
我配置了兼容 可选链 了,但是打包后并没有进行编译,后来发现是因为读取了 tsconfig.json 文件的 target 属性
-
这里的
"esnext"指的是最新的ECMAScript标准的特性集,它包括了所有已经被ECMAScript标准委员会接受的最新特性,但可能还没有被所有浏览器或环境完全支持。使用esnext作为目标意味着编译器会尽可能地保留最新的语言特性,而不会转换为旧版本的ECMAScript标准。 -
选择
esnext作为目标可以让开发者使用最前沿的JavaScript特性,但同时也需要注意,这可能会导致在一些不支持这些最新特性的环境中出现兼容性问题。因此,在决定将target设置为esnext时,需要确保你的代码运行环境支持这些新特性,或者你已经有了相应的polyfill策略来填补缺失的功能。