Rust宏插件库swc_plugin_macro的使用:SWC编译器自定义转换与代码生成宏工具
Rust宏插件库swc_plugin_macro的使用:SWC编译器自定义转换与代码生成宏工具
安装
在项目目录中运行以下Cargo命令:
cargo add swc_plugin_macro
或者在Cargo.toml中添加以下行:
swc_plugin_macro = "1.1.0"
使用示例
swc_plugin_macro是一个用于创建SWC编译器插件的宏库,允许开发者自定义代码转换逻辑。下面是一个完整的示例:
use swc_plugin_macro::plugin_module;
use swc_core::{
ecma::{
ast::*,
visit::{VisitMut, VisitMutWith},
},
plugin::{
metadata::TransformPluginMetadataContextKind,
plugin_transform,
},
};
// 定义一个简单的转换插件,将变量名"foo"重命名为"bar"
#[plugin_module]
pub fn transform(program: Program, _metadata: TransformPluginMetadataContextKind) -> Result<Program, String> {
let mut visitor = RenameVisitor;
program.visit_mut_with(&mut visitor);
Ok(program)
}
// 自定义访问器实现变量重命名
struct RenameVisitor;
impl VisitMut for RenameVisitor {
fn visit_mut_ident(&mut self, ident: &mut Ident) {
if ident.sym == "foo" {
ident.sym = "bar".into();
}
}
}
// 导出插件入口点
#[plugin_transform]
pub fn process_transform(program: Program, metadata: TransformPluginMetadataContextKind) -> Program {
transform(program, metadata).unwrap()
}
完整示例代码
以下是一个更完整的示例,展示了如何使用swc_plugin_macro创建自定义转换插件:
use swc_plugin_macro::{plugin_module, plugin_transform};
use swc_core::{
ecma::{
ast::*,
visit::{VisitMut, VisitMutWith},
},
plugin::metadata::TransformPluginMetadataContextKind,
};
// 主转换函数,使用plugin_module宏标记
#[plugin_module]
pub fn transform(
mut program: Program,
_metadata: TransformPluginMetadataContextKind
) -> Result<Program, String> {
// 创建自定义访问器实例
let mut visitor = CustomVisitor::new();
// 遍历并修改AST
program.visit_mut_with(&mut visitor);
Ok(program)
}
// 自定义访问器结构体
struct CustomVisitor;
impl CustomVisitor {
fn new() -> Self {
CustomVisitor
}
}
// 实现VisitMut trait来修改AST
impl VisitMut for CustomVisitor {
// 处理标识符
fn visit_mut_ident(&mut self, ident: &mut Ident) {
if ident.sym == "old_name" {
ident.sym = "new_name".into();
}
}
// 处理函数声明
fn visit_mut_function(&mut self, func: &mut Function) {
// 先处理子节点
func.visit_mut_children_with(self);
// 修改函数名
if let Some(ident) = &mut func.ident {
if ident.sym == "old_function" {
ident.sym = "new_function".into();
}
}
}
}
// 插件入口点,使用plugin_transform宏标记
#[plugin_transform]
pub fn process_transform(
program: Program,
metadata: TransformPluginMetadataContextKind
) -> Program {
transform(program, metadata).unwrap()
}
主要功能
#[plugin_module]
宏:简化SWC插件模块的创建#[plugin_transform]
宏:提供插件转换的入口点- 与SWC编译器生态无缝集成
- 支持自定义AST转换逻辑
许可证
Apache-2.0
1 回复
Rust宏插件库swc_plugin_macro的使用:SWC编译器自定义转换与代码生成宏工具
介绍
swc_plugin_macro
是一个用于为SWC编译器创建自定义转换插件的Rust宏库。SWC是一个用Rust编写的超快速TypeScript/JavaScript编译器,而swc_plugin_macro
允许开发者通过Rust宏来扩展SWC的功能,实现自定义的代码转换和生成。
这个库特别适合需要:
- 自定义JavaScript/TypeScript代码转换
- 实现特定领域的代码优化
- 开发自定义的代码生成工具
- 创建编译时的元编程功能
使用方法
基本安装
首先,在Cargo.toml中添加依赖:
[dependencies]
swc_plugin_macro = "0.2"
swc_core = { version = "0.82", features = ["ecma_plugin_transform"] }
创建基本插件
use swc_plugin_macro::plugin_transform;
use swc_core::ecma::ast::*;
use swc_core::ecma::visit::VisitMut;
#[plugin_transform]
pub fn process_transform(program: Program, _plugin_config: String) -> Program {
// 这里实现你的转换逻辑
program
}
示例:转换所有标识符为大写
use swc_plugin_macro::plugin_transform;
use swc_core::ecma::ast::*;
use swc_core::ecma::visit::{VisitMut, as_folder};
struct UpperCaseVisitor;
impl VisitMut for UpperCaseVisitor {
fn visit_mut_ident(&mut self, ident: &mut Ident) {
ident.sym = ident.sym.to_uppercase().into();
}
}
#[plugin_transform]
pub fn uppercase_transform(program: Program, _config: String) -> Program {
program.fold_with(&mut as_folder(UpperCaseVisitor))
}
示例:自定义JSX转换
use swc_plugin_macro::plugin_transform;
use swc_core::ecma::ast::*;
use swc_core::ecma::visit::{VisitMut, as_folder};
struct JsxTransformVisitor;
impl VisitMut for JsxTransformVisitor {
fn visit_mut_jsx_element(&mut self, el: &mut JSXElement) {
// 转换所有JSX元素
if let JSXElementName::Ident(ident) = &el.opening.name {
if ident.sym == "div" {
el.opening.name = JSXElementName::Ident(Ident::new("section".into(), el.opening.name.span()));
}
}
}
}
#[plugin_transform]
pub fn jsx_transform(program: Program, _config: String) -> Program {
program.fold_with(&mut as_folder(JsxTransformVisitor))
}
配置插件
plugin_transform
宏允许通过第二个参数传递配置字符串:
#[plugin_transform]
pub fn configured_transform(program: Program, config: String) -> Program {
println!("Received config: {}", config);
// 解析配置并应用到转换逻辑
program
}
构建和使用
- 将你的插件构建为动态库:
[lib]
crate_type = ["cdylib"]
- 在SWC配置中引用:
{
"jsc": {
"experimental": {
"plugins": [
["path/to/your/plugin.wasm", {}]
]
}
}
}
高级用法
访问编译器上下文
use swc_plugin_macro::plugin_transform;
use swc_core::{
ecma::ast::*,
plugin::{metadata::TransformPluginMetadataContext, plugin_transform},
};
#[plugin_transform]
pub fn context_aware_transform(
program: Program,
metadata: TransformPluginMetadataContext,
) -> Program {
let filename = metadata
.get_context(&program)
.and_then(|ctx| ctx.filename)
.unwrap_or_default();
println!("Processing file: {}", filename);
program
}
代码生成示例
use swc_plugin_macro::plugin_transform;
use swc_core::ecma::ast::*;
#[plugin_transform]
pub fn codegen_transform(program: Program, _config: String) -> Program {
if let Program::Module(mut module) = program {
// 在模块末尾添加console.log语句
module.body.push(ModuleItem::Stmt(Stmt::Expr(ExprStmt {
span: Default::default(),
expr: Box::new(Expr::Call(CallExpr {
span极客时间 年卡
span: Default::default(),
callee: Callee::Expr(Box::new(Expr::Member(MemberExpr {
span: Default::default(),
obj: ExprOrSuper::Expr(Box::new(Expr::Ident(Ident::new(
"console".into(),
Default::default(),
))),
prop: Box::new(Expr::Ident(Ident::new(
"log".into(),
Default::default(),
))),
computed: false,
})),
args: vec![Lit::Str(Str {
span: Default::default(),
value: "Transformed by swc plugin!".into(),
raw: None,
})
.as_arg()],
type_args: None,
})),
})));
Program::Module(module)
} else {
program
}
}
完整示例
下面是一个完整的SWC插件示例,实现了将代码中的特定函数调用替换为其他函数:
// Cargo.toml
/*
[dependencies]
swc_plugin_macro = "0.2"
swc_core = { version = "0.82", features = ["ecma_plugin_transform"] }
*/
use swc_plugin_macro::plugin_transform;
use swc_core::ecma::ast::*;
use swc_core::ecma::visit::{VisitMut, as_folder};
// 定义访问器结构体
struct FunctionReplaceVisitor {
// 可以在这里添加配置参数
}
impl VisitMut for FunctionReplaceVisitor {
fn visit_mut_call_expr(&mut self, call: &mut CallExpr) {
// 检查是否是我们要替换的函数调用
if let Callee::Expr(expr) = &call.callee {
if let Expr::Ident(ident) = &**expr {
if ident.sym == "oldFunction" {
// 替换为新的函数调用
call.callee = Callee::Expr(Box::new(Expr::Ident(Ident::new(
"newFunction".into(),
ident.span,
))));
}
}
}
}
}
// 使用宏标记插件入口点
#[plugin_transform]
pub fn function_replace_plugin(program: Program, _config: String) -> Program {
// 应用我们的访问器
program.fold_with(&mut as_folder(FunctionReplaceVisitor {}))
}
注意事项
- 插件必须编译为WASM格式才能在SWC中使用
- 性能敏感的转换应该尽量减少AST遍历次数
- 复杂的转换可能需要多次遍历AST
- 注意保持源映射信息以确保调试体验
swc_plugin_macro
为Rust开发者提供了强大的能力来扩展SWC编译器的功能,实现各种自定义的代码转换和生成需求。