石材网站源码,怎么用手机建网站,有哪些设计好看的企业官网,首页html模板前言
开门见山#xff0c;现代前端 Rust 构建基本分三大类#xff0c;即 构建 .wasm 、构建 .node 二进制 、构建 swc 插件。 入门详见 《 前端Rust开发WebAssembly与Swc插件快速入门 》 。 对于单独开发某一类的流程#xff0c;在上述参考文章中已有介绍#xff0c;但对于…前言
开门见山现代前端 Rust 构建基本分三大类即 构建 .wasm 、构建 .node 二进制 、构建 swc 插件。 入门详见 《 前端Rust开发WebAssembly与Swc插件快速入门 》 。 对于单独开发某一类的流程在上述参考文章中已有介绍但对于一次开发后全平台构建发布上述文章并未涉猎基于此本文将快速介绍一个最简的 全平台构建 包括二进制 .node 与 .wasm 前端 Rust 包的开发流程是怎样的。
注我们默认读者已掌握构建三大类前端 Rust 包的知识。
正文
Rust workspace
以 workspace 组织代码仓库核心逻辑全部独立为一个子包参考如下 - crates- binding_node # 基于 napi 分发 .node 二进制- binding_wasm # 基于 wasm-pack 分发 .wasm- core # 核心逻辑- ... # 其他解耦binding_node
其中 binding_node 为 node 构建出口引用核心逻辑后暴露 API 简式参考如下
// binding_node/src/lib.rs#[macro_use]
extern crate napi_derive;use napi::{bindgen_prelude::AsyncTask, Env, Task};
use core::{core_process, IInput, IResult};// ⬇️ 同步部分
#[napi]
pub fn method_sync(input: IInput) - ResultIResult, anyhow::Error {core_process(input)
}// ⬇️ 异步部分
pub struct TaskExecutor {input: IInput,
}pub struct ProcessTask {task: TaskExecutor,
}impl Task for ProcessTask {type Output IResult;type JsValue IResult;fn compute(mut self) - napi::ResultSelf::Output {self.task.process().map_err(|err| napi::Error::from_reason(err.to_string()))}fn resolve(mut self, _env: Env, output: Self::Output) - napi::ResultSelf::JsValue {Ok(output)}
}impl TaskExecutor {pub fn process(self) - ResultIResult, anyhow::Error {core_process(self.input.clone())}
}#[napi(ts_return_typePromiseIResult)]
pub fn method(input: IInput) - AsyncTaskProcessTask {AsyncTask::new(ProcessTask {task: TaskExecutor { input },})
}注此处为最简函数式示例涉及 异步信号、错误处理、错误打印、导出多方法的复杂类 等情况时请自行处理。
通常情况提供最普通的 同步函数 方法已足够。
类型处理
为了尽可能减少工作量让 napi 自动生成 .d.ts 类型需给结构对象加上 #[napi] 宏才能生成类型但所有结构声明在 crates/core 核心逻辑包中而我们的 napi 出口在 crates/binding_node 。
一种解法是条件编译提供 feature node 的特定模式参考如下
# core/Cargo.toml[features]
default []
node [napi, napi-derive][dependencies]
napi { ..., optional true }
napi-derive { ..., optional true }// 条件编译宏#[macro_export]
#[cfg(feature node)]
macro_rules! multi_env {($($items:item)*) {use napi_derive::napi;$(#[napi(object)]$items)*};
}使用参考
multi_env! {pub struct IInput {pub input: ...,}pub struct IResult {pub output: ...,}// ...
}综上通过特定 node feature 方式在引用时条件添加 #[napi] 来做到自动生成类型。
人工应对复杂类型
如 想自行管理导出方法类型的暴露情况、涉及 class 等复杂的类型 、无法自动识别生成 等情况可以人工编写整份 .d.ts 文件但十分耗费精力。
对于 异步情况等 引发的动态值转换而无法自动识别类型的可尝试 napi 默认自带的类型选项如 #[napi(ts_return_type...)] 等选项来辅助修改生成的类型省时省力。
构建
对于多平台我们通常需要依赖 GitHub Actions 来进行多平台构建在 CI 中构建、测试后发布到 npm 。
现代常用构建对象 napi 列表如下 triples: {defaults: false,additional: [x86_64-apple-darwin,aarch64-apple-darwin,x86_64-pc-windows-msvc,aarch64-pc-windows-msvc,x86_64-unknown-linux-gnu,aarch64-unknown-linux-gnu,x86_64-unknown-linux-musl,aarch64-unknown-linux-musl]},最常用的即如上 8 个平台酌情构建 armv7-unknown-linux-gnueabihf 必要时采用 wasm 兜底即可。
此部分过于冗长且模板化可参考 swc 等项目的构建 CI 来取用。
binding_wasm
其中 binding_wasm 为 wasm 构建出口引用核心逻辑后暴露 API 简式参考如下
use wasm_bindgen::prelude::*;use core::{core_process, IInput, IResult};#[wasm_bindgen(js_name methodSync)]
pub fn method_sync(input: IInput) - ResultIResult, JsError {core_process(input).map_err(|err| JsError::new(err.to_string()))
}#[wasm_bindgen(typescript_custom_section)]
const INTERFACE_DEFINITIONS: static str r#
export function method(config: IInput): PromiseIResult;
#;#[wasm_bindgen(skip_typescript)]
pub fn method(input: IInput) - js_sys::Promise {wasm_bindgen_futures::future_to_promise(async {core_process(input).map(|r| serde_wasm_bindgen::to_value(r).unwrap()).map_err(|err| JsValue::from_str(err.to_string()))})
}注此处为最简函数式示例涉及 异步、错误处理、错误打印 等情况时请自行修订处理。
通过 serde-wasm-bindgen 来动态转换 JS 值与 Rust 中的结构。
通常情况提供最普通的 同步函数 方法已足够。
类型处理
为了尽可能减少工作量我们使用 tsify 做自动类型生成同上文中相同采用条件编译提供 feature wasm 模式
# core/Cargo.toml[features]
default []
wasm [tsify, wasm-bindgen][dependencies]
tsify { ..., optional true }
wasm-bindgen { ..., optional true}// 条件编译宏#[macro_export]
#[cfg(feature wasm)]
macro_rules! multi_env {($($items:item)*) {use tsify::Tsify;use serde::{Deserialize, Serialize};use wasm_bindgen::prelude::*;$(#[derive(Tsify, Serialize, Deserialize)]#[tsify(into_wasm_abi, from_wasm_abi)]$items)*};
}// 兜底用
#[macro_export]
#[cfg(all(not(feature wasm), not(feature node),))]
macro_rules! multi_env {($($tokens:tt)*) {$($tokens)*};
}人工应对复杂类型
如 想自行管理导出方法类型的暴露情况、无法自动识别生成 等情况可以人工编写整份 .d.ts 文件。
对于 异步情况等 引发的动态值转换而无法自动识别类型的尝试 #[wasm_bindgen(skip_typescript)] 跳过自动生成类型后使用 #[wasm_bindgen(typescript_custom_section)] 人工插入少量类型声明来解决节省编写时间。
构建
由于 wasm 无需依赖本机环境根据情况可选在云构建或本地构建均可主要包含 web 用途与 nodejs 用途的 wasm 产物构建。
web 用途
web 用途的 wasm 产物主要用于网页应用playground 等构建命令参考 # web 用途cd crates/binding_wasm wasm-pack build --verbose --out-dir ./output/wasm_web --out-name index --releaseweb 用途的构建产物包含 ESM 格式胶水代码 可直接将产物整体用在 webpack 项目导入对于 webpack 5 可直接开启 async webassembly 特性直接适配项目
// webpack.config.jsexperiments: {asyncWebAssembly: true,},import * as wasm from /path/to/wasm-output
// 或使用异步 await import() 延时、按需加载nodejs 用途
nodejs 用途主要用于非主流平台兜底如 边缘函数、serverless 等环境构建命令参考 # nodejs 用途cd crates/binding_wasm wasm-pack build --target nodejs --verbose --out-dir ./output/wasm --out-name index --release和 web 用途构建命令区别在于特定了 --target nodejs 这会得到 CJS 格式产物代码可直接用于 nodejs 。
使用与安装时机
对于两种 wasm 包通常命名为 scope/wasm nodejs 用途 、scope/wasm-web web 用途在对应平台下可直接安装该包来使用。
同时对非主流架构环境我们一般在主包的 postinstall 时进行脚本检测并在需要时自动安装 scope/wasm 包来兜底具体逻辑较冗长且模板化可参考 swc 等项目取用即可。
如何安装指定平台包
最新版本的 pnpm v8 支持配置 pnpm.supportedArchitectures 来安装想要的平台包即使你不在某个平台上这通常用于 wasm 安装校验
# .npmrc
# 关闭 postinstall 缓存
side-effects-cachefalse
# 打印 postinstall 日志
reporterappend-only// package.json// ↓ 该配置将匹配不到任何 .node 的平台包于是自动 fallback 到 wasm 兜底包pnpm: {supportedArchitectures: {os: [unknown],cpu: [x64]}}wasm 产物优化
通常 .node 二进制产物由 Rust 生产构建后自动优化加上 strip 优化体积已足够。
对于 wasm 一般采用 wasm-opt 优化体积默认 wasm-pack 生产构建最终阶段会自动下载相关工具并执行优化如遇网络问题可关闭自动优化转为手动下载后执行优化 # 提前下载好执行工具防止网络问题cargo install wasm-bindgen-cli# binding_wasm/Cargo.toml# 关闭 wasm-opt 自动优化之后手动优化
[package.metadata.wasm-pack.profile.release]
wasm-opt false# 下载 wasm-opt 工具并解压# 最新版本见https://github.com/WebAssembly/binaryen/releasescurl -L https://github.com/WebAssembly/binaryen/releases/download/version_116/binaryen-version_116-x86_64-macos.tar.gz -o ./binaryen.tar.gzmkdir ./.cachetar -xvf ./binaryen.tar.gz -C ./.cache# 优化 wasm 产物./.cache/binaryen-version_116/bin/wasm-opt -Oz -o ./output/wasm/index_bg.wasm ./output/wasm/index_bg.wasm总结
在全平台构建时编写 十分大量 的人力脚本与文件操作在所难免如有可能可将其统一抽象化方便下次取用。
由于流程更偏向于固定模板化在实践时请自行参考相关项目自取所需即可。