Hello, World!
本节将向你展示如何构建和运行你的第一个 Rust 和 WebAssembly 程序:一个警告“Hello,World!”
开始之前,请确保已按照安装说明进行操作。
克隆项目模板
项目模板预先配置了 sane 默认值,因此你可以快速构建、集成和打包Web代码。
使用以下命令克隆项目模板:
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 库而正确初始化的 crainte type。
wasm-game-of-life/src/lib.rs
src/lib.rs 文件是我们正在编译到 WebAssembly 的 Rust crate 的根文件。它使用 wasm bindgen 与JavaScript 接口。它导入 window.alert JavaScript 函数,并导出名为 greet Rust 函数,该函数用于创建警告弹窗消息。
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 构建的步骤:
- 确保我们有 Rust 1.30 或更新版本,并且通过
rustup安装了wasm32 unknowntarget, - 经过
cargo,将我们的 Rust 源代码编译成为 WebAssembly.wasm的二进制文件, - 使用
wasm bindgen生成 JavaScript API,以使用我们的 Rust-generated WebAssembly。
要执行所有这些操作,请在项目目录中运行以下命令:
wams-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,并将一个优雅的 API 开放给 JavaScript 的 WebAssembly 函数。
例如,下面的 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 包用于 Web 页面,我们可以使用 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 的依赖关系,它是已发布到 npm 的初始 wasm-pack-templatek的一个版本。
wasm-game-of-life/www/webpack.config.js
这个文件配置了 webpack 以及本地开发服务器。 它是预先配置好的,不需要任何调整或配置即可在本地运行了。
wasm-game-of-life/www/index.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 模板的编译 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 and 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": { // Add this three lines block!"wasm-game-of-life": "file:../pkg"},"devDependencies": {//...}}
然后引入 wasm-game-of-life 到文件 wasm-game-of-life/www/index.js 里面,而不是 hello-wasm-pack 包:
import * as wasm from "wasm-game-of-life";wasm.greet();
既然我们新增了依赖,那我们就需要更新一下:
npm install
接着,我们的网页现在可以在本地运行了!
在本地运行
接下来,为开发服务器打开一个新终端。
在一个新的终端上运行服务器可以让它在后台运行,同时不会阻止我们运行其他命令。
在新终端中,从 wasm-game-of-life/www 目录中运行以下命令:
npm run start
打开浏览器进入 http://localhost:8080,将会出现弹窗警告信息。

更改之后,如果希望出现在 http://localhost: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 二进制文件,然后在浏览器重新打开 http://localhost:8080 ,将会出现自定义的弹窗警告信息。
答案
将新的函数 greet 写在 wasm-game-of-life/src/lib.rs:
#[wasm_bindgen]pub fn greet(name: &str) {alert(&format!("Hello, {}!", name));}
可以使用调用方式
wasm.greet("Name");
