摘要

2019 年是 Rust 與 WebAssembly 從「可用」邁向「穩定、功能完善且可投入生產環境」的一年。

為了實現此目標,Rust 與 WebAssembly 領域工作組將:

  • 透過協作開發模組化工具包來培養函式庫生態系統

  • 將多執行緒功能帶入 Rust 生成的 Wasm

  • 將一流的除錯支援整合到我們的工具鏈中

  • 完善我們的工具鏈和開發者工作流程,最終推出 wasm-pack 的 1.0 版本

  • 投資於監控、測試和效能分析基礎設施,以確保我們的工具和函式庫快速、穩定且可投入生產環境。

動機

這份路線圖草案參考了

詳細說明

協作開發模組化工具包

以模組化的方式構建 [高階函式庫] 的想法,讓社群中的其他人能夠以不同的方式組合這些元件,這讓我感到非常興奮。希望這能讓整個生態系統更加強大。

我特別希望看到以模組化的方式實現一個具有類似 JSX 語法的虛擬 DOM 函式庫。在這方面已經有一些嘗試,但似乎都相對龐大且「功能齊全」。我希望這在 2019 年會有所改變。

— Ryan Levick 在 Rust WebAssembly 2019

不要建立品牌孤島。品牌化也許有助於提升知名度。但如果我們真的希望 Rust 的 Wasm 故事取得成功,我們應該思考如何合作,而不是劃分地盤。

— Yoshua Wuyts 在 Wasm 2019

在 2018 年,我們建立了基礎函式庫,例如 js-sysweb-sys。在 2019 年,我們應該在它們的基礎上構建模組化的高階函式庫,並將這些函式庫收集到一個工具包 crate 中,以提供整體體驗。這個工具包及其函式庫將提供您在以 Wasm 為目標時所需的所有功能。

正在構建一個全新的 Web 應用程式?使用整個工具包可以快速上手。仔細製作一個微小的 Wasm 模組並將其整合回現有的 JavaScript 專案?從工具包中取出您需要的目標函式庫,並單獨使用它。

  • 模組化:可以選擇使用或不使用任何個別元件。優先考慮介面而非實作。

  • 培養協作:我們已經看到 Rust 和 WebAssembly 領域中出現了一個生態系統,並且有許多很棒的實驗,但我們沒有看到專案之間有很多協作。透過刻意建立協作空間,我們可以減少重複工作,發揮更大的影響力,並幫助生態系統保持健康。

Wasm 的多執行緒

我們必須將 Rust 的無所畏懼的並發帶到 Web!

— Nick Fitzgerald 在 Rust and WebAssembly in 2019

成為 WebAssembly 絕對的尖端,我們應該考慮成為第一個滿足 [執行緒和原子操作] 的人。

— richardanaya 在 My Rust 2019 Dream

我們的工具鏈已經實驗性地支援 Wasm 中的多執行緒。瀏覽器目前在功能旗標後發布 SharedArrayBuffer 和原子操作(Wasm 多執行緒的原語),並且他們預計在 2019 年開始預設啟用它們。

WebAssembly 的賣點之一是能夠有效利用可用的硬體。多執行緒將這個故事從單核心擴展到多核心。雖然多執行緒對於 JavaScript 和任何編譯為 Wasm 的語言來說都是實際可行的,但 Rust 獨特的擁有權系統使其在經濟上可行

有一些技術上的問題(詳情請參閱上面的連結)意味著我們無法讓 Rust 標準函式庫的 std::thread::* 在 Wasm 上運作。但至關重要的是,我們在整個生態系統中都有核心多執行緒構建塊(例如執行緒池和鎖)的共享實作。在 2019 年,我們應該將我們實驗性的多執行緒支援轉變為 Wasm 上可投入生產環境的多執行緒基礎,讓 rayon 等熱門 crate 在 Web 上運作,並利用 Rust 無所畏懼的並發性。

除錯

在 [除錯] 正常運作之前(包括變數檢查,目前 wasm 完全不支援),其他一切都只是在玩耍。

— anlumo 在 r/rust 上的評論

擁有 [原始碼地圖] 對除錯來說會非常好。

— Yoshua Wuyts 在 Wasm 2019

