Movatterモバイル変換


[0]ホーム

URL:


Skip to Content
DocsPluginECMAScriptGetting started

Implementing a plugin

Important API Changes

⚠️

Recent API changes that may affect your plugin development:

  • Replacechain! macro with tuples: Use( instead ofchain!(. You can replace allchain!( with( using IDE features.
  • Forchain! with 13+ arguments: Use nested tuples for items after the 13th element.
  • Replace-> impl Fold with-> impl Pass in general.
  • as_folder is nowvisit_mut_pass and returnsimpl VisitMut + Pass instead ofimpl VisitMut + Fold.
  • UseProgram.apply andProgram.mutate to apply Pass to program:
    • fn apply(self, impl Pass) -> Self
    • fn mutate(&mut self, impl Pass)
  • Replacenoop() withnoop_pass(). The new function lives inswc_ecma_ast and is a real noop function.

Setup environment

Install required toolchain

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

Install rust

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

Add wasm target to rust

SWC supports two kinds of.wasm files.Those are

In this guide, we will usewasm-wasip1 as a target.

Installswc_cli

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

cargo install swc_cli

Configuring IDE

If you are going to use vscode, it’s recommended to installrust-analyzer extension.rust-analyzer is alanguage 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 supports creating a new plugin project.

Run

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

to create a new plugin, and openmy-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}

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


We will use

foo=== bar;

as the input. Fromthe 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}

Let’s implement a method forBinExpr.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); }}

Note thatvisit_mut_children_with is required if you want to call the method handler for children.e.g.visit_mut_ident forfoo andbar will be called bye.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!("===") is a macro call, and it returns various types of operators.It returnsBinaryOp  in this case, because we provided"===", which is a binary operator.Seethe rustdoc for op! macro  for more details.

If we run this plugin, we will get

kdy1=== bar;

Testing your transform

You can simply runcargo 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;"#);

Then, once you runUPDATE=1 cargo test, the snapshot will be updated.

You can take a look atthe 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:

Logging

SWC usestracing for logging.By default, SWC testing library configures the log level todebug by default, and this can be controlled by using an environment variable namedRUST_LOG.e.g.RUST_LOG=trace cargo test will print all logs, includingtrace logs.

If you want, you can remove logging for your plugin by using cargo features oftracing.Seethe documentation for it .

Publishing your plugin

Please seeplugin publishing guide

Last updated on
Selecting swc_coreCheatsheet
Powered by
[8]ページ先頭

©2009-2025 Movatter.jp