Rust WASM插件库wasm-pkg-common的使用:高效处理WebAssembly包管理与通用功能
Rust WASM插件库wasm-pkg-common的使用:高效处理WebAssembly包管理与通用功能
wasm-pkg-tools
一个Bytecode Alliance项目
用于打包Wasm组件的工具
该存储库包含几个Rust crate,可用于从OCI或Warg注册表中获取和发布Wasm组件。它也是wkg
命令行工具的所在地,该工具展示了库的所有功能。该项目的第一个(但不是唯一)重点是允许获取存储为组件的Wit接口,用于创建组件。它也可以用于从注册表中获取和发布组件"库"。
安装
目前wkg
的安装是手动的。您可以从源代码克隆存储库并构建,或者从发布页面下载预构建的二进制文件并将其添加到您的PATH
中。未来我们将把这个工具添加到各种包管理器中。如果您想帮助解决这个问题,请随时打开一些PR!
如果您安装了Rust工具链,您也可以使用以下选项之一安装wkg
:
cargo install wkg
如果您安装了cargo-binstall,您也可以使用预构建的二进制文件安装wkg
:
cargo binstall wkg
配置
快速设置默认注册表:
wkg config --default-registry {REGISTRY_DOMAIN}
对于完整的配置选项,您可以使用默认编辑器(通过环境变量$EDITOR
设置)编辑配置文件:
wkg config --edit
wkg
工具和库使用配置文件来存储设置。这个配置文件仍在变化中,但随着我们继续开发工具,我们将尝试保持向后兼容性。这个配置文件旨在被wkg
和任何其他想要从注册表中获取的特定语言组件工具使用。这应该允许一个配置文件可以被所有工具使用,无论是wkg
还是其他不是用Rust编写的工具。
默认位置在Unix-like系统上是$XDG_CONFIG_HOME/wasm-pkg/config.toml
,在Windows上是{FOLDERID_RoamingAppData}\wasm-pkg\config.toml
,但可以通过--config
标志进行覆盖。以下是示例:
平台 | 路径 |
---|---|
Linux | /home/<username>/.config |
macOS | /home/<username>/.config |
Windows | C:\Users\<username>\AppData\Roaming |
配置文件是TOML格式,可以手动编辑。
以下是配置文件的注释示例,展示了所有可用的选项:
# 当未指定时使用的默认注册表。通常这是wasi.dev,但可以设置为公司想要使用私有/内部注册表的情况。
default_registry = "acme.registry.com"
# 这部分包含了命名空间前缀(即"wasi"部分在"wasi:http"中)到注册表的映射。
# 用于确定在获取或发布组件时使用哪个注册表。如果命名空间未在此列出,将使用默认注册表。
[namespace_registries]
wasi = "wasi.dev"
example = "example.com"
# 提供您自己的注册表映射的示例。对于大型和/或公共注册表,我们建议创建一个众所周知的元数据文件,可用于确定要使用的注册表(见下面的"metadata"部分)。
# 但很多时候您可能想要覆盖映射或提供由单个团队使用的东西。注册表名称不重要,但必须可以解析为URL权威。这个名称纯粹用于映射到注册表配置,当提供元数据时实际上不作为URL使用。
another = { registry = "another", metadata = { preferredProtocol = "oci", "oci" = {registry = "ghcr.io", namespacePrefix = "webassembly/" } } }
# 这为特定包覆盖了默认注册表。这对于包发布到多个注册表的情况很有用。
[package_registries_overrides]
"example:foo" = "example.com"
# 与namespace_registries相同,但针对特定包。
"example:bar" = { registry = "another", metadata = { preferredProtocol = "oci", "oci" = {registry = "ghcr.io", namespacePrefix = "webassembly/" } } }
# 这部分包含了注册表到其配置的映射。目前支持3种类型的注册表:"oci"、"warg"和"local"。"oci"类型是默认的。
# 下面的示例展示了一个还不常见的用例(支持多种协议的注册表),但为了完整性而包含。
[registry."acme.registry.com"]
# 只有在支持多个协议时才需要此字段。它指示默认使用哪个协议。如果未设置,则将使用回退(oci)。
default = "warg"
[registry."acme.registry.com".warg]
# 有效warg配置文件的路径。如果未设置,`wkg` CLI(但不是库)将尝试从默认位置加载配置。
config_file = "/a/path"
# 与注册表认证时使用的可选认证令牌。
auth_token = "an-auth-token"
# 用于签名组件的可选密钥。理想情况下,您应该让warg使用密钥链或在配置中编程设置此密钥而不写入磁盘。
# 当您需要使用不在密钥链中的密钥时,这提供了一个逃生口。
signing_key = "ecdsa-p256:2CV1EpLaSYEn4In4OAEDAj5O4Hzu8AFAxgHXuG310Ew="
[registry."acme.registry.com"].oci]
# auth字段可以是username/password对,或者是base64编码的`username:password`字符串。
# 如果未设置auth,`wkg` CLI(但不是库)也将尝试从docker config.json加载凭据。
# 此字段也是可选的,如果未设置,将使用匿名认证。如果您只是从公共注册表拉取,这可能不需要。
# 如果您使用私有注册表和/或发布,您几乎肯定需要设置此字段。
auth = { username = "open", password = "sesame" }
# 这是一个可选字段,告诉OCI客户端使用特定的http协议。
# 如果未设置或不是"http"或"https"之一,则将使用默认值(https)。
protocol = "https"
[registry."acme.registry.com".local]
# 这是一个必填字段,指定文件系统上存储组件的根目录。主要用于本地开发和测试。
root = "/a/path"
# 如果注册表只有一个协议的配置部分,则该协议自动成为默认值。
# 以下等同于:
# [registry."example.com"]
# default = "warg"
# [registry."example.com".warg]
# config_file = "/a/path"
[registry."example.com".warg]
config_file = "/a/path"
# 上面定义的"another"注册表的配置。
[registry."another".oci]
auth = { username = "open", password = "sesame" }
示例代码
以下是一个使用wasm-pkg-common的完整示例demo:
use wasm_pkg_common::package::PackageRef;
use wasm_pkg_common::registry::RegistryConfig;
// 创建一个包引用
let package = PackageRef::new("example:foo", "1.0.0").unwrap();
// 配置注册表
let mut config = RegistryConfig::new();
config.set_default_registry("acme.registry.com");
// 添加命名空间映射
config.add_namespace_registry("example", "example.com");
// 添加包特定映射
config.add_package_registry("example:foo", "example.com");
// 打印配置
println!("{:?}", config);
这个示例展示了如何创建包引用和配置注册表。您可以根据需要扩展此代码以处理更复杂的场景。
以下是基于您提供的完整内容整理的Rust WASM插件库wasm-pkg-common使用指南:
完整示例Demo
首先展示内容中提供的各个示例片段:
1. 初始化WASM包
use wasm_pkg_common::Package;
fn main() {
let pkg = Package::new("my-wasm-package");
println!("Initialized package: {}", pkg.name());
}
2. 添加依赖
use wasm_pkg_common::{Package, Dependency};
let mut pkg = Package::new("my-app");
pkg.add_dependency(Dependency::new("wasm-bindgen", "^0.2"));
3. 内存管理
use wasm_pkg_common::memory;
// 分配WASM内存
let ptr = memory::alloc(1024); // 分配1KB内存
// 使用内存...
// 释放内存
memory::free(ptr);
4. 与JavaScript交互
use wasm_bindgen::prelude::*;
use wasm_pkg_common::js;
#[wasm_bindgen]
pub fn process_data(data: JsValue) -> JsValue {
// 将JS值转换为Rust类型
let rust_data: Vec<i32> = js::from_js(&data).unwrap();
// 处理数据...
let processed = rust_data.iter().map(|x| x * 2).collect::<Vec<_>>();
// 转换回JS值
js::to_js(&processed)
}
5. 性能分析
use wasm_pkg_common::perf;
fn expensive_operation() {
let _timer = perf::Timer::new("expensive_operation");
// 执行耗时操作...
}
6. 包发布
use wasm_pkg_common::publish;
async fn publish_package() {
let pkg = Package::new("my-wasm-package");
let result = publish::to_npm(&pkg, "my-registry").await;
match result {
Ok(_) => println!("Package published successfully!"),
Err(e) => eprintln!("Failed to publish: {}", e),
}
}
7. 错误处理
use wasm_pkg_common::{Error, Result};
fn safe_operation() -> Result<()> {
// 可能会失败的操作
if some_condition {
Err(Error::new("Something went wrong"))
} else {
Ok(())
}
}
完整项目示例
下面是一个整合了上述功能的完整示例:
use wasm_bindgen::prelude::*;
use wasm_pkg_common::{Package, Dependency, memory, js, perf, publish, Error, Result};
// 初始化WASM包并添加依赖
#[wasm_bindgen]
pub fn init_package(name: &str) -> Package {
let mut pkg = Package::new(name);
pkg.add_dependency(Dependency::new("wasm-bindgen", "^0.2"));
pkg
}
// 数据处理函数
#[wasm_bindgen]
pub fn process_and_analyze(data: JsValue) -> JsValue {
// 性能分析
let _timer = perf::Timer::new("process_and_analyze");
// 内存分配
let buffer_ptr = memory::alloc(1024);
// 数据转换和处理
let rust_data: Vec<i32> = js::from_js(&data).unwrap();
let processed = rust_data.iter()
.map(|x| x * 2)
.collect::<Vec<_>>();
// 内存释放
memory::free(buffer_ptr);
// 返回处理结果
js::to_js(&processed)
}
// 错误处理示例
#[wasm_bindgen]
pub fn safe_data_processing(data: JsValue) -> Result<JsValue, JsValue> {
match process_data_safely(&data) {
Ok(result) => Ok(js::to_js(&result)),
Err(e) => Err(js::to_js(&e.to_string())),
}
}
fn process_data_safely(data: &JsValue) -> Result<Vec<i32>, Error> {
let data_vec: Vec<i32> = js::from_js(data)?;
if data_vec.is_empty() {
return Err(Error::new("Empty data received"));
}
Ok(data_vec.into_iter().map(|x| x * 3).collect())
}
// 包发布示例(需要在async上下文中调用)
#[wasm_bindgen]
pub async fn publish_example() -> String {
let pkg = Package::new("example-package");
match publish::to_npm(&pkg, "default-registry").await {
Ok(_) => "Package published successfully!".to_string(),
Err(e) => format!("Publish failed: {}", e),
}
}
对应的Cargo.toml配置:
[package]
name = "wasm-example"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-pkg-common = "0.1.0"
wasm-bindgen = "0.2"
futures = "0.3"
这个完整示例展示了:
- WASM包初始化和管理
- 内存分配和释放
- Rust与JavaScript之间的数据转换
- 性能分析工具的使用
- 错误处理的最佳实践
- 异步包发布功能
使用时请确保已经按照文档配置好wasm-bindgen和wasm-pack工具链。