Rust 和 WebAssembly 可以結合在 許多 美妙的方式中。為了彙整我們的努力,並可以產生最大、最正面的影響,Rust 和 WebAssembly 領域工作小組正專注於單一遠景

將已編譯成 WebAssembly 的 Rust 外科手術式地插入,應是加速效能最敏感的 JavaScript 程式碼路徑的最佳選擇。不要 捨棄您現有的程式碼庫,因為 Rust 與其他人友好相處,不論您是 Rust 或網路開發人員,當已編譯成 WebAssembly 的 Rust 無縫整合至您偏好的工具時,您的自然工作流程不應有所改變。

這篇部落格文章將針對這些期許進一步說明,並說明我們目前與這些期許的關係。在後續一系列的文章中,我們將討論 Rust 和 WebAssembly 生態系統中每個主要組成的下一步行動。

您有興趣協助我們實現這些理想嗎?加入 Rust 和 WebAssembly 領域工作小組吧!

為什麼著重於效能敏感的程式碼?

在效能最敏感的脈絡中,JavaScript 僅造成妨礙,而非助益。它的動態型別系統和非決定性垃圾回收器暫停會造成阻礙。如果不小心地偏離了 JIT 的順暢路徑,看似微小的程式碼變更會導致劇烈的效能衰退。

另一方面,Rust 提供給程式設計師低階控制和可靠效能。它免於遭受非決定性垃圾回收的暫停,程式設計師可以控制間接、單態化和記憶體配置。

使用 Rust 時,我們不需要深入熟悉每個 JavaScript 實作的 JIT 內部運作,成為效能大師。我們可以有「無需魔法的極速

不要 改寫,而是整合

已編譯成 WebAssembly 的 Rust 沒有執行時間。這將產生尺寸小巧的 .wasm 二進位檔,與編譯成 WebAssembly 的 Rust 程式碼數量成比例。二進位檔尺寸非常重要,因為 .wasm 必須透過網路下載。這種比例關係表示您只需為您使用的部分 (以程式碼尺寸計) 付費。因此,現有的 JavaScript 程式碼庫可以逐步且部分地採用 Rust。

保留已經能運作的程式碼:我們可以僅將效能最敏感的 JavaScript 函式移植到 Rust,即可立即獲得好處。

保留您的工作流程

如果你是一位 JavaScript 駭客,而你想使用用 Rust 和 WebAssembly 編寫的函式庫,你不應該必須全部變更你的工作流程。我們可以發佈 .wasm 套件到 npm,而你可以像你常依賴於其他 JavaScript 函式庫的方式一樣,在 package.json 中依賴於它們。它們可以作為 ECMAScript 模組、CommonJS 類型的 require,或當作一個新的物件屬性新增到 JavaScript 全域變數中進行匯入。 自動打包程式會理解 Rust 和 WebAssembly,就像它們理解 JavaScript 一樣好。

如果你是一位 Rust 駭客,而你想將你的函式庫編譯成 .wasm,並在 npm 上分享,你也不應該必須變更你的工作流程。事實上,你甚至不用安裝 npm、Node.js 和一個完整的 JavaScript 開發環境。 wasm-pack 會為你的函式庫編譯、最適化,並產生 JavaScript 繫結。然後它會替你將函式庫發佈到 npm!

目前的狀態

這個區段提供我們的目前的生態系、目前可用的工具,以及與上文描述的願景相較之下,這一切是什麼樣子。

Rust 和 WebAssembly 書籍

如果人們無法自己學習如何使用我們建立的一切,那我們的努力將是徒勞無功的。因此,我們寫著 Rust 和 WebAssembly 書籍

現在,它已經有很多很讚的內容

  • 啟動並執行
  • 設計與實作一個非平凡範例(生命遊戲),整合 Rust 和 JavaScript
  • 除錯、時間剖析和程式碼大小剖析方面的技巧
  • 如何使用 wasm-pack 發佈到 npm

