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)
}

注意事项

  1. 该库主要用于SWC内部实现,公共接口已被弃用
  2. 建议使用swc_core作为编写SWC插件的新入口点
  3. 插件开发需要对Rust和JavaScript AST有深入理解

1 回复

Rust转译工具SWC插件库swc_plugin的使用

介绍

SWC(Speedy Web Compiler)是一个用Rust编写的高速JavaScript/TypeScript转译器,而swc_plugin是SWC的插件系统,允许开发者自定义转换逻辑。相比Babel,SWC在性能上有显著优势,同时提供了灵活的插件机制。

主要特点

  1. 高性能:Rust编写的转译器,比Babel快20倍左右
  2. 可扩展:通过插件系统自定义转换逻辑
  3. 支持广泛:支持JSX、TypeScript、ES6+等现代JavaScript特性
  4. 生态系统:与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))
}

构建和部署

  1. 构建WASM插件:
cargo build --target wasm32-unknown-unknown --release
  1. 优化WASM大小:
wasm-opt -Oz ./target/wasm32-unknown-unknown/release/your_plugin.wasm -o ./dist/your_plugin.wasm

性能优化技巧

  1. 尽量减少AST遍历次数
  2. 使用swc_plugin::ast::*中的高效数据结构
  3. 避免在插件中进行不必要的内存分配
  4. 利用Rust的所有权系统减少拷贝

常见用途

  1. 自定义语法扩展
  2. 代码优化和压缩
  3. 框架特定的转换(如React、Vue等)
  4. 代码分析工具
  5. 自动化重构工具

通过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))
}

构建和使用

  1. 首先添加Cargo.toml依赖:
[dependencies]
swc_plugin = "0.1.0"
swc_ecma_ast = "0.100.0"
  1. 构建WASM插件:
cargo build --target wasm32-unknown-unknown --release
  1. 在SWC配置中使用:
{
  "jsc": {
    "experimental": {
      "plugins": [
        ["./target/wasm32-unknown-unknown/release/console_replace.wasm", {}]
      ]
    }
  }
}

这个示例展示了如何创建一个完整的SWC插件,从代码转换逻辑到构建部署的全过程。开发者可以根据实际需求修改转换逻辑,实现各种自定义的代码转换功能。

回到顶部