Skip to Content
开发文档PluginECMAScript新手入门

实现插件

¥Implementing a plugin

重要的 API 更改

¥Important API Changes

⚠️

可能会影响插件开发的最近 API 更改:

¥Recent API changes that may affect your plugin development:

  • 用元组替换 chain! 宏:使用 ( 代替 chain!(。你可以使用 IDE 功能将所有 chain!( 替换为 (

    ¥Replace chain! macro with tuples: Use ( instead of chain!(. You can replace all chain!( with ( using IDE features.

  • 对于具有 13 个以上参数的 chain!:对第 13 个元素之后的项目使用嵌套元组。

    ¥For chain! with 13+ arguments: Use nested tuples for items after the 13th element.

  • 一般用 -> impl Pass 替换 -> impl Fold

    ¥Replace -> impl Fold with -> impl Pass in general.

  • as_folder 现在是 visit_mut_pass,返回 impl VisitMut + Pass 而不是 impl VisitMut + Fold

    ¥as_folder is now visit_mut_pass and returns impl VisitMut + Pass instead of impl VisitMut + Fold.

  • 使用 Program.applyProgram.mutate 将 Pass 应用于程序:

    ¥Use Program.apply and Program.mutate to apply Pass to program:

    • fn apply(self, impl Pass) -> Self

    • fn mutate(&mut self, impl Pass)

  • noop_pass() 替换 noop()。新功能位于 swc_ecma_ast 中,是一个真正的 noop 功能。

    ¥Replace noop() with noop_pass(). The new function lives in swc_ecma_ast and is a real noop function.

设置环境

¥Setup environment

安装所需的工具链

¥Install required toolchain

由于插件是用 Rust 编程语言编写并构建为 .wasm 文件,因此你需要安装 rust 工具链和 wasm 目标。

¥As plugin is written in the rust programming language and built as a .wasm file, you need to install rust toolchain and wasm target.

安装 Rust

¥Install rust

你可以按照 Rust 官方网站的 ‘安装 Rust’ 页面 的说明进行操作

¥You can follow instructions at ‘Install Rust’ page from the official rust website

将 wasm 目标添加到 Rust

¥Add wasm target to rust

SWC 支持两种 .wasm 文件。那些是

¥SWC supports two kinds of .wasm files. Those are

  • wasm32-wasip1

  • wasm32-未知-未知

    ¥wasm32-unknown-unknown

在本指南中,我们将使用 wasm-wasip1 作为目标。

¥In this guide, we will use wasm-wasip1 as a target.

安装 swc_cli

¥Install swc_cli

你可以通过执行以下操作为 SWC 安装基于 Rust 的 CLI

¥You can install a rust-based CLI for SWC by doing

cargo install swc_cli

配置 IDE

¥Configuring IDE

如果你要使用 vscode,建议安装 rust-analyzer 扩展。rust-analyzer 是 Rust 编程语言的 语言服务器,它为代码完成、代码导航和代码分析提供了良好的功能。

¥If you are going to use vscode, it’s recommended to install rust-analyzer extension. rust-analyzer is a language server for the rust programming language, which provides good features for code completion, code navigation, and code analysis.

实现简单的插件

¥Implementing simple plugin

创建一个项目

¥Create a project

SWC CLI 支持创建新的插件项目。

¥SWC CLI supports creating a new plugin project.

运行

¥Run

swc plugin new --target-type wasm32-wasip1 my-first-plugin # You should to run this rustup target add wasm32-wasip1

创建一个新插件,然后使用你首选的 Rust IDE 打开 my-first-plugin

¥to create a new plugin, and open my-first-plugin with your preferred rust IDE.

实现访客

¥Implementing a visitor

生成的代码有

¥The generated code has

impl VisitMut for TransformVisitor { // Implement necessary visit_mut_* methods for actual custom transform. // A comprehensive list of possible visitor methods can be found here: // https://rustdoc.swc.rs/swc_ecma_visit/trait.VisitMut.html }

用于转换代码。性状 VisitMut 支持修改 AST 节点,并且由于它支持所有 AST 类型,因此它有很多方法。

¥which is used to transform code. The trait VisitMut supports mutating AST nodes, and as it supports all AST types, it has lots of methods.


我们将使用

¥We will use

foo === bar;

作为输入。从 SWC 在线运行 开始,你可以得到这段代码的实际表示。

¥as the input. From the SWC Playground, you can get actual representation of this code.

{ "type": "Module", "span": { "start": 0, "end": 12, "ctxt": 0 }, "body": [ { "type": "ExpressionStatement", "span": { "start": 0, "end": 12, "ctxt": 0 }, "expression": { "type": "BinaryExpression", "span": { "start": 0, "end": 11, "ctxt": 0 }, "operator": "===", "left": { "type": "Identifier", "span": { "start": 0, "end": 3, "ctxt": 0 }, "value": "foo", "optional": false }, "right": { "type": "Identifier", "span": { "start": 8, "end": 11, "ctxt": 0 }, "value": "bar", "optional": false } } } ], "interpreter": null }

让我们为 BinExpr 实现一个方法。你可以这样做

¥Let’s implement a method for BinExpr. You can do it like

use swc_core::{ ast::*, visit::{VisitMut, VisitMutWith}, }; impl VisitMut for TransformVisitor { fn visit_mut_bin_expr(&mut self, e: &mut BinExpr) { e.visit_mut_children_with(self); } }

请注意,如果要调用子级的方法处理程序,则需要 visit_mut_children_with。例如 foobarvisit_mut_ident 将被上面的 e.visit_mut_children_with(self); 调用。

¥Note that visit_mut_children_with is required if you want to call the method handler for children. e.g. visit_mut_ident for foo and bar will be called by e.visit_mut_children_with(self); above.

让我们使用二元运算符缩小范围。

¥Let’s narrow down it using the binary operator.

use swc_core::{ ast::*, visit::{VisitMut, VisitMutWith}, common::Spanned, }; impl VisitMut for TransformVisitor { fn visit_mut_bin_expr(&mut self, e: &mut BinExpr) { e.visit_mut_children_with(self); if e.op == op!("===") { e.left = Box::new(Ident::new_no_ctxt("kdy1".into(), e.left.span()).into()); } } }

op!("===") 是一个宏调用,它返回各种类型的运算符。在本例中它返回 BinaryOp,因为我们提供了 "===",它是一个二元运算符。详细信息请参见 op 的 rustdoc!macro

¥op!("===") is a macro call, and it returns various types of operators. It returns BinaryOp in this case, because we provided "===", which is a binary operator. See the rustdoc for op! macro for more details.

如果我们运行这个插件,我们会得到

¥If we run this plugin, we will get

kdy1 === bar;

测试你的变换

¥Testing your transform

你只需运行 cargo test 即可测试你的插件。SWC 还提供了一个实用程序来简化夹具测试。

¥You can simply run cargo test to test your plugins. SWC also provides a utility to ease fixture testing.

你可以轻松验证转换的输入和输出。

¥You can easily verify the input and output of the transform.

test!( Default::default(), |_| visit_mut_pass(TransformVisitor), // Note: Updated to use visit_mut_pass instead of as_folder boo, r#"foo === bar;"# );

然后,一旦运行 UPDATE=1 cargo test,快照就会更新。

¥Then, once you run UPDATE=1 cargo test, the snapshot will be updated.

你可以看看 Typescript Type Stripper 的真实夹具测试

¥You can take a look at the real fixture test for typescript type stripper.

#[testing::fixture("tests/fixture/**/input.ts")] #[testing::fixture("tests/fixture/**/input.tsx")] fn fixture(input: PathBuf) { let output = input.with_file_name("output.js"); test_fixture( Syntax::Typescript(TsConfig { tsx: input.to_string_lossy().ends_with(".tsx"), ..Default::default() }), &|t| (tr(), properties(t, true)), // Note: Updated to use tuple syntax instead of chain! &input, &output, ); }

注意事项:

¥Things to note:

  • 提供给 testing::fixture 的 glob 是相对于 cargo 项目目录的。

    ¥The glob provided to testing::fixture is relative to the cargo project directory.

  • 输出文件是 output.js,它与输入文件存储在同一目录中。

    ¥The output file is output.js, and it’s stored in a same directory as the input file.

  • test_fixture 驱动测试。

    ¥test_fixture drives the test.

  • 你可以通过将语法传递给 test_fixture 来确定输入文件的语法。

    ¥You can determine the syntax of the input file by passing the syntax to test_fixture.

  • 然后,你提供访问者实现作为 test_fixture 的第二个参数。

    ¥You then provide your visitor implementation as the second argument to test_fixture.

  • 然后提供输入文件路径和输出文件路径。

    ¥Then you provide the input file path and the output file path.

日志

¥Logging

SWC 使用 tracing 进行日志记录。默认情况下,SWC 测试库将日志级别默认配置为 debug,这可以通过使用名为 RUST_LOG 的环境变量来控制。例如 RUST_LOG=trace cargo test 将打印所有日志,包括 trace 日志。

¥SWC uses tracing for logging. By default, SWC testing library configures the log level to debug by default, and this can be controlled by using an environment variable named RUST_LOG. e.g. RUST_LOG=trace cargo test will print all logs, including trace logs.

如果需要,你可以使用 tracing 的 Cargo 功能删除插件的日志记录。参见 它的文档

¥If you want, you can remove logging for your plugin by using cargo features of tracing. See the documentation for it.

发布你的插件

¥Publishing your plugin

请参阅 插件发布指南

¥Please see plugin publishing guide

Last updated on
SWC v1.11 中文网 - 粤ICP备13048890号
Nodejs.cn 旗下网站