
本文旨在解答关于是否可以使用 TypeScript/JavaScript 编写 SWC 插件的疑问。虽然 SWC 官方文档主要介绍 Rust 编写插件的方式,但实际上,通过操作抽象语法树 (AST),可以在一定程度上实现插件逻辑。本文将提供代码示例,展示如何利用 SWC 的 parse 和 transform API 修改 AST,从而达到插件效果。
虽然 SWC 官方提供的插件系统主要面向 Rust 开发者,但并非完全无法使用 TypeScript/JavaScript 实现插件的某些功能。 关键在于理解和利用 SWC 的 parse 和 transform API,通过操作抽象语法树 (AST) 来实现自定义的转换逻辑。
AST 操作实现插件逻辑
SWC 的核心工作流程是将代码解析为 AST,然后对 AST 进行转换,最后将转换后的 AST 生成代码。 我们可以通过以下步骤实现插件逻辑:
立即学习“Java免费学习笔记(深入)”;
- 解析代码为 AST: 使用 swc.parse() 函数将源代码解析为 AST。
- 修改 AST: 在 AST 上进行自定义的修改,实现插件的转换逻辑。
- 将 AST 转换为代码: 使用 swc.transform() 函数将修改后的 AST 转换为代码。
示例代码
以下示例代码展示了如何使用 TypeScript 修改 AST,将 TypeScript 文件中的 .ts 扩展名替换为 .js。
import swc from '@swc/core'
let source = `
import abc from './abc.ts'
import abc from "./def.mts"
import('./abc.ts')
import('./def.cts')
`
async function transformCode(sourceCode: string) {
let program = await swc.parse(sourceCode, {
syntax: 'typescript',
comments: false,
script: true,
target: 'esnext',
});
// 插件逻辑:修改 ImportDeclaration 节点的 source 属性
for (let item of program.body) {
if (item.type === 'ImportDeclaration') {
if (item.source.value.endsWith('.ts')) {
item.source.value = item.source.value.replace('.ts', '.js');
item.source.raw = item.source.raw.replace('.ts', '.js'); // Also update raw for accurate representation
}
}
}
const transformed = await swc.transform(program, {
jsc: {
minify: {
// known bugs, don't use.
// compress: {},
mangle: {},
},
target: 'esnext',
},
});
return transformed.code;
}
async function main() {
const transformedCode = await transformCode(source);
console.log(transformedCode);
}
main();代码解释:
- swc.parse(source, options): 将 TypeScript 代码解析为 AST。 options 对象指定了语法、目标环境等配置。
- 遍历 program.body: program.body 包含了 AST 的顶层节点。 我们遍历这些节点,寻找 ImportDeclaration 类型的节点。
- 修改 item.source.value 和 item.source.raw: 对于 ImportDeclaration 节点,我们修改 source.value 和 source.raw 属性,将 .ts 替换为 .js。 raw 属性表示原始字符串,value 属性表示解析后的字符串。 同时修改两者可以保证 AST 的一致性。
- swc.transform(program, options): 将修改后的 AST 转换回代码。 options 对象指定了转换的配置,例如目标环境、是否进行代码压缩等。
注意事项:
- AST 的复杂性: AST 结构比较复杂,需要一定的学习成本才能熟练操作。
- 类型安全: 在 TypeScript 中操作 AST 时,需要确保类型安全,避免运行时错误。
- 性能: AST 操作可能会影响性能,需要进行优化。
- 兼容性: SWC 的 AST 结构可能会发生变化,需要关注 SWC 的更新,并及时调整代码。
- 局限性: 这种方式无法实现所有类型的插件逻辑。 某些高级功能,例如代码生成,可能需要使用 Rust 插件才能实现。
总结
虽然不能直接使用 TypeScript/JavaScript 编写完整的 SWC 插件,但通过操作 AST,我们仍然可以使用 TypeScript/JavaScript 实现部分插件逻辑。 这种方式适用于简单的代码转换和修改。 对于更复杂的需求,建议考虑使用 Rust 编写插件。 在使用 AST 操作时,需要注意 AST 的复杂性、类型安全、性能和兼容性。 此外,也要认识到这种方式的局限性。










