Web 前端和 WASM 结合起来, 实现一个看板.

概述

拟实现一个简单的任务看板, 用于管理任务状态.

最初版本需求如下:

  1. 可以展示任务的 ToDo, Doing, Done, Closed 状态.
  2. 可以将任务拖动到不同状态.
  3. 可以新建任务, 修改任务信息, 删除任务.

主要目的:

  1. 调查几种技术集成的方式.
  2. 调查 WASM 的几种部署方式.

调查

工程骨架初始化主要参考: https://www.tkat0.dev/posts/how-to-create-a-react-app-with-rust-and-wasm/

  1. React 看板 UI 实现.
  2. Rust WASM 实现.
  3. 以及如何同 React 前端进行数据交互.

React 前端

前端使用 React + TypeScript, 利用 create-react-app 命令创建项目, 为简化处理, 状态先存放在 Rust WASM 侧, 后续考虑数据库持久化.

  1. 初始化工程: npx create-react-app . --template typescript
  2. 修改了一下代码验证.

Rust 核心

  1. 初始化一个 Rust WASM 项目, 由于项目已创建好目录, 只需要在目录中创建一个 lib 即可, 因此使用到的命令是: cargo init --lib .

  2. 需要将工程设置为 cdylib, 并添加 wasm-bindgen 依赖, 以便将需要导出的函数进行标记, 如下所示:

    在 Cargo.toml 中设置:

    toml
    [lib]
    crate-type = ["cdylib"]
    
    [dependencies]
    wasm-bindgen = "0.2.78"
    rust
    use wasm_bindgen::prelude::*;
    
    #[wasm_bindgen]
    pub fn add(left: usize, right: usize) -> usize {
        left + right
    }

对接

  1. 安装 wasm-pack 以便之后将 rust 代码打包为 wasm: cargo install wasm-pack

  2. 在前端工程中添加一个脚本, 用于打包 wasm: "build:wasm": "cd <rust 工程目录> && wasm-pack build --target web --out-dir <便于前端使用的打包目录>", 比如:

    json
    "build:wasm": "cd ../wasm-rust && wasm-pack build --target web --out-dir pkg",
  3. 前端添加对应依赖项: npm install ../wasm-rust/pkg, 此时 package.json 中会多出来一条依赖记录:

    json
    "wasm-rust": "file:../wasm-rust/pkg",
  4. 在前端调用:

    ts
    import React, { useEffect, useState } from "react";
    import logo from "./logo.svg";
    import "./App.css";
    import init, { add } from "wasm-rust";
    
    function App() {
      const [ans, setAns] = useState(0);
      useEffect(() => {
        init().then(() => {
          setAns(add(1, 1));
        });
      }, []);
    
      return (
        <div className="App">
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <p>
              Edit <code>src/App.tsx</code> and save to reload.
            </p>
            <a
              className="App-link"
              href="https://reactjs.org"
              target="_blank"
              rel="noopener noreferrer"
            >
              Learn React with Ease
            </a>
            <p>1 + 1 = {ans}</p>
          </header>
        </div>
      );
    }
    
    export default App;

实现

实现时, 选型如下:

  1. 前端: React
  2. 底层: Rust WASM
  3. 前端和底层交互.

前端实现: 看板 UI 实现

(参考 fullstack-react-with-typescript 一书)

前端配合 Rust 的 WASM 实现, 实际就是将 UI 放到 React, 前端业务逻辑放到 “客户端 wasm” 中. 暂未进行后端业务开发, 后期考虑放到 CF 的 worker 上.

这里主要看前端的 UI 实现.

UI 提供的动作, 将数据传入底层, 获取到结果后确认展示即可.

前端实现: WASM 业务逻辑

业务逻辑主要是任务和列表的管理.