Catsify 是什么?
Catsify 是一款猫咪名字生成器,托管在 Azure 静态 Web 应用上。其技术栈包括:
在本指南中,我们将了解如何采用前端 Angular 应用程序、用 Rust 编写并编译为 Web Assembly 的后端 API,并将所有内容部署到全新Azure 静态 Web 应用程序服务上的无服务器环境中。
虽然 UI 是用Angular编写的,但这款应用的有趣之处在于,其后端 API 的核心部分——生成器,完全用 Rust 编写,然后编译为 Web Assembly(简称 WASM)。公共 API 通过无服务器 Azure Function 暴露在 Node.js 的后台。
让我们开始吧...
我们要开发一款猫咪取名应用。我喜欢猫,相信你也一样。这款应用能帮你为心爱的宠物找到独一无二的猫咪名字。
⚡️ 在https://catsify.app上试用该应用⚡️
我们的应用程序结构如下(仅显示重要部分):
.
├── api
│ ├── dist
│ │ └── func
│ ├── func
│ ├── ...
│ ├── Cargo.toml
│ └── rust
├── app
│ ├── dist
│ │ └── ui
│ ├── ...
│ └── src
├── ...
└── scripts
一些亮点:
api
是标准的 Azure Functions App 文件夹。api/func
包含 Node.js 无服务器功能。api/rust
包含 Rust 源代码。app
包含 Angular 源代码。和...
api/dist/func
包含API构建工件。app/dist/ui
包含APP构建工件。接下来我们将描述每个堆栈的作用:Rust/WASM、Node.js、Angular;然后解释每个部分是如何构建和部署的。
我们的公共后端 API 是一个充当Façade的 Node.js Azure Function 。
在./api/func/index.ts
文件中,我们只需导入并调用“a”generate()
函数(参见下一部分),获取结果并将结果发送回客户端。
以下是代码的简化版本:
const { generate } = require("./wasm_loader");
const func = async function (context, req) {
const name = await generate();
const [adjective, noun] = name.split(" ");
context.res = {
body: {
adjective,
noun,
},
};
};
export default func;
然而,在./api/func/wasm_loader.ts
文件中,奇迹发生了,我们实际上加载了从 Rust 编译的 WASM 模块(参见 Rust 故事),调用该generate_name_str
函数,传入种子参数,并解码结果字符串输出。
以下是代码的简化版本:
const fs = require('fs');
const path = require('path');
// the WASM file is copied to dis/func during the build
const wasmFile = path.join(__dirname, 'generator.wasm');
// a bunch of utilities to decode the WASM binary
function getInt32Memory(wasm) {...}
function getUint8Memory(wasm) {...}
function getStringFromWasm(wasm, ptr, len) {...}
// export a JavaScript function
export const generate = async function() {
// load the WASM module
const bytes = new Uint8Array(fs.readFileSync(wasmFile));
const result = await WebAssembly.instantiate(bytes);
const wasm = await Promise.resolve(result.instance.exports);
// setup args
const retptr = 8;
const seed = Date.now() % 1000 | 0;
// invoke the WASM code
const ret = wasm.generate_name_str(retptr, seed);
// decode result
const memi32 = getInt32Memory(wasm);
const v0 = getStringFromWasm(...);
wasm.__wbindgen_free(...);
// this is final the decoded name
return v0;
};
这不是 Rust 代码或 WASM 的深度指南。您可以在Rust 官方网站上了解 Rust 和 WASM 。
正如我之前提到的,后端 API 的主要部分是用 Rust 编写的名称生成器。
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn generate_name_str(seed: i32) -> String {
// the seed is coming from the JS side
let a = seed % (ADJECTIVES.len() as i32);
let b = seed % (NOUNS.len() as i32);
[ADJECTIVES[a as usize].to_string(), " ".to_string(), NOUNS[b as usize].to_string()].join("")
}
const ADJECTIVES: [&str; 1116] = [
"aback",
"abaft",
//...
];
const NOUNS: [&str; 1201] = [
"abbey",
"abbie",
//...
];
// used for debugging only
pub fn main() {
println!("{:?}", generate_name_str(1));
}
无需赘述,我们基本上使用两个 Rust 向量来存储猫的名词和形容词,然后从每个向量中选择一个随机值来构造一个字符串。该generate_name_str
函数使用 outer 属性从 Rust 导出到 JavaScript #[wasm_bindgen]
。这将使我们能够从 JavaScript 代码中调用此函数,并传入 seed 参数。
该 Angular 应用是使用Angular CLI版本 10.0.0-next.4生成的。经典配置!
我们的 Node.js Azure Function Node.js 代码是用 TypeScript 编写的,因此我们使用tsc
它将其转换为 JavaScript 并将结果输出到./dist/func
文件夹中。
cd api
tsc # will create ./dist/func/
对于 Rust 代码,为了编译它并生成 WASM 模块,我们使用[wasm-pack](https://github.com/rustwasm/wasm-pack)
:
cd api
wasm-pack build # will create ./pkg/
并且以下配置api/Cargo.toml
:
[dependencies]
wasm-bindgen = "0.2.58"
[lib]
crate-type = ["cdylib", "rlib"]
path = "rust/lib.rs"
[[bin]]
name = "generator"
path = "rust/lib.rs"
[profile.release]
lto = true
panic = "abort"
# Tell `rustc` to optimize for small code size.
opt-level = "s"
注意:
wasm-pack
生成一个 Node.js 包装器来加载 WASM 模块。由于我们自己编写了加载器,所以我们只关注*.wasm
文件本身。然后,我们需要将 WASM 文件复制到./api/dist/func
:
cp pkg/catsify_bg.wasm dist/func/generator.wasm
构建 Angular 应用非常简单。Angular CLI 负责处理所有事情:
ng build --prod
此命令将在 下生成应用程序包./app/dist/ui
。
cd api
tsc # builds the Azure function.
wasm-pack build # builds the WASM module.
cp pkg/catsify_bg.wasm \
dist/func/generator.wasm
cd ../app
ng build --prod # builds the front-end app.
现在我们已经创建了一个前端 Angular 应用程序和一个后端无服务器 API,那么在 Azure 上最容易实现静态无服务器的应用程序是什么?
静态 Web 应用是 Azure 应用服务推出的一项新功能。它是一种全新且简化的托管选项,适用于由无服务器 API 提供支持的现代 Web 应用。
静态 Web 应用程序提供:
注意:Azure Static Web Apps 创建的YML 工作流文件已使用自定义构建步骤进行了更新。
Catsify 是一款猫咪名字生成器,托管在 Azure 静态 Web 应用上。其技术栈包括: