使用 Yew 构建 Rust 前端 - 第一部分 Wumpus Season

2025-06-04

使用 Yew 构建 Rust 前端 - 第一部分

乌姆普斯季节

乌姆普斯季节

在本系列文章中,我们将学习如何使用Yew重现经典的“捉妖巫师 (Hunt the Wumpus) ”游戏。原版游戏是在命令行上进行的,而我们将使用网页。Yew 允许我们用 Rust 定义前端。我们的应用将被编译为WebAssembly以供执行。

这个应用需要这个吗?不需要。

应用需要这个吗?尚有争议,但很有可能。欢迎在评论区留言讨论!

我们到底会不会做?当然会!

这是一个入门级的教程——熟悉 Rust 会很有帮助,但这里没有太多花哨的内容。熟悉任何命令式语言就足够了。

我把这篇文章分成了三个部分。第一部分旨在作为你开始一个空白项目的实用指南。暂时不要开始寻找乌姆普斯,只需将填充文本替换成适合你应用的内容即可。第二部分设置了我们的基本 UI 和在洞穴中移动的机制,第三部分讨论了游戏逻辑。

编辑:您可以在这里播放已完成的应用程序!

设置

Rust 有一些很棒的工具,让编译流程相对轻松。cargo-web我们使用的 Yew 只是其中一种。如果您喜欢这里的内容,我接下来推荐您阅读RustWasm 一书。它将引导您构建一个 Game of Life<canvas>应用程序,无需使用任何复杂的框架或工具——您可以在此基础上选择所需的功能。您可以决定使用它的底层或高层级。另外,也请务必查看draco,这是一个替代的客户端 Rust->Wasm 框架。

你需要一个夜间 Rust 编译器。如果需要,可以参考rustup入门 - 很简单。你还需要cargo-webcargo install cargo-web

安装完成后,导航到你的项目目录,并cargo new hunt-the-wumpus在终端中执行 issue。用你选择的文本编辑器打开该文件夹。我们将首先添加一些内容,以确保所有内容能够编译和运行。

首先,让我们设置项目文件夹以使用内置的 Rust 目标。执行以下命令:

$ rustup override set nightly
$ echo 'default-target = "wasm32-unknown-unknown"' > Web.toml
Enter fullscreen mode Exit fullscreen mode

这将确保cargo web命令始终使用正确的目标。该rustup override命令特定于目录 - 要全局更改它,请使用rustup default nightly。我更喜欢默认使用 stable 版本,仅在必要时使用 nightly 版本。

现在让你的Cargo.toml外观如下所示:

[package]
authors = ["Hunter Wumpfrey <hw@bottomlesspit.net>"]
edition = "2018"
name = "hunt-the-wumpus"
version = "0.1.0"
[[bin]]
name = "hunt"
path = "src/main.rs"

[dependencies]
stdweb = "0.4"

[dependencies.yew]
version = "0.9.2"

[lib]
name = "hunt_the_wumpus"
path = "src/lib.rs"
Enter fullscreen mode Exit fullscreen mode

我们的大部分代码都将存在于库中,而二进制文件只是将应用程序安装到页面上。

main.rs接下来用以下内容替换您的:

extern crate hunt_the_wumpus;
extern crate yew;

use hunt_the_wumpus::Model;
use yew::prelude::App;

fn main() {
    yew::initialize();
    let app: App<Model> = App::new();
    app.mount_to_body();
    yew::run_loop();
}
Enter fullscreen mode Exit fullscreen mode

这个存根会找到我们的挂载点,并将我们的程序挂载到上面。说到这儿,我们来创建一个挂载点。问题:

$ mkdir static
$ touch static/index.html
Enter fullscreen mode Exit fullscreen mode

我们也只需要一个存根。将以下内容添加到该文件并保存:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="description" content="Hunt the wumpus!">
  <meta name="author" content="YOU">
  <title>HUNT THE WUMPUS</title>
  <link rel="stylesheet" type="text/css" href="hunt.css">
  <script src="hunt.js"></script>
</head>

<body>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

我们不需要再用它了——它只会加载我们编译好的 JS 和样式表。这个static目录也是你的图标存放的地方——我喜欢这个

现在,让我们添加基本的紫杉轮廓——我们要渲染的东西。问题:

$ touch src/lib.rs
Enter fullscreen mode Exit fullscreen mode

使用以下模板填充:

extern crate stdweb;
#[macro_use]
extern crate yew;

use yew::prelude::*;

pub struct Model {
  arrows: u8,
}

