Hello,世界!
本節將示範如何建立並執行您的第一個 Rust 和 WebAssembly 程式:一個會彈出「Hello,世界!」警示的網頁。
在開始前,請確認您已遵循 設定說明。
複製專案範本
此專案範本預設為妥善設定,讓您能快速建置、整合和封裝您的程式碼,以在網路上使用。
使用此指令複製專案範本
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
的依賴項和元資料,而 cargo
是 Rust 的套件管理員和建構工具。其中預先設定的資料包括 wasm-bindgen
依賴項、一些我們將在稍後深入了解的選用依賴項,以及已妥善初始化的 crate-type
,用於產生 .wasm
函式庫。
wasm-game-of-life/src/lib.rs
src/lib.rs
檔案是我們編譯為 WebAssembly 的 Rust 箱根。它使用 wasm-bindgen
與 JavaScript 介接。它匯入了 window.alert
JavaScript 函數,並匯出了 greet
Rust 函數,其中會發出問候訊息。
# #![allow(unused_variables)] #fn main() { extern crate cfg_if; extern crate wasm_bindgen; mod utils; use cfg_if::cfg_if; use wasm_bindgen::prelude::*; cfg_if! { // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global // allocator. if #[cfg(feature = "wee_alloc")] { extern crate 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
產生的,其中包含 Javascript 黏著劑,用於將 DOM 及 JavaScript 函數匯入 Rust 中,並向 JavaScript 公開 WebAssembly 函數的良好 API。舉例來說,有一個 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
檔案包含 TypeScript 類型宣告,用於 JavaScript 黏著劑。如果您正在使用 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
套件並在網頁中使用它,我們使用 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
,這是一個 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 綁定套件及其開發伺服器。
請注意,
webpack
不是處理 Rust 和 WebAssembly 所必需的,它只是我們在此處為方便起見選擇的綁定套件和開發伺服器。Parcel 和 Rollup 也應支援將 WebAssembly 匯入為 ECMAScript 模組。您也可以使用 Rust 和 WebAssembly 不用綁定套件,如果您想要的話!
在 www
中使用我們的本機 wasm-game-of-life
套件
我們不使用 npm 的 hello-wasm-pack
套件,而是希望使用我們自己的本機 wasm-game-of-life
套件。這將讓我們逐步開發我們的生命遊戲程式。
開啟 wasm-game-of-life/www/package.json
並編輯 "dependencies"
來包含 "wasm-game-of-life": "file:../pkg"
項目
{
// ...
"dependencies": {
"wasm-game-of-life": "file:../pkg", // Add this line!
// ...
}
}
再來,修改 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
二進位檔,然後在你的瀏覽器中更新 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");