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);

这个示例展示了如何创建包引用和配置注册表。您可以根据需要扩展此代码以处理更复杂的场景。


1 回复

以下是基于您提供的完整内容整理的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"

这个完整示例展示了:

  1. WASM包初始化和管理
  2. 内存分配和释放
  3. Rust与JavaScript之间的数据转换
  4. 性能分析工具的使用
  5. 错误处理的最佳实践
  6. 异步包发布功能

使用时请确保已经按照文档配置好wasm-bindgen和wasm-pack工具链。

回到顶部