#[derive(Debug, Clone)]
pub enum Msg {}

impl Component for Model {
  type Message = Msg;
  type Properties = ();

  fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
    Model { arrows: 5 }
  }

  fn update(&mut self, _msg: Self::Message) -> ShouldRender {
    true
  }
}

impl Renderable<Model> for Model {
  fn view(&self) -> Html<Self> {
    html! {
        <div class="hunt",>
            <div class="header",>{"Hunt the Wumpus"}</div>
            <div class="body",>
              <span class="arrows",>{&format!("Arrows: {}", self.arrows)}</span>
            </div>
        </div>
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

这就是我们大多数组件的样子。如果你用过其他前端框架,应该会觉得它看起来有些熟悉。它有一个Componenttrait,我们可以在其中定义状态转换,例如createupdate,还有一个Renderable<T>trait,它使用类似 JSX 的html!宏来定义视图。然后,它借鉴了 Elm 等工具的灵感,提供了一种Msg类型来驱动update方法中的事件。我们目前还没有任何消息需要处理,所以只包含一个存根。一开始,update它会始终返回trueShouldRender并触发重绘。

在开始编码之前,我们需要设置其余的构建管道。毕竟,我们要用它yarn——毕竟它是一个 Web 应用。

$ yarn init
// answer the questions
$ yarn add -D @babel/core @babel/preset-env autoprefixer node-sass nodemon npm-run-all postcss postcss-cli rollup rollup-plugin-babel rollup-plugin-postcss rollup-plugin-uglify rollup-plugin-wasm serve
Enter fullscreen mode Exit fullscreen mode

然后将这些脚本添加到您的package.json

  "scripts": {
    "build:js": "rollup -c",
    "build:rs": "cargo web deploy --release",
    "build:scss": "node-sass --include-path scss scss/hunt.scss css/hunt.css",
    "build:css": "postcss --use autoprefixer -o static/hunt.css css/hunt.css",
    "build:style": "run-s build:scss build:css",
    "build:copy": "cp target/deploy/hunt.css release/ && cp target/deploy/hunt.wasm release/ && cp target/deploy/index.html release/ && cp target/deploy/favicon.ico release/",
    "build": "run-s clean:deploy build:rs build:js build:style build:copy",
    "clean:deploy": "rm -rf /release",
    "prod": "run-s build serve",
    "serve": "serve -p 8080 release",
    "watch:rs": "cargo web start --release",
    "test": "echo \"Error: no tests!\" && exit 1"
  },
Enter fullscreen mode Exit fullscreen mode

要设置我们的应用程序范围的样式表,请发出:

$ mkdir scss
$ touch scss/hunt.scss
Enter fullscreen mode Exit fullscreen mode

为了确保一切连接正常,请输入以下内容:

.arrows {
  font-weight: bold;
}
Enter fullscreen mode Exit fullscreen mode

现在,让我们按下大按钮。打开你的终端并输入

$ yarn build:style
$ yarn watch:rs
Enter fullscreen mode Exit fullscreen mode

最后,将浏览器指向localhost:8000。您应该会看到以下内容:

猎杀 Wumpus
箭:5

一切就绪!开发配置已生效。接下来,让我们完成以下配置.gitignore

/target
**/*.rs.bk
/node_modules
yarn-*.log
/css
/static/*.css
/release
Enter fullscreen mode Exit fullscreen mode

让我们测试一下我们的生产包。首先创建rollup.config.js并保存以下内容:

import babel from "rollup-plugin-babel"
import uglify from "rollup-plugin-uglify"

export default {
    input: './target/deploy/hunt.js',
    output: {
        name: 'hunt',
        file: './release/hunt.js',
        format: 'es',
    },
    plugins: [
        babel({
            exclude: 'node_modules/**'
        }),
        uglify
    ]
};
Enter fullscreen mode Exit fullscreen mode

现在请确保退出该watch:rs过程,然后尝试yarn prod。构建完成后,您应该在 处看到相同的输出localhost:8080

一旦一切正常,就提交!git init && git commit -m "Initial commit

请参阅此处第 1 部分末尾的完整代码。

如果您已准备好继续构建,请参阅第 2 部分

文章来源:https://dev.to/decidously/lets-build-a-rust-frontend-with-yew---part-1-3k2o
PREV
使用 Rust/WebAssembly 和 web-sys 实现 Reactive Canvas,或者说我如何学会不再担心并爱上宏
NEXT
您最喜欢的 Markdown 编辑器是什么?