除錯很困難,因為大部分的工作都不在這個工作組的掌控範圍內,而是取決於 WebAssembly 標準化機構和實現瀏覽器開發者工具的人員。然而,我們可以採取一些具體步驟來改進除錯

  1. println!dbg! 等功能與 Wasm 開箱即用。為此,我們將構建對 WebAssembly 參考系統根目錄和標準化流程中 Wasm 的標準系統呼叫的支援。

  2. 建立在除錯時將我們 Rust 生成的 Wasm 編譯為帶有原始碼地圖的 JavaScript 的能力。原始碼地圖是一種 JavaScript 的有限除錯資訊格式,它允許在除錯器中逐步執行原始碼位置,而不是逐步執行編譯器生成的 JavaScript 程式碼。

  3. 在我們的工具鏈中新增以除錯為重點的追蹤和檢測功能。例如,目前很難除錯 Wasm 記憶體調整大小導致的 JavaScript 陣列緩衝區檢視被分離的問題。我們可以透過選擇性地使用日誌記錄來檢測 mem.grow 指令,使除錯更容易。

除此之外,我們應該與 WebAssembly 標準化機構和瀏覽器開發者工具製造商合作,並積極參與 WebAssembly 除錯子章程,以在除錯領域創造一些進展。透過持續施加環境和社會壓力,並在我們可以提供幫助的地方伸出援手,我們最終將為 Wasm 擁有豐富的原始碼級除錯功能。

工具鏈和工作流程改進

設定 Wasm 專案需要相當多的樣板程式碼。如果我們能找到減少這種情況的方法就好了。

— Yoshua Wuyts 在 Wasm 2019

我們原本打算在 2018 年將一些東西包含在 wasm-pack 中,但最終沒有實現。[...] 我們應該完成這些任務,並將 wasm-pack 打磨成 1.0 工具。

— Nick Fitzgerald 在 Rust and WebAssembly in 2019

在 2019 年,我們的工具鏈和工作流程應該功能齊全且完善。wasm-pack 作為我們工具鏈的入口點,將承擔這項工作的重擔,但其中大部分工作也將在由 wasm-pack 呼叫的工具中進行,而不是在 wasm-pack 本身中進行。

鑑於這項工作主要是關於填補缺失的部分和改善使用者體驗,它有點像是一個待辦事項清單。但這也是一個好現象:這意味著 wasm-pack 實際上相當接近功能齊全。

完成所有這些任務後,我們應該發布 wasm-pack 的 1.0 版本。

監控、效能分析和測試基礎設施

我建議使用 rust/wasm 時遇到的主要反對意見是編譯時間,但到目前為止,端到端延遲實際上看起來很有競爭力 [...] 在 CI 中進行幾次基準測試並在網路上某處顯示圖表將有助於保持這種狀態。

— @jamii 在 RFC 評論

如果我想使用 libtest 和 wasm-bindgen-test 執行函式庫的測試,我需要寫


# #![allow(unused_variables)]
#fn main() {
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn my_test() { ... }
#}

而不是僅僅寫


# #![allow(unused_variables)]
#fn main() {
#[test]`
fn my_test() { ... }
#}

— @gnzlbg 在 RFC 評論

我們應該構建類似 perf.rust-lang.org 的基礎設施0 來關注

  • 熱門和基礎 wasm crate(例如我們模組化工具包中的那些 crate)的程式碼大小,以及

  • 我們的 wasm-bindgenwasm-pack 的構建時間。

透過持續追蹤這些數據,以及在特定時間點追蹤這些數據,我們將對自己負責,兌現我們對輕量級工具包和「穩定、可投入生產環境」工具鏈的承諾。

0或者,如果合理且維護者願意,將我們的監控整合到 perf.rust-lang.org 中。

這是宏觀層面的基礎設施故事,但我們也需要在微觀層面支援生態系統中 crate 的需求。這意味著繼續投資於單元測試和效能分析 Rust 生成的 Wasm 二進位檔案。具體來說,我們應該

  • wasm-bindgen-test 中新增基準測試支援,以及

  • 使 wasm-bindgen-test自訂測試框架的 eRFC 相容,為使常規 #[test]#[bench] 與 Wasm 協同工作鋪平道路,而不是需要使用 #[wasm_bindgen_test]

原理、缺點和替代方案

我們選擇在 2019 年將精力集中在

  1. 我們——Rust 和 WebAssembly 工作組——可以構建和發布功能的地方。我們在這些領域可能不會受到外部因素的阻礙,例如仍在進行中的標準。

  2. 我們可以利用 WebAssembly 領域中Rust 獨有的優勢。

我們可以構建和發布的東西

我們不希望我們的命運掌握在除了我們自己之外的任何人手中。

工具包和工具鏈的改進工作不涉及任何可能減緩我們進度的外部實體。對於除錯,如果更大的故事涉及與外部團體的大量共識和標準化工作,我們明確選擇專注於我們自己可以做些什麼來改進我們自己的除錯故事。我們不會讓自己受制於 WebAssembly 社群團體除錯子章程產生的任何東西,我們也不會等待瀏覽器供應商在開發者工具中實作新的 Wasm 除錯支援。

