当前位置: 首页 > java >正文

Rust Web 全栈开发(十一):WebAssembly 尝鲜

Rust Web 全栈开发(十一):WebAssembly 尝鲜

  • Rust Web 全栈开发(十一):WebAssembly 尝鲜
    • 什么是 WebAssembly?
    • 安装 wasm-pack 和 cargo-generate
    • 使用项目模板
    • 构建项目
    • 生成网页
    • 安装依赖项
    • 在 www 中使用本地的 wasm-pack-template 包
    • 本地服务

Rust Web 全栈开发(十一):WebAssembly 尝鲜

参考视频:https://www.bilibili.com/video/BV1RP4y1G7KF

继续之前的 Actix 项目。

我们已经实现了一个 Web App,在网页端查看并操作数据库中教师的数据。现在我们想创建一个 WebAssembly App,查看并操作数据库中课程的数据。

在这里插入图片描述

什么是 WebAssembly?

WebAssembly 是一种新的编码方式,可以在现代浏览器中运行。

  • 它是一种低级的类汇编语言
  • 具有紧凑的二进制格式
  • 可以接近原生的性能运行
  • 并为 C/C++、C#、Rust 等语言提供一个编译目标,以便它们可以在 Web 上运行
  • 它也被设计为可以与 JavaScript 共存,允许两者一起工作

WebAssembly 不是汇编语言,它不针对特定的机器,而是中间编译器目标,针对浏览器。

在这里插入图片描述

WebAssembly 有两种格式:

  • 文本格式,后缀为 .wat
  • 二进制格式,后缀为 .wasm

WebAssembly 能做什么?

  • 可以把你编写 C/C++、C#、Rust 等语言的代码编译成 WebAssembly 模块
  • 你可以在 Web 应用中加载该模块,并通过 JavaScript 调用它
  • 它并不是为了替代 JS,而是与 JS 一起工作
  • 仍然需要 HTML 和 JS,因为 WebAssembly 无法访问平台 API,例如 DOM、WebGL …

在这里插入图片描述

一个 C 语言的例子:

在这里插入图片描述

  • 快速、高效、可移植:通过利用常见的硬件能力,WebAssembly 代码在不同平台上能够以接近本地速度
    运行。

  • 可读、可调试:WebAssembly 是一门低阶语言,但是它有确实有一种人类可读的文本格式(其标
    准最终版本目前仍在编制),这允许通过手工来写代码,看代码以及调试代码。

  • 保持安全:WebAssembly 被限制运行在一个安全的沙箱执行环境中。像其他网络代码一样,它遵循浏览器的同源策略和授权策略。

  • 不破坏网络:WebAssembly 的设计原则是与其他网络技术和谐共处并保持向后兼容。

安装 wasm-pack 和 cargo-generate

官方文档:https://rustwasm.github.io/docs/book/game-of-life/setup.html

  • wasm-pack 是构建、测试和发布 Rust 生成的 WebAssembly 的一站式商店。

  • cargo-generate 通过利用已有的 git 存储库作为模板,帮助你快速启动并运行新的 Rust 项目。

命令行执行以下两个命令:

cargo install wasm-pack
cargo install cargo-generate

使用项目模板

官方文档:https://rustwasm.github.io/docs/book/game-of-life/hello-world.html

项目模板预先配置了相同的默认值,因此你可以快速构建、集成和打包 Web 代码。

回到 Actix 项目的最顶层,在终端中用下面的命令克隆项目模板:

cargo generate --git https://github.com/rustwasm/wasm-pack-template

这里我一直 git 不下来:

在这里插入图片描述

就直接下载 zip,解压到 Actix 项目的最顶层了。

在这里插入图片描述

因为是手动添加的 wasm-pack-template,需要将其手动添加为 members:

在这里插入图片描述

先来看看 wasm-pack-template 的 Cargo.toml:

[package]
name = "{{project-name}}"
version = "0.1.0"
authors = ["{{authors}}"]
edition = "2018"[lib]
crate-type = ["cdylib", "rlib"][features]
default = ["console_error_panic_hook"][dependencies]
wasm-bindgen = "0.2.84"# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.7", optional = true }[dev-dependencies]
wasm-bindgen-test = "0.3.34"[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"

其中最核心的是依赖中的 wasm-bindgen,用于绑定生成器。

修改一下字段:

在这里插入图片描述

再来看 src 目录下的 lib.rs,这是我们要编译到 WebAssembly 的 Rust crate 的根文件。它使用 wasm-bindgen 与 JavaScript 进行交互。它导入 JavaScript 函数 alert,并导出 Rust 函数 greet,该函数会发出问候消息的警报。

mod utils;use wasm_bindgen::prelude::*;#[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-pack-template!");
}

在 Rust 中,想要调用前端的函数,需要这样声明:

#[wasm_bindgen]
extern {fn alert(s: &str);
}

Rust 函数想要被前端调用,需要加上 #[wasm_bindgen]。

在前端中,想要调用 Rust 的函数,需要这样声明:

#[wasm_bindgen]
pub fn greet() {alert("Hello, wasm-pack-template!");
}

