大小仅为Rust四分之一!MoonBit 现已支持Wasm组件模型

使用 MoonBit 开发 Wasm 组件模型

Wasm组件

WebAssembly(Wasm)是一种新的低级虚拟指令集标准(low-level virtual instruction set standard),用于沙箱模型。低级的,意味着它接近原生速度。虚拟的,意味着它可以在包括浏览器和操作系统在内的多个运行时(runtime)上运行,例如wasmtimewamr。它是沙箱模型,这意味着它不能与外界交互,除非使用FFI。不过FFI只能返回数字,因此通过线性内存进行数据传输是更有效的方法。许多编程语言都可以编译成Wasm,包括Java、JavaScript/TypeScript、Python、Rust以及当然还有MoonBit

那么如何结合用不同编程语言实现的Wasm组件呢?我们便需要引入组件模型(component model),一个统一接口的提案。通过组件模型,我们可以定义一个高级抽象的API。只要接口匹配,组件就可以与不同组件结合。

本文将介绍如何使用MoonBit编写一个输出"Hello World"的小型HTTP服务器。通过本教程我们可以看出,MoonBit在开发Wasm组件模型时实现了高兼容性和互操作性,同时能够显著减少输出大小。

操作步骤

我们将编写一个小型HTTP服务器,它将使用MoonBit打印"Hello World"。先决条件如下:

定义WIT(Wasm Interface Type)

首先,你需要使用WIT定义接口(如何使用详见官方手册)。

wit/deps.toml中指定依赖项。本教程中仅使用wasi-http版本0.2.0。

toml 复制代码
http = "https://github.com/WebAssembly/wasi-http/archive/v0.2.0.tar.gz"

使用wit-deps更新依赖项,在wit/deps文件夹中可以看到所有依赖项。

然后我们在wit/world.wit中指定"世界"对应于生成的Wasm:

wit 复制代码
package moonbit:example;

world server {
  export wasi:http/incoming-handler@0.2.0;
}

一个"世界"可以包含其他"世界",或导入/导出接口。这里我们导出wasi:http版本0.2.0的incoming-handler接口,因为HTTP服务器需要导出一个传入处理程序接口,以便运行时可以使用它来处理传入请求并生成响应。

生成代码

在这一步骤,我们会使用wit-bindgen生成代码。你可以利用这个命令安装:

bash 复制代码
cargo install wit-bindgen-cli --git https://github.com/peter-jerry-ye/wit-bindgen/ --branch moonbit

获得wit-bindgen命令后,只需使用适当的子命令(moonbit)和WIT文件的位置(wit)执行它。还有参数用于指定类型是否应派生Showtrait 或Eqtrait。

bash 复制代码
wit-bindgen moonbit wit --derive-show --derive-eq --out-dir .

你将获得以下内容:

bash 复制代码
.
├── ffi
│  ├── moon.pkg.json
│  └── top.mbt
├── gen
│  ├── ffi.mbt
│  ├── interface_exports_wasi_http_incoming_handler_export.mbt
│  ├── moon.pkg.json
│  └── worlds_server_export.mbt
├── interface
│  ├── exports
│  │  └── wasi
│  │     └── http
│  │        └── incomingHandler
│  │           ├── moon.pkg.json
│  │           ├── README.md
│  │           └── top.mbt
│  └── imports
│     └── wasi
│        ├── clocks
│        │  └── monotonicClock
│        │     ├── moon.pkg.json
│        │     ├── README.md
│        │     └── top.mbt
│        ├── http
│        │  └── types
│        │     ├── moon.pkg.json
│        │     ├── README.md
│        │     └── top.mbt
│        └── io
│           ├── error
│           │  ├── moon.pkg.json
│           │  └── top.mbt
│           ├── poll
│           │  ├── moon.pkg.json
│           │  ├── README.md
│           │  └── top.mbt
│           └── streams
│              ├── moon.pkg.json
│              ├── README.md
│              └── top.mbt
├── moon.mod.json
├── wit // contents ignored here
└── worlds
   └── server
      ├── import.mbt
      ├── moon.pkg.json
      └── top.mbt

