Wasm 是什么? MDN 官方文檔 [1] 是這樣給出定義
WebAssembly(為了書寫方便,簡稱 Wasm)是一種新的編碼方式,可以在現(xiàn)代的網(wǎng)絡(luò)瀏覽器中運行 - 它是一種低級的類匯編語言,具有緊湊的二進制格式,可以接近原生的性能運行,并為諸如 C / C 等語言提供一個編譯目標,以便它們可以在 Web 上運行。它也被設(shè)計為可以與 JavaScript 共存,允許兩者一起工作。
對于網(wǎng)絡(luò)平臺而言,WebAssembly 具有巨大的意義——它提供了一條途徑,以使得以各種語言編寫的代碼都可以以接近原生的速度在 Web 中運行。在這種情況下,以前無法以此方式運行的客戶端軟件都將可以運行在 Web 中。
WebAssembly 被設(shè)計為可以和 JavaScript 一起協(xié)同工作——通過使用 WebAssembly 的 JavaScript API,你可以把 WebAssembly 模塊加載到一個 JavaScript 應(yīng)用中并且在兩者之間共享功能。這允許你在同一個應(yīng)用中利用 WebAssembly 的性能和威力以及 JavaScript 的表達力和靈活性,即使你可能并不知道如何編寫 WebAssembly 代碼。
在學(xué)習(xí)于航老師的《WebAssembly 入門課》開篇詞中,老師是這樣總結(jié)的“WebAssembly 是基于棧式虛擬機的虛擬二進制指令集(V-ISA),它被設(shè)計為高級編程語言的可移植編譯目標”。
帶著好奇心,開啟我們的 Wasm 學(xué)習(xí)之路,創(chuàng)建屬于自己的第一個 Wasm 應(yīng)用。
環(huán)境安裝 Rust [2] 一門賦予每個人 構(gòu)建可靠且高效軟件能力的語言。
# macOS curl --proto '=https' --tlsv1.2 -sSf https://sh. | sh# 其他安裝方式 # https://forge./infra/other-installation-methods.html
# 版本更新 rustup update# 查看版本 cargo --version# 構(gòu)建項目 cargo build# 運行項目 cargo run# 測試項目 cargo test # 為項目構(gòu)建文檔 cargo doc# 將庫發(fā)布到 crates.io cargo publish# nightly rust rustup toolchain install nightly rustup toolchain list rustup override set nightly
Node.js[3] Node.js 是基于 Chrome 的 V8 JavaScript 引擎構(gòu)建的 JavaScript 運行時
wasm-pack[4] 用于構(gòu)建和使用您希望與 JavaScript,瀏覽器或 Node.js 互操作的Rust生成的 WebAssembly。
# macOS curl https://rustwasm./wasm-pack/installer/init.sh -sSf | sh# 其他安裝方式 # https://rustwasm./wasm-pack/installer # 創(chuàng)建 # https://rustwasm./docs/wasm-pack/commands/new.html wasm-pack new <name> --template <template> --mode <normal|noinstall|force># 構(gòu)建 # https://rustwasm./docs/wasm-pack/commands/build.html wasm-pack build [--out-dir <out>] [--out-name <name>] [--<dev|profiling|release>] [--target <bundler|nodejs|web|no-modules>] [--scope <scope>] [mode <normal|no-install>]# 測試 # https://rustwasm./docs/wasm-pack/commands/test.html wasm-pack test # 發(fā)包 # https://rustwasm./docs/wasm-pack/commands/pack-and-publish.html # npm pack wasm-pack pack# npm publish wasm-pack publish
Vite[5] 下一代前端工具
vite-plugin-rsw [6] :vite 插件集成 wasm-pack,實現(xiàn)熱更新以及構(gòu)建# vite項目中安裝 npm i -D vite-plugin-rsw# or yarn add -D vite-plugin-rsw快速開始 在原有vite項目中使用,只需安裝配置vite-plugin-rsw插件即可。 新項目可以使用vite提供的@vitejs/app初始化項目,然后安裝配置vite-plugin-rsw。 新項目推薦使用我的腳手架create-xc-app,會定期更新維護相關(guān)版本依賴。 create-xc-app [7]
?? 在幾秒鐘內(nèi)創(chuàng)建一個項目!維護了多種基于 vite,deno 等的前端項目模板。
npx create-xc-app my-wasm-app --template wasm-react
創(chuàng)建 Wasm 包 # 兩種方式 # name如果以@開頭創(chuàng)建npm組織包 # 會被轉(zhuǎn)成中劃線連接,需要手動修改文件夾名稱 wasm-pack new <name># or # name可以是npm組織 # 例:cargo new --lib @rsw/hello # 需要手動配置Cargo.toml cargo new --lib <name>
項目結(jié)構(gòu) # 推薦目錄結(jié)構(gòu) [my-wasm-app] # 項目根路徑 |- [rust-crate] # npm包`rust-crate` | |- [pkg] # 生成wasm包的目錄 | |- [src] # rust源代碼 | | # 了解更多: https://doc./cargo/reference/cargo-targets.html | |- [target] # 項目依賴,類似于npm的`node_modules` | | # 了解更多: https://doc./cargo/reference/manifest.html | |- Cargo.toml # rust包管理清單 | `- ... |- [@rsw] # npm 組織包 | |- [hello] # @rsw/crate, 目錄結(jié)構(gòu)同`rust-crate` | `- ... |- [node_modules] # 前端的項目包依賴 |- [src] # 前端源代碼(可以是vue, react, 或其他) | # 了解更多: https://v/learn/the-package-json-guide |- package.json # `npm`或`yarn`包管理清單 | # 了解更多: https://v/config |- vite.config.ts # vite配置文件 | # 了解更多: https://www./docs/handbook/tsconfig-json.html |- tsconfig.json # vite配置文件 ` ...
乍一看,可能會覺得目錄有點復(fù)雜,其實它就是一個標準的基于vite前端項目,然后,在根路徑下添加我們需要構(gòu)建的 wasm 包(一個 rust crate 會對應(yīng)生成一個 wasm 包,可單獨發(fā)布到 npm 上)
項目配置 Step1: vite.config.ts
// 以react項目為例 import reactRefresh from '@vitejs/plugin-react-refresh' ;import { defineConfig } from 'vite' ;import ViteRsw from 'vite-plugin-rsw' ;export default defineConfig({ plugins : [ reactRefresh(), // 更多配置:https://github.com/lencx/vite-plugin-rsw ViteRsw({ // 包含生產(chǎn)和開發(fā)模式 mode : 'release' , crates : [ // 包名稱,支持npm組織 '@rsw/chasm' ] }), ], })Step2: rust-crate/Cargo.toml
# ... [lib] # https://doc./reference/linkage.html crate-type = ['cdylib'] wasm-opt = false # https://doc./cargo/reference/profiles.html # dev | release | test | bench [profile.release] lto = true opt-level = 's' # https://doc./cargo/guide/dependencies.html # 指定依賴項:https://doc./cargo/reference/specifying-dependencies.html # 依賴包及版本管理,與npm的`package.json`類似 [dependencies] wasm-bindgen = '0.2.69'
Step3: rust-crate/src/lib.rs
use wasm_bindgen::prelude::*;// Import the `window.alert` function from the Web. #[wasm_bindgen] extern 'C' { fn alert (s: &str ); }// Export a `greet` function from Rust to JavaScript, that alerts a hello message. #[wasm_bindgen] pub fn greet (name: &str ) { alert(&format! ('Hello, {}!' , name)); }Step4: src/App.tsx
import React, { useEffect } from 'react' ;import init, { greet } from 'wasm-test' ;import logo from './logo.svg' ;import './App.css' ;function App ( ) { useEffect(() => { // wasm初始化,在調(diào)用`wasm-test`包方法時 // 必須先保證已經(jīng)進行過初始化,否則會報錯 // 如果存在多個wasm包,則必須對每一個wasm包進行初始化 init(); }, []) return ( <div className ='App' > <header className ='App-header' > <img src ={logo} className ='App-logo' alt ='logo' /> <p > Hello WebAssembly!</p > <p > Vite Rust React</p > <p > {/* 調(diào)用greet方法 */} <button onClick ={() => greet('wasm')}>hi wasm</button > </p > <p > Edit <code > App.tsx</code > and save to test HMR updates.</p > </header > </div > ) }export default App
完整代碼示例 源碼: https://github.com/lencx/learn-wasm