将 alert 中的字符串改为 “Hello, wasm-pack-template!”。

utils.rs 模块提供了常用的实用程序,使 Rust 更容易编译到 WebAssembly。例如,在调试 wasm 代码时,这个文件很有用,但是我们现在可以忽略这个文件。

构建项目

我们使用 wasm-pack 编排以下构建步骤:

  • 确保我们有 Rust 1.30 或更新的版本,并且通过 Rust 安装了 wasm32-unknown-unknown 目标。

  • 通过 cargo 将 Rust 源代码编译成 WebAssembly .wasm 二进制文件。

  • 使用 wasm-bindgen 来生成 JavaScript API,以便使用 Rust 生成的 WebAssembly。

要完成所有这些,cd 到 wasm-pack-template 目录下,执行命令:

wasm-pack build

构建成功:

在这里插入图片描述

当构建完成后,我们可以在 pkg 目录中找到它的工件:

在这里插入图片描述

下面讲解几个重要的文件。

wasm-pack-template/pkg/wasm-pack-template_bg.wasm:由 Rust 编译器从 Rust 源代码生成的 WebAssembly 二进制文件。它包含所有 Rust 函数和数据的编译到 wasm 的版本。例如,它有一个导出的 greet 函数。

wasm-pack-template/pkg/wasm-pack-template.js:

import * as wasm from "./wasm_pack_template_bg.wasm";
export * from "./wasm_pack_template_bg.js";
import { __wbg_set_wasm } from "./wasm_pack_template_bg.js";
__wbg_set_wasm(wasm);
wasm.__wbindgen_start();

wasm-pack-template/pkg/wasm-pack-template.js 是包含 JavaScript 的胶水代码,由 wasm-bindgen 生成。它包含 JavaScript glue,用于将 DOM 和 JavaScript 函数导入 Rust,并将 WebAssembly 中的函数暴露给 JavaScript。

例如,有一个 JavaScript greet 函数,它包装了从 WebAssembly 模块导出的 greet 函数。现在,这种粘合并没有做太多的事情,但是当我们开始在 wasm 和 JavaScript 之间来回传递更多值时,它将帮助引导这些值跨越边界。

这里有问题,我把 wasm-pack-template/pkg/wasm-pack-template.js 改成了这样:

// import * as wasm from "./wasm_pack_template_bg.wasm";
import * as wasm from "./wasm_pack_template";
export * from "./wasm_pack_template_bg.js";
// import { __wbg_set_wasm } from "./wasm_pack_template_bg.js";
// __wbg_set_wasm(wasm);
// wasm.__wbindgen_start();
export function greet() {alert("Hello, wasm-pack-template!");
}

wasm-pack-template/pkg/wasm-pack-template.d.js:

/* tslint:disable */
/* eslint-disable */
export function greet(): void;

此类 .d.js 文件包含用于 JavaScript glue 的 TypeScript 类型声明。如果你使用 TypeScript,你可以检查调用 WebAssembly 函数的类型。如果你不使用 TypeScript,你可以安全地忽略这个文件。

wasm-pack-template/pkg/package.json:

{"name": "wasm-pack-template","type": "module","collaborators": ["xiye <812288728@qq.com>"],"version": "0.1.0","files": ["wasm_pack_template_bg.wasm","wasm_pack_template.js","wasm_pack_template_bg.js","wasm_pack_template.d.ts"],"main": "wasm_pack_template.js","types": "wasm_pack_template.d.ts","sideEffects": ["./wasm_pack_template.js","./snippets/*"]
}

package.json 文件包含生成的 JavaScript 和 WebAssembly 包的元数据。它被 npm 和 JavaScript 打包器用来确定包之间的依赖关系、包名、版本和其他一些东西。它帮助我们集成 JavaScript 工具,并允许我们将包发布到 npm。

生成网页

要获取 wasm-pack-template 包并在 Web 页面中使用它,我们需要使用 create-wasm-app 这个 JavaScript 项目模板。

首先下载 create-wasm-app 这个库:

npm install -g create-wasm-app

在 wasm-pack-template 目录下运行这个命令:

npm init wasm-app www

构建成功:

在这里插入图片描述

在 wasm-pack-template 目录下生成了一个 www 目录,与 pkg 目录并列:

在这里插入图片描述

让我们仔细看看其中的一些文件。

wasm-pack-template/www/package.json:

{"name": "create-wasm-app","version": "0.1.0","description": "create an app to consume rust-generated wasm packages","main": "index.js","bin": {"create-wasm-app": ".bin/create-wasm-app.js"},"scripts": {"build": "webpack --config webpack.config.js","start": "webpack-dev-server"},"repository": {"type": "git","url": "git+https://github.com/rustwasm/create-wasm-app.git"},"keywords": ["webassembly","wasm","rust","webpack"],"author": "Ashley Williams <ashley666ashley@gmail.com>","license": "(MIT OR Apache-2.0)","bugs": {"url": "https://github.com/rustwasm/create-wasm-app/issues"},"homepage": "https://github.com/rustwasm/create-wasm-app#readme","devDependencies": {"hello-wasm-pack": "^0.1.0","webpack": "^4.29.3","webpack-cli": "^3.1.0","webpack-dev-server": "^3.1.5","copy-webpack-plugin": "^5.0.0"}
}