生成的项目有四个文件夹:

  • ffigen是生成的帮助Wasm绑定的文件,可以忽略。gen目录包含项目入口。

  • interface包含所有导入到所选"世界"的接口。分为importsexportsimports提供所有导入的函数和类型,而exports包含你所要导出的函数以及一个空实现(panic())。

  • worlds包含"世界"。与interface类似,它包含一个import.mbt,提供"世界"级别的导入函数和类型,以及一个top.mbt,包含导出函数的模板。

然后你可以像开发一般MoonBit应用一样继续开发。此时moon check --target wasm应该能够成功通过。你可以通过运行moon doc --serve查看API以及类型或函数的注释文档。别忘了执行moon fmt来格式化程序。

开发

以下是我们用于演示的实现最小输出的"Hello-World"服务器代码:

rust 复制代码
pub fn handle(
  request : @types.IncomingRequest,
  response_out : @types.ResponseOutparam
) -> Unit {
  let response = match request.path_with_query() {
      None | Some("/") => make_response(b"Hello, World")
      _ => make_response(b"Not Found", status_code=404)
    }
    |> Ok
  response_out.set(response)
}

fn make_response(
  body : Bytes,
  ~status_code : UInt = 200
) -> @types.OutgoingResponse {
  ...
}

完整示例见moonbit-docs/examples/wasi-http

组件化

我们已经实现了一个核心Wasm,即一个遵循WebAssembly标准的Wasm。然而,我们需要将其转变为一个组件,以便可以将必要的信息------接口------一并分发。

你需要使用wasm-tools将核心Wasm嵌入到组件中。首先将WIT信息嵌入到核心Wasm的自定义部分中,此步骤需要指定编码为UTF-16。然后我们将核心Wasm转换为组件Wasm。

bash 复制代码
moon build --target wasm
wasm-tools component embed wit target/wasm/release/build/gen/gen.wasm -o target/wasm/release/build/gen/gen.wasm --encoding utf16
wasm-tools component new target/wasm/release/build/gen/gen.wasm -o target/wasm/release/build/gen/gen.wasm

如果你更喜欢使用npmpnpm,也可以使用JCO来完成此步骤。

使用

利用我们创建的Wasm,可以使用Wasmtime进行托管:

bash 复制代码
wasmtime serve target/wasm/release/build/gen/gen.wasm

你也可以使用JCO在Node.js或Deno上进行服务,或者使用WasmCloudSpin进行托管。

比较

至此,我们已经实现了一个简单的仅输出 "Hello World" 的 HTTP 服务器。下表为 MoonBit 与主流编程语言生成的http-hello-world大小对比(基于WasmCloud的模板)

语言 输出尺寸
Python 17M
TypeScript 8.7M
Rust 100K
MoonBit 27K

结论

我们展示了如何使用MoonBit创建一个遵循组件模型标准的Wasm。组件模型为创建可互操作的Wasm提供了新标准。比如我们能够通过从Spin中提取WIT文件,在5分钟内轻松构建一个无服务器AI应用。

通过支持WebAssembly组件模型,MoonBit增强了其在微服务架构和云原生应用中的应用场景,具有高编译性能和紧凑代码尺寸,允许在各种环境中快速部署和执行。

在8月18日,MoonBit将达到beta预览版本,表明着我们在语言方面已达到一定的稳定性,适合投入更加广泛的测试与实际应用环境。未来,我们将继续拓展MoonBit生态系统,优化文档和工具链,以提供更好的用户体验。敬请期待!

相关推荐
Alive~o.08 分钟前
Go语言进阶&依赖管理
开发语言·后端·golang
花海少爷10 分钟前
第十章 JavaScript的应用课后习题
开发语言·javascript·ecmascript
手握风云-11 分钟前
数据结构(Java版)第二期:包装类和泛型
java·开发语言·数据结构
喵叔哟31 分钟前
重构代码中引入外部方法和引入本地扩展的区别
java·开发语言·重构
尘浮生37 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
hopetomorrow1 小时前
学习路之PHP--使用GROUP BY 发生错误 SELECT list is not in GROUP BY clause .......... 解决
开发语言·学习·php
小牛itbull1 小时前
ReactPress vs VuePress vs WordPress
开发语言·javascript·reactpress
请叫我欧皇i1 小时前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
闲暇部落1 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
GIS瞧葩菜1 小时前
局部修改3dtiles子模型的位置。
开发语言·javascript·ecmascript