如何為通用專用容器加入 WebAssembly 支援
本節適用於想要支援 WebAssembly 的通用專用容器作者。
您的專用容器可能已支援 WebAssembly!
檢閱有關資訊 哪些情況可能會讓通用專用容器無法移植至 WebAssembly。如果您的專用容器沒有這些情況,很有可能已支援 WebAssembly!
您隨時可以執行 cargo build
來檢查 WebAssembly 目標
cargo build --target wasm32-unknown-unknown
如果指令失敗,表示您的專用容器目前不支援 WebAssembly。如果沒有失敗,表示您的專用容器可能支援 WebAssembly。您可以 新增對 wasm 的測試,並在 CI 中執行這些測試,以 100% 確定專用容器確實支援 WebAssembly(並持續支援中)。
加入對 WebAssembly 的支援
避免直接執行 I/O
在網路上,I/O 始終是非同步的,且沒有檔案系統。將 I/O 從您的函式庫中提供出來,讓使用者執行 I/O,然後再將輸入部分傳遞至您的函式庫。
例如,重新整理這段
# #![allow(unused_variables)] #fn main() { use std::fs; use std::path::Path; pub fn parse_thing(path: &Path) -> Result<MyThing, MyError> { let contents = fs::read(path)?; // ... } #}
变成這樣
# #![allow(unused_variables)] #fn main() { pub fn parse_thing(contents: &[u8]) -> Result<MyThing, MyError> { // ... } #}
將 wasm-bindgen
新增為相依性
如果您需要與外界互動(即您不能讓函式庫消費者為您驅動該互動),則當編譯目標為 WebAssembly 時,您需要新增 wasm-bindgen
(如果需要,還要新增 js-sys
和 web-sys
)作為相依性。
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2"
js-sys = "0.3"
web-sys = "0.3"
避免同步 I/O
如果您必須在函式庫中執行 I/O,則不能同步執行。在 Web 上只有非同步 I/O。使用 futures
crate 和 wasm-bindgen-futures
crate 來管理非同步 I/O。如果您的函式庫函數針對某些未來類型 F
為通用,則可以在 Web 上透過 fetch
或透過作業系統提供的非區塊 I/O 來實作該未來類型。
# #![allow(unused_variables)] #fn main() { pub fn do_stuff<F>(future: F) -> impl Future<Item = MyOtherThing> where F: Future<Item = MyThing>, { // ... } #}
您也可以定義特徵,並為 WebAssembly 和 Web 以及本機目標實作該特徵
# #![allow(unused_variables)] #fn main() { trait ReadMyThing { type F: Future<Item = MyThing>; fn read(&self) -> Self::F; } #[cfg(target_arch = "wasm32")] struct WebReadMyThing { // ... } #[cfg(target_arch = "wasm32")] impl ReadMyThing for WebReadMyThing { // ... } #[cfg(not(target_arch = "wasm32"))] struct NativeReadMyThing { // ... } #[cfg(not(target_arch = "wasm32"))] impl ReadMyThing for NativeReadMyThing { // ... } #}
避免產生執行緒
Wasm 尚未支援執行緒(但 實驗性工作正在進行中),因此嘗試在 wasm 中產生執行緒會引發錯誤。
您可以使用 #[cfg(..)]
來啟用執行緒化和非執行緒化程式碼路徑,視目標是否為 WebAssembly
# #![allow(unused_variables)] #![cfg(target_arch = "wasm32")] #fn main() { fn do_work() { // Do work with only this thread... } #![cfg(not(target_arch = "wasm32"))] fn do_work() { use std::thread; // Spread work to helper threads.... thread::spawn(|| { // ... }); } #}
另一個選項是從函式庫中取出執行緒產生程式碼,並允許使用者「自備執行緒」,類似於取出檔案 I/O 並允許使用者自備 I/O。這會讓想擁有自家自訂執行緒池的應用程式感到滿意。
維護對 WebAssembly 的持續支援
針對 wasm32-unknown-unknown
在 CI 中建置
透過讓您的 CI 腳本執行下列指令,確保編譯不會在目標為 WebAssembly 時失敗
rustup target add wasm32-unknown-unknown
cargo check --target wasm32-unknown-unknown
例如,您可以將這新增到您針對 Travis CI 的 .travis.yml
組態中
matrix:
include:
- language: rust
rust: stable
name: "check wasm32 support"
install: rustup target add wasm32-unknown-unknown
script: cargo check --target wasm32-unknown-unknown
在 Node.js 和無頭瀏覽器中進行測試
您可以使用 wasm-bindgen-test
和 wasm-pack test
子指令在 Node.js 或無頭瀏覽器中執行 wasm 測試。您甚至可以將這些測試整合到您的 CI 中。