但是它沒有很多的連貫性。它感覺就像是附錄和隨機教學課程的集合。我們將會有一個後續的網誌文章來詳述它的具體需求,以及如果你有興趣的話,如何提供協助。

wasm-bindgen

wasm-bindgen 促進 Rust 和 JavaScript 之間的溝通。你可以將 JavaScript 事物匯入 Rust,並將 Rust 事物匯出到 JavaScript。它允許你在 wasm 和 JavaScript 分享像是字串和結構這些豐富類型,而非僅僅只有 WebAssembly 標準所定義的簡單整數和浮點數。

以下是使用 wasm-bindgen 在 Rust 和 JavaScript 之間的「Hello, World!」。首先,我們將 alert 函式匯入 Rust,並將 greet 函式匯出到 JavaScript

extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!("Hello, {}!", name));
}

然後,我們以 ECMAScript 模組的形式匯入 wasm 到 JavaScript,並呼叫 greet 函式

import { greet } from "./hello_world";

greet("World!");

wasm-bindgen architecture

wasm-bindgen 怎麼運作?簡短地說,它是一個程序巨集,接收加上 #[wasm_bindgen] 屬性的 Rust 原始碼,建構一個抽象語法樹 (AST),然後它會發射兩個產出

  1. 匯入 JavaScript 事物並匯出 Rust 事物的 Rust 繫結。

  2. JavaScript 綁定會將一個友善的介面公開至 Rust 匯出的事物,供其他 JavaScript 程式碼使用,並提供 Rust 所需的匯入。

wasm-bindgen 處理 JavaScript 綁定的方法允許您只對您所使用的匯入功能付費。雖然您匯入了 window.alert 函式,但您不會取得 window.document 的輔助程式碼。

最大的缺點是,現在您總是必須自行宣告匯入。JavaScript 函式及類型和 Web 平台 API 有許多常見的匯入項,且將會有人重複使用好幾次。手動匯入這些項目既無聊又機械化。我們有一個修正此問題的計畫,但您必須等到後續的部落格文章才能瞭解詳情。

wasm-pack

wasm-pack 希望成為建置、最佳化和發佈 Rust 生成的 WebAssembly 的一站式服務,您可以在瀏覽器或 Node.js 中與 JavaScript 互操作。 wasm-pack 可協助您建置和將 Rust 生成的 WebAssembly 發佈至 npm 註冊表,與您在現有工作流程中使用的任何其他 JavaScript 套件搭配使用,例如 webpack 等套件管理工具或 greenkeeper 等服務。

wasm-pack cartoon

Lin Clark 在 讓 WebAssembly 對 Rust 與所有語言都更好 中繪製。

目標是,如果您是 Rust 開發人員,且想要在 npm 上發佈編譯為 wasm 的程式庫,wasm-pack 將會

  1. 使用 wasm32-unknown-unknown 目標將程式庫編譯為 WebAssembly,
  2. .wasm 上執行 wasm-bindgen CLI 工具以產生其 JavaScript 介面,
  3. 執行任何其他建置後工具,例如 wasm-snipwasm-opt
  4. 彙整您的程式庫和/或其 JavaScript 綁定可能有的任何和所有 npm 相依項,
  5. 並在 npm 上發佈產出的套件。

這一切無須您這位 Rust 開發人員具備並執行 JavaScript 工具鏈即可進行。

目前已實作第 1、2 和 5 步驟,但您的本機系統仍需要安裝 npm。針對 wasm-pack 還有更多計畫,我們即將發佈關於建置、相依項和發佈的統籌故事,但您必須等待後續的專屬部落格文章。

等等,還有更多!

Twiggy!

Twiggy!

即將到來:未來

如本文所述,我們將進一步發布部落格文章,詳細說明我們對 Rust 2018 版的特定目標,以及您可以如何提供協助。在此同時,請不要猶豫,加入 Rust 與 WebAssembly 領域工作小組,並立即協助建構 Rust 與 WebAssembly 的未來!