你好,世界!
本節將說明如何建立並執行您第一個 Rust 和 WebAssembly 程式:顯示「你好,世界!」的網頁。
在開始前,請務必按照設定說明進行操作。
複製專案範本
專案範本預先設定好合理的預設值,讓您可以快速為網頁建立、整合和封裝您的程式碼。
使用此指令複製專案範本
cargo generate --git https://github.com/rustwasm/wasm-pack-template
這將會提示您輸入新專案的名稱。我們將使用「wasm-game-of-life」。
wasm-game-of-life
內含什麼內容
進入新的 wasm-game-of-life
專案
cd wasm-game-of-life
了解它的內容
wasm-game-of-life/
├── Cargo.toml
├── LICENSE_APACHE
├── LICENSE_MIT
├── README.md
└── src
├── lib.rs
└── utils.rs
讓我們詳細看看其中幾個檔案。
wasm-game-of-life/Cargo.toml
Cargo.toml
檔案為 cargo
(Rust 的套件管理員和建置工具)指定了依賴項和資料。此檔案預先設定了一項 wasm-bindgen
依賴項、幾個我們稍後將深入探討的選用依賴項,以及為產生 .wasm
函式庫而正確初始化的 crate-type
。
wasm-game-of-life/src/lib.rs
src/lib.rs
檔案是我們編譯成 WebAssembly 的 Rust Crate 的根目錄。它使用 wasm-bindgen
與 JavaScript 介接。它匯入 window.alert
JavaScript 函式,並匯出 greet
Rust 函式,用於提醒問候語訊息。
# #![allow(unused_variables)] #fn main() { mod utils; use wasm_bindgen::prelude::*; // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global // allocator. #[cfg(feature = "wee_alloc")] #[global_allocator] static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; #[wasm_bindgen] extern { fn alert(s: &str); } #[wasm_bindgen] pub fn greet() { alert("Hello, wasm-game-of-life!"); } #}
wasm-game-of-life/src/utils.rs
模組 src/utils.rs
提供常見的實用程式,讓處理編譯成 WebAssembly 的 Rust 變得更容易。我們稍後會在教學中更詳細地查看其中一些實用程式,例如在我們檢視 除錯我們的 wasm 程式碼 時,但我們現在可以忽略這個檔案。
建置專案
我們使用 wasm-pack
編排下列建置步驟
- 確保我們已經透過
rustup
安裝 Rust 1.30 或更新版本和wasm32-unknown-unknown
目標, - 使用
cargo
將我們的 Rust 原始碼編譯成 WebAssembly.wasm
執行檔, - 使用
wasm-bindgen
為使用我們 Rust 生成的 WebAssembly 產生 JavaScript API。
要執行以上所有操作,請在專案目錄中執行這個指令
wasm-pack build
建置完成後,我們可以在 pkg
目錄中找到其產出,它應該有這些內容
pkg/
├── package.json
├── README.md
├── wasm_game_of_life_bg.wasm
├── wasm_game_of_life.d.ts
└── wasm_game_of_life.js
README.md
檔案從主專案複製,但其他檔案是全新的。
wasm-game-of-life/pkg/wasm_game_of_life_bg.wasm
.wasm
檔案是 Rust 編譯器根據我們的 Rust 原始碼產生的 WebAssembly 執行檔。它包含所有我們的 Rust 函式和資料以編譯成 wasm 的版本。例如,它有已匯出的「greet」函式。
wasm-game-of-life/pkg/wasm_game_of_life.js
.js
檔案由 wasm-bindgen
產生,包含將 DOM 和 JavaScript 函式匯入 Rust 以及公開 WebAssembly 函式提供極好的 JavaScript API 的 JavaScript 黏合。例如,有一個 JavaScript greet
函式包裹 WebAssembly 模組匯出的 greet
函式。現在,這個黏合並沒有做太多事情,但當我們開始在 wasm 和 JavaScript 之間傳遞更多有趣的數值時,這將有助於將這些數值引導跨越邊界。
import * as wasm from './wasm_game_of_life_bg';
// ...
export function greet() {
return wasm.greet();
}
wasm-game-of-life/pkg/wasm_game_of_life.d.ts
.d.ts
檔案包含 JavaScript 黏合的 TypeScript 型別宣告。如果您正在使用 TypeScript,您可以讓系統檢查呼叫 WebAssembly 函式的型別,而且您的 IDE 可以提供自動完成和建議!如果您沒有使用 TypeScript,您可以安全地忽略這個檔案。
export function greet(): void;
wasm-game-of-life/pkg/package.json
package.json
檔案包含有關產生的 JavaScript 和 WebAssembly 套件的元資料。 npm 和 JavaScript 打包器使用這項功能來確定套件之間的依賴關係、套件名稱、版本和其他許多東西。這有助於我們整合 JavaScript 工具,並允許我們將我們的套件發佈到 npm。
{
"name": "wasm-game-of-life",
"collaborators": [
"Your Name <your.email@example.com>"
],
"description": null,
"version": "0.1.0",
"license": null,
"repository": null,
"files": [
"wasm_game_of_life_bg.wasm",
"wasm_game_of_life.d.ts"
],
"main": "wasm_game_of_life.js",
"types": "wasm_game_of_life.d.ts"
}
將其放入網頁
要擷取我們的 wasm-game-of-life
套件並在網頁中使用它,我們使用 the create-wasm-app
JavaScript 專案範本。
在 wasm-game-of-life
目錄中執行這個指令
npm init wasm-app www
我們新的 wasm-game-of-life/www
子目錄包含以下內容
wasm-game-of-life/www/
├── bootstrap.js
├── index.html
├── index.js
├── LICENSE-APACHE
├── LICENSE-MIT
├── package.json
├── README.md
└── webpack.config.js
讓我們再次仔細查看其中幾個檔案。
wasm-game-of-life/www/package.json
這個 package.json
已經預先設定好 webpack
和 webpack-dev-server
相依項目,以及一個 hello-wasm-pack
相依項目,這是最初的 wasm-pack-template
套件已發布到 npm 的版本。
wasm-game-of-life/www/webpack.config.js
這個檔案會設定 webpack 和其本機開發伺服器。它已經預先設定好,你不應該需要修改這個任何設定來讓 webpack 和其本機開發伺服器正常運作。
wasm-game-of-life/www/index.html
這是網頁的根目錄 HTML 檔案。除了載入 bootstrap.js
之外,它並未執行太多動作,而 bootstrap.js
是 index.js
的一個很薄的包裝器。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello wasm-pack!</title>
</head>
<body>
<script src="./bootstrap.js"></script>
</body>
</html>
wasm-game-of-life/www/index.js
index.js
是網頁 JavaScript 的主要進入點。它會匯入 hello-wasm-pack
npm 套件,其中包含預設的 wasm-pack-template
已編譯好的 WebAssembly 與 JavaScript 黏合程式,然後呼叫 hello-wasm-pack
的 greet
函數。
import * as wasm from "hello-wasm-pack";
wasm.greet();
安裝相依項目
首先,確保本機開發伺服器及其相依項目已安裝,方法是在 wasm-game-of-life/www
子目錄中執行 npm install
。
npm install
這個指令只需要執行一次,它將安裝 webpack
JavaScript 捆綁器及其開發伺服器。
請注意,使用 Rust 和 WebAssembly 不需要
webpack
,它只是一個我們在此出於方便而選擇的捆綁器和開發伺服器。Parcel 和 Rollup 也應支援匯入 WebAssembly 作為 ECMAScript 模組。如果你願意,你也可以使用沒有捆綁器的 Rust 和 WebAssembly in a bundler!
在 www
中使用我們的本機 wasm-game-of-life
套件
我們不希望使用來自 npm 的 hello-wasm-pack
套件,而是希望改用我們的本機 wasm-game-of-life
套件。這樣讓我們可以逐步開發我們的 Game of Life 程式。
開啟 wasm-game-of-life/www/package.json
,在 "devDependencies"
旁邊,新增 "dependencies"
欄位,包括 "wasm-game-of-life": "file:../pkg"
項目。
{
// ...
"dependencies": { // Add this three lines block!
"wasm-game-of-life": "file:../pkg"
},
"devDependencies": {
//...
}
}
接著,修改 wasm-game-of-life/www/index.js
以匯入 wasm-game-of-life
,而不是 hello-wasm-pack
套件。
import * as wasm from "wasm-game-of-life";
wasm.greet();
由於我們新增一個相依項目,我們需要安裝它。
npm install
我們的網頁現在準備好可以在本機伺服!
在本地端提供服務
接著,為開發伺服器開啟一個新的終端機。在一個新的終端機中執行伺服器讓我們可以讓它在背景中執行,而且這不會阻擋我們在此同時執行其他指令。在新終端機中,從 wasm-game-of-life/www
目錄執行這個指令:
npm run start
在你的網頁瀏覽器導航到 https://127.0.0.1:8080/,你應該會看到一個快顯訊息。
每次您進行變更並希望反映在 https://127.0.0.1:8080/ 中,只需在 wasm-game-of-life
目錄中重新執行 wasm-pack build
命令即可。
練習
-
修改
wasm-game-of-life/src/lib.rs
中的greet
函式以接受自訂提醒訊息的name: &str
參數,並將您的姓名傳遞給wasm-game-of-life/www/index.js
中的greet
函式。使用wasm-pack build
重新建置.wasm
執行檔,然後在您的 Web 瀏覽器中重新整理 https://127.0.0.1:8080/,您應該會看到自訂的歡迎訊息!解答
wasm-game-of-life/src/lib.rs
中的greet
函式的新版本# #![allow(unused_variables)] #fn main() { #[wasm_bindgen] pub fn greet(name: &str) { alert(&format!("Hello, {}!", name)); } #}
wasm-game-of-life/www/index.js
中greet
的新呼叫wasm.greet("Your Name");