Babel插件开发小试:支持模块化、代码复用化
一、解决上期问题
上期提到,如果用如下方式导出插件会报错:
1 | export default function ({ types: t }) { |
解决方式是在package.json
根对象下加入
1 | "type": "module" |
这样,所有.js
文件都会当作ES module
处理。如果想按CommonJS
处理,将文件扩展名改为.cjs
。同理,如果type
是commonjs
,所有ES module
文件的扩展名应为.mjs
。
注意,用ESM
引入CJS
模块时:
1 | // lib.js |
如果这样引用模块就会报错traverse
不是函数。因为这里引入的是整个exports
对象,所以需要如下写:
1 | import traverse from "./lib.js" |
这点我们后面会用到。
二、支持导入重载
1 | import { $operator as $ } from "./operator.js" |
现在会被编译为如下代码(如果$operator
重载了加法):
1 | import { $operator as $ } from "./operator.js" |
编译后重载对象的名称都是as
后面的名称,import
必须为具名导入,as
不是必需的,不能为:
1 | import $operator from "./operator.js" |
这与插件的工作原理有关。
三、导入的工作原理
1 | Program(path, state) { |
插件会先遍历import
语句,并判断import
进来的名字是不是babel
配置文件中配置的重载对象名operatorObjectName
。然后将$operator
所在的文件解析为绝对路径,用于后续读取。specifier.local.name
在有as
的情况下为as
后的值,没有则是原来的值,即specifier.imported.name
。
1 | import parser from "@babel/parser"; |
接下来读取$operator
所在的文件为字符串,并讲其解析为抽象语法树,然后遍历其抽象语法树,找到重载对象的声明并注册重载。
我们需要在Babel
配置文件中配置被读取的文件的编码,默认值为utf8
。
1 | "plugins": [["./plugin-operator/main.js", { "encoding": "utf8" }]] |
此处我们用到了两个Babel API
。parser.parse
读取字符串并将其解析为AST
,只有在第二个参数中传入sourceType: "module"
才能解析ESM
,否则会报错。
四、复用代码
注意到,本插件中所有的visitor
都哦有类似的如下结构:
1 | const operatorObjectParent = path.findParent((parentPath) => t.isVariableDeclaration(parentPath) && operatorObjName == parentPath.node.declarations?.[0].id.name); |
我们可以将这些代码提取出来以优化代码结构。每个visitor
都是一个函数,因此我们可以创建一个高阶函数,他接受一个函数replacement
,这是所有visitor
唯一不同的地方,并返回一个拥有相应replacement
的函数。
1 | const visitorFactory = (replacement) => (path) => { |
但只有这样是不够的,因为replacement
需要访问path
和operator
,所以我们需要将replacement
改成一个函数,将path
和operator
传递给他。
1 | const visitorFactory = (replacement) => (path) => { |
于是visitor
可以改造成这样:
1 | AssignmentExpression: visitorFactory((operator, path) => t.parenthesizedExpression( |
对于自增减,我们进行如下的特殊处理:
1 | if (path.node.prefix) { |
我们直接在这里操作抽象语法树节点,并返回节点自身,这样在visitorFacotry
中就不会再修改了。
- 标题: Babel插件开发小试:支持模块化、代码复用化
- 作者: Stone926
- 创建于 : 2024-11-17 18:38:15
- 更新于 : 2025-04-17 23:54:59
- 链接: https://stone926.github.io/2024/11/17/babel-plugin-operator2/
- 版权声明: 本文为公有领域作品,可自由转载、引用。