这个 package.json 预先配置了 webpack 和 webpack-dev-server 依赖项,以及对 hello-wasm-pack 的依赖项,它是发布到 npm 的初始 wasm-pack-template 包的一个版本。

wasm-pack-template/www/webpack.config.js:

const CopyWebpackPlugin = require("copy-webpack-plugin");
const path = require('path');module.exports = {entry: "./bootstrap.js",output: {path: path.resolve(__dirname, "dist"),filename: "bootstrap.js",},mode: "development",plugins: [new CopyWebpackPlugin(['index.html'])],
};

该文件配置 webpack 及其本地开发服务器。它是预先配置的,你根本不需要调整它来让 webpack 和它的本地开发服务器工作。

wasm-pack-template/www/index.html:

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Hello wasm-pack!</title></head><body><noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript><script src="./bootstrap.js"></script></body>
</html>

这是 Web 页面的根 HTML 文件。除了加载 bootstrap.js 之外,它没有做太多的事情,这是 index.js 的一个非常薄的包装。

wasm-pack-template/www/index.js:

import * as wasm from "hello-wasm-pack";wasm.greet();

这是 Web 页面 JavaScript 的主要入口点。它导入 hello-wasm-pack npm 包,其中包含默认的 wasm-pack-template 的编译 WebAssembly 和 JavaScript glue,然后调用 hello-wasm-pack 的 greet 函数。

安装依赖项

首先,通过在 wasm-pack-template/www 子目录下运行 npm install,确保本地开发服务器及其依赖已经安装:

在这里插入图片描述

这个命令只需要运行一次,就会安装 webpack JavaScript 打包器和它的开发服务器。

注意,使用 Rust 和 WebAssembly 并不需要 webpack,它只是我们为了方便而选择的打包器和开发服务器。Parcel 和 Rollup 还应该支持将 WebAssembly 作为 ECMAScript 模块导入。如果你愿意,你也可以使用 Rust 和 WebAssembly 而不使用捆绑器。

在 www 中使用本地的 wasm-pack-template 包

向 wasm-pack-template/www/package.json 中添加依赖:

  "dependencies": {"wasm-pack-template": "file:../pkg"},

修改 wasm-pack-template/www/index.js,不使用 hello-wasm-pack 中的 greet 函数,而使用我们的 greet 函数:

// import * as hello_wasm from "hello-wasm-pack";
import * as wasm from "wasm-pack-template";wasm.greet();

因为依赖有修改,需要再次在 wasm-pack-template/www 子目录下运行 npm install:

在这里插入图片描述

现在,我们的 Web 页面现在可以在本地访问了!

本地服务

接下来,为开发服务器打开一个新终端。在新终端中运行服务器可以让它在后台运行,并且不会阻止我们同时运行其他命令。在新的终端中,从 wasm-pack-template/www 目录中运行以下命令:

npm run start

构建成功:

在这里插入图片描述

将 Web 浏览器导航到 localhost:8081/,应该会看到一条警告消息:

在这里插入图片描述

任何时候进行更改并希望它们反映在 localhost:8081/ 上,只需在 wasm-pack-template 目录中重新运行 wasm-pack build 命令。

http://www.xdnf.cn/news/16471.html

相关文章:

  • 数学建模——模糊综合评价
  • 【C语言网络编程基础】TCP 服务器详解
  • java8+springboot2.5.4环境Markdwon转word
  • SecureCRT连接密钥交换失败
  • Sql server开挂的OPENJSON
  • fchdir系统调用及示例
  • Git+宝塔面板部署Hugo博客
  • CodeBLEU:面向代码合成的多维度自动评估指标——原理、演进与开源实践
  • 三色标记法
  • Spring经典“送命题”:BeanFactory vs FactoryBean
  • GPT 生成一个打字练习页面
  • 基于LNMP架构的分布式个人博客搭建
  • Mysql中的索引详解
  • 浅谈智能体经济(上篇)——人机共生、生态自治的未来经济形态
  • JavaScript单线程实现异步
  • 「iOS」————MRC
  • Python爬虫实战:研究netaddr库相关技术构建IP地址信息采集分析系统
  • 【NLP实践】三、LLM搭建中文知识库:提供RestfulAPI服务
  • 解决GoLand运行go程序报错:Error: Cannot find package xxx 问题
  • 3.JDK+JRE组件构成与协作
  • Qt 窗口 工具栏QToolBar、状态栏StatusBar
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现标签条码一维码的检测(C#代码,UI界面版)
  • 基于Django的天气数据可视化分析预测系统
  • 背包DP之多重背包
  • python 阿里云 安装 dashscope的简介、安装
  • 【数据结构与算法】数据结构初阶:详解排序(二)——交换排序中的快速排序
  • 算法竞赛阶段二-数据结构(36)数据结构双向链表模拟实现
  • bash的特性-bash中的引号
  • 力扣131:分割回文串
  • 智能化设备健康管理:中讯烛龙预测性维护系统引领行业变革