Rust 和 WebAssembly 遠景
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
怎麼運作?簡短地說,它是一個程序巨集,接收加上 #[wasm_bindgen]
屬性的 Rust 原始碼,建構一個抽象語法樹 (AST),然後它會發射兩個產出
-
匯入 JavaScript 事物並匯出 Rust 事物的 Rust 繫結。
-
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 等服務。
Lin Clark 在 讓 WebAssembly 對 Rust 與所有語言都更好 中繪製。
目標是,如果您是 Rust 開發人員,且想要在 npm 上發佈編譯為 wasm 的程式庫,wasm-pack
將會
- 使用
wasm32-unknown-unknown
目標將程式庫編譯為 WebAssembly, - 在
.wasm
上執行wasm-bindgen
CLI 工具以產生其 JavaScript 介面, - 執行任何其他建置後工具,例如
wasm-snip
與wasm-opt
, - 彙整您的程式庫和/或其 JavaScript 綁定可能有的任何和所有 npm 相依項,
- 並在 npm 上發佈產出的套件。
這一切無須您這位 Rust 開發人員具備並執行 JavaScript 工具鏈即可進行。
目前已實作第 1、2 和 5 步驟,但您的本機系統仍需要安裝 npm
。針對 wasm-pack
還有更多計畫,我們即將發佈關於建置、相依項和發佈的統籌故事,但您必須等待後續的專屬部落格文章。
等等,還有更多!
-
Twiggy 是
.wasm
二進位檔的程式碼大小評估工具。它可幫助您回答「這個函式為什麼會在這裡 - 有誰呼叫它?」以及「如果我停止使用這個函數、將它移除,並移除它移除後變成死碼的所有函數,就可以節省多少空間?」等問題。 -
wee_alloc
是專為 WebAssembly 設計的微小配置器,其(壓縮前)程式碼大小足跡僅為一 KB。它針對執行少數初始動態大小配置,然後在沒有任何進一步配置的情況下執行龐大任務的程式碼而設計。此情境需要存在某些配置器,但我們非常樂意犧牲配置效能以換取較小的程式碼大小。
-
console_error_panic_hook
套件為 wasm 提供一個會透過console.error
函式將 panic 記錄至開發人員主控台的 panic hooks。不再有含糊不清的「RuntimeError: unreachable executed」訊息!取得您預期看到的適切宣告失敗訊息或索引超出界線資訊。它讓除錯 panic 變得更容易。 -
wasm-snip
工具讓您可以強制將函式主體替換為單一unreachable
指令。您知道某些函式在執行階段永遠不會被呼叫,但編譯器無法在編譯階段證明這一點?剪掉它!然後再次執行 wasm-gc,它所傳遞呼叫的所有函式(在執行階段也可能永遠都不會被呼叫)也會被移除。當您預期提供帶有panic=abort
的小型.wasm
二進位檔時,這對於移除 Rust 的恐慌及格式化架構特別有幫助。
即將到來:未來
如本文所述,我們將進一步發布部落格文章,詳細說明我們對 Rust 2018 版的特定目標,以及您可以如何提供協助。在此同時,請不要猶豫,加入 Rust 與 WebAssembly 領域工作小組,並立即協助建構 Rust 與 WebAssembly 的未來!