跳到內容
文件
外掛
ECMAScript
開始使用

實作外掛

設定環境

安裝必要的工具鏈

由於外掛程式是用 Rust 程式語言撰寫,並建置成 .wasm 檔案,因此您需要安裝 Rust 工具鏈和 wasm 目標。

安裝 Rust

您可以按照 Rust 官方網站上的「安裝 Rust」頁面(在新分頁中開啟) 中的說明進行操作。

將 wasm 目標新增至 Rust

SWC 支援兩種 .wasm 檔案。它們是

  • wasm32-wasi
  • wasm32-unknown-unknown

在本指南中,我們將使用 wasm-wasi 作為目標。

安裝 swc_cli

您可以執行以下動作來安裝 SWC 的 Rust-based CLI:

cargo install swc_cli

設定 IDE

如果您打算使用 vscode,建議安裝 rust-analyzer 擴充功能。 rust-analyzer 是 Rust 程式語言的 語言伺服器(在新分頁中開啟),它為程式碼完成、程式碼導覽和程式碼分析提供了良好的功能。

實作簡單的插件

建立專案

SWC CLI 支援建立新的插件專案。

執行

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

建立新的插件,並使用你偏好的 Rust IDE 開啟 my-first-plugin

實作訪客

產生的程式碼有

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 類型,因此它有很多方法。


我們將使用

foo === bar;

作為輸入。從 SWC Playground(在新分頁開啟),你可以取得此程式碼的實際表示。

{
  "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 的方法。你可以這樣做

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。例如,visit_mut_ident 針對 foobar 會由上述 e.visit_mut_children_with(self); 呼叫。

讓我們使用二元運算子來縮小範圍。

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("kdy1".into(), e.left.span()).into());
        }
    }
}

op!("===") 是一個巨集呼叫,它會傳回各種類型的運算子。它會傳回 BinaryOp (在新分頁中開啟),因為我們提供了 "===",它是一個二元運算子。請參閱 op! 巨集的 rustdoc (在新分頁中開啟) 以取得更多詳細資料。

如果我們執行這個外掛程式,我們會得到

kdy1 === bar;

測試您的轉換

您可以簡單地執行 cargo test 來測試您的外掛程式。SWC 也提供了一個實用程式來簡化固定測試。

您可以輕鬆驗證轉換的輸入和輸出。

test!(
    Default::default(),
    |_| as_folder(TransformVisitor),
    boo,
    r#"foo === bar;"#
);

然後,一旦您執行 UPDATE=1 cargo test,快照就會更新。

您可以查看 typescript 類型剝離器的真實固定測試 (在新分頁中開啟)

#[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| chain!(tr(), properties(t, true)),
        &input,
        &output,
    );
}
 

注意事項

  • 提供給 testing::fixture 的 glob 相對於 cargo 專案目錄。
  • 輸出檔案是 output.js,它儲存在與輸入檔案相同的目錄中。
  • test_fixture 驅動測試。
  • 你可以透過將語法傳遞給 test_fixture 來決定輸入檔案的語法。
  • 然後你將你的訪客實作提供給 test_fixture 的第二個引數。
  • 接著你提供輸入檔案路徑和輸出檔案路徑。

記錄

SWC 使用 tracing 來記錄。預設情況下,SWC 測試函式庫將日誌層級設定為 debug,這可以使用名為 RUST_LOG 的環境變數來控制。例如,RUST_LOG=trace cargo test 會列印所有日誌,包括 trace 日誌。

如果你願意,你可以使用 tracing 的 cargo 功能來移除你的外掛程式記錄。請參閱 文件(在新分頁中開啟)

發佈你的外掛程式

請參閱 外掛程式發佈指南