在路線圖項目中,多執行緒故事的風險最大:我們在這個領域的成功依賴於瀏覽器預設啟用 Wasm 的多執行緒原語。然而,這似乎是一個相對安全的賭注,因為多執行緒原語已經度過了它們最實驗性的階段,Chrome 已經預設啟用了它們,所有其他主要瀏覽器都有實作,只是尚未預設啟用。

利用獨特的優勢

我們希望將精力集中在我們能夠最大限度提高效率的地方,並將自己打造成 WebAssembly 領域的領導者,讓其他人甚至沒有辦法追趕我們。

多執行緒故事也許是獨特優勢的最大例子:多執行緒眾所周知地容易出錯(至少可以這麼說!),而 Rust 的擁有權系統在編譯時就消除了數據競爭。

透過構建模組化的函式庫工具包,我們增強了目標應用的能力範圍,從精確插入現有 JavaScript 應用程式的小型模組,到使用 Rust 構建完整的 Web 應用程式。任何依賴垃圾回收器、龐大執行環境或對 FFI 和與外部世界互動有強烈意見的語言都無法達到該範圍的小型模組端。

工具鏈的完善和除錯工作在獨特優勢方面較不明顯。但兩者都是良好開發體驗的必要條件,而且目前 Wasm 領域的這些條件的標準如此之低,以至於我們可以而且應該脫穎而出。

已考慮的替代路線圖項目

以下是一些已考慮納入路線圖的替代項目,可能是因為它們在 #RustWasm2019 的文章中被提及,但最終未被包含。

anyref 整合到 Rust 語言中

透過 wasm-bindgen,我們已經做好了充分的準備,一旦 Wasm 支援主機繫結和 GC 參考類型,我們就可以利用它們。我們可以更進一步,想像 Rust 語言未來能夠以一流的方式傳遞對替代記憶體空間(其中一些可能是 GC 管理的)中物件的不透明參考:跨記憶體空間分割的結構體、指向多個記憶體空間的胖指標等。

然而,目前尚不清楚將所有這些都推送到語言中是否會比 wasm-bindgen 已經擁有的現有 「邊緣 anyref」實現 帶來更多效用。此外,利用這項工作的成果很容易受到以下幾個方面的阻礙:anyref 尚未在任何主流 wasm 引擎中發佈,而且透過涉及所有利益相關者的更大的 Rust RFC 流程來實現這種語言級別的整合將會非常緩慢(如果它真的發生了!)。

只關注純 Rust Web 應用程式

我們更願意透過模組化工具包來回答「是,而且」純 Rust Web 應用程式,該工具包可以服務於從小型模組到整個 Web 應用程式的整個範圍,而不是僅關注整個 Web 應用程式端。我們希望透過該工具包,無論您的專案落在該範圍的哪個位置,都能夠受益。

此外,完整的 Web 應用程式並不是 Rust 的獨特優勢。JavaScript 已經這樣做了很長時間,就 Wasm 而言,該領域有資金更雄厚的「競爭對手」,它們能夠更快地提供更具吸引力的單體式 Web 應用程式開發體驗(透過與工具、現有生態系統整合,或投入資金和開發人員來解決問題)。例如,Microsoft 和 Blazor、Google 和 Go,以及使用 Emscripten 將現有的原生應用程式帶到 Web 上。我們應該在最有利的位置上競爭,而單體式 Web 應用程式不是我們的優勢。

話雖如此,如果您想使用 Rust 生成的 Wasm 構建整個 Web 應用程式,並且不想編寫任何 JavaScript 程式碼,您應該能夠做到這一點。事實上,您已經可以使用 #[wasm_bindgen(start)]no-modules 目標做到這一點。我們永遠不會移除此功能,新的工具包只會使開發整個 Web 應用程式變得更容易。

非 JavaScript 和非 Web 嵌入

雖然所有非 Web 和非 JavaScript 的 WebAssembly 嵌入看起來都非常令人興奮,但每個嵌入都是一個獨特的環境,並且目前還沒有標準的功能集可用。我們不想等待一整套標準功能的出現,也不想選擇一個特定的嵌入環境。

我們確實打算支援參考系統根目錄工作,以及之後的任何後續工作,但我們將根據機會利用這些東西,而不是將其作為路線圖項目。

我們鼓勵任何對非 JavaScript 和非 Web 嵌入感興趣的人與 WebAssembly 社群小組合作,透過定義標準 Wasm 功能來推動這一進展!

未解決的問題

待定。