Rust转译工具SWC插件库swc_plugin的使用,高效实现JavaScript和TypeScript代码转换与优化
Rust转译工具SWC插件库swc_plugin的使用,高效实现JavaScript和TypeScript代码转换与优化
swc_plugin (公共接口已弃用)
提供@swc/core
与插件之间通信的内部实现细节。
注意:这之前是编写插件的入口点SDK,但现在swc_core
成为SWC提供的所有功能的元入口点。
安装
在项目目录中运行以下Cargo命令:
cargo add swc_plugin
或者在Cargo.toml中添加以下行:
swc_plugin = "1.0.1"
基本使用示例
以下是一个使用swc_plugin创建简单代码转换插件的完整示例:
use swc_common::FileName;
use swc_plugin::{plugin_transform, syntax_pos::Span, TransformPluginProgramMetadata};
use swc_ecma_ast::*;
use swc_ecma_visit::{VisitMut, VisitMutWith};
// 定义一个简单的访问者结构体来转换代码
struct MyVisitor;
impl VisitMut for MyVisitor {
fn visit_mut_expr(&mut self, expr: &mut Expr) {
// 转换所有字符串字面量
if let Expr::Lit(Lit::Str(str_lit)) = expr {
*expr = Expr::Lit(Lit::Str(Str {
value: format!("transformed: {}", str_lit.value).into(),
span: str_lit.span,
has_escape: false,
kind: Default::default(),
}));
}
expr.visit_mut_children_with(self);
}
}
// 插件入口函数
#[plugin_transform]
pub fn process_transform(program: Program, _metadata: TransformPluginProgramMetadata) -> Program {
// 创建一个访问者实例
let mut visitor = MyVisitor;
// 转换AST
program.fold_with(&mut visitor)
}
更高级的示例 - 实现console.log替换
use swc_plugin::{plugin_transform, TransformPluginProgramMetadata};
use swc_ecma_ast::*;
use swc_ecma_visit::{VisitMut, VisitMutWith};
struct ConsoleLogReplacer;
impl VisitMut for ConsoleLogReplacer {
fn visit_mut_call_expr(&mut self, call: &mut CallExpr) {
// 检查是否是console.log调用
if let Expr::Member(MemberExpr { obj, prop, .. }) = &*call.callee {
if let Expr::Ident(ident) = &**obj {
if ident.sym == "console" {
if let MemberProp::Ident(prop_ident) = prop {
if prop_ident.sym == "log" {
// 替换为自定义日志函数
call.callee = Box::new(Expr::Ident(Ident::new(
"customLog".into(),
prop_ident.span,
)));
}
}
}
}
}
call.visit_mut_children_with(self);
}
}
#[plugin_transform]
pub fn replace_console_log(program: Program, _metadata: TransformPluginProgramMetadata) -> Program {
program.fold_with(&mut ConsoleLogReplacer)
}
完整示例:实现箭头函数转普通函数
use swc_plugin::{plugin_transform, TransformPluginProgramMetadata};
use swc_ecma_ast::*;
use swc_ecma_visit::{VisitMut, VisitMutWith};
struct ArrowFnTransformer;
impl VisitMut for ArrowFnTransformer {
fn visit_mut_expr(&mut self, expr: &mut Expr) {
// 处理箭头函数表达式
if let Expr::Arrow(arrow_expr) = expr {
// 将箭头函数转换为普通函数表达式
*expr = Expr::Fn(FnExpr {
ident: None, // 匿名函数
function: Function {
params: arrow_expr.params,
body: arrow_expr.body,
decorators: vec![], // 无装饰器
span: arrow_expr.span,
is_async: arrow_expr.is_async,
is_generator: arrow_expr.is_generator,
type_params: arrow_expr.type_params,
return_type: arrow_expr.return_type,
},
});
}
expr.visit_mut_children_with(self);
}
}
#[plugin_transform]
pub fn transform_arrow_functions(program: Program, _metadata: TransformPluginProgramMetadata) -> Program {
program.fold_with(&mut ArrowFnTransformer)
}
注意事项
- 该库主要用于SWC内部实现,公共接口已被弃用
- 建议使用
swc_core
作为编写SWC插件的新入口点 - 插件开发需要对Rust和JavaScript AST有深入理解
1 回复
Rust转译工具SWC插件库swc_plugin的使用
介绍
SWC(Speedy Web Compiler)是一个用Rust编写的高速JavaScript/TypeScript转译器,而swc_plugin
是SWC的插件系统,允许开发者自定义转换逻辑。相比Babel,SWC在性能上有显著优势,同时提供了灵活的插件机制。
主要特点
- 高性能:Rust编写的转译器,比Babel快20倍左右
- 可扩展:通过插件系统自定义转换逻辑
- 支持广泛:支持JSX、TypeScript、ES6+等现代JavaScript特性
- 生态系统:与webpack、Rollup等构建工具集成良好
使用方法
1. 创建基本插件
首先在Cargo.toml
中添加依赖:
[dependencies]
swc_plugin = "0.1.0"
2. 编写简单插件
use swc_plugin::{ast::*, plugin_transform, TransformPluginProgramMetadata};
// 定义一个简单的插件,将所有标识符转换为大写
pub struct UpperCasePlugin;
impl VisitMut for UpperCasePlugin {
fn visit_mut_ident(&mut self, ident: &mut Ident) {
ident.sym = ident.sym.to_uppercase().into();
}
}
#[plugin_transform]
pub fn process_transform(program: Program, _metadata: TransformPluginProgramMetadata) -> Program {
program.fold_with(&mut as_folder(UpperCasePlugin))
}
3. 使用插件
在SWC配置中使用自定义插件:
{
"jsc": {
"experimental": {
"plugins": [
["path/to/your/plugin.wasm", {}]
]
}
}
}
高级示例:自定义JSX转换
use swc_plugin::{ast::*, plugin_transform, TransformPluginProgramMetadata};
use swc_ecma_ast::{JSXElement, JSXOpeningElement};
pub struct CustomJsxPlugin;
impl VisitMut for CustomJsxPlugin {
fn visit_mut_jsx_element(&mut self, el: &mut JSXElement) {
if let JSXOpeningElement::Ident(ident) = &mut el.opening.name {
if ident.sym == "div" {
ident.sym = "section".into();
}
}
}
}
#[plugin_transform]
pub fn process_jsx(program: Program, _metadata: TransformPluginProgramMetadata) -> Program {
program.fold_with(&mut as_folder(CustomJsxPlugin))
}
构建和部署
- 构建WASM插件:
cargo build --target wasm32-unknown-unknown --release
- 优化WASM大小:
wasm-opt -Oz ./target/wasm32-unknown-unknown/release/your_plugin.wasm -o ./dist/your_plugin.wasm
性能优化技巧
- 尽量减少AST遍历次数
- 使用
swc_plugin::ast::*
中的高效数据结构 - 避免在插件中进行不必要的内存分配
- 利用Rust的所有权系统减少拷贝
常见用途
- 自定义语法扩展
- 代码优化和压缩
- 框架特定的转换(如React、Vue等)
- 代码分析工具
- 自动化重构工具
通过swc_plugin
,开发者可以充分利用Rust的性能优势,构建高效的JavaScript/TypeScript代码转换工具。
完整示例demo
下面是一个完整的SWC插件开发示例,实现将代码中的console.log替换为自定义函数:
use swc_plugin::{ast::*, plugin_transform, TransformPluginProgramMetadata};
use swc_ecma_ast::{CallExpr, Callee, Expr, Ident};
// 定义插件结构体
pub struct ConsoleReplacePlugin;
impl VisitMut for ConsoleReplacePlugin {
fn visit_mut_call_expr(&mut self, call_expr: &mut CallExpr) {
// 检查是否是console.log调用
if let Callee::Expr(expr) = &call_expr.callee {
if let Expr::Member(member_expr) = &**expr {
if let Expr::Ident(ident) = &*member_expr.obj {
if ident.sym == "console" {
if let MemberProp::Ident(prop_ident) = &member_expr.prop {
if prop_ident.sym == "log" {
// 替换为自定义函数
call_expr.callee = Callee::Expr(Box::new(Expr::Ident(Ident::new(
"customLog".into(),
prop_ident.span,
))));
}
}
}
}
}
}
}
}
#[plugin_transform]
pub fn process_console(program: Program, _metadata: TransformPluginProgramMetadata) -> Program {
program.fold_with(&mut as_folder(ConsoleReplacePlugin))
}
构建和使用
- 首先添加Cargo.toml依赖:
[dependencies]
swc_plugin = "0.1.0"
swc_ecma_ast = "0.100.0"
- 构建WASM插件:
cargo build --target wasm32-unknown-unknown --release
- 在SWC配置中使用:
{
"jsc": {
"experimental": {
"plugins": [
["./target/wasm32-unknown-unknown/release/console_replace.wasm", {}]
]
}
}
}
这个示例展示了如何创建一个完整的SWC插件,从代码转换逻辑到构建部署的全过程。开发者可以根据实际需求修改转换逻辑,实现各种自定义的代码转换功能。