feat(runtime): upgrade to WASI Preview 2 + Component Model

Replaces the wasmtime-runtime run_module implementation:
- wasmtime::Module → wasmtime::component::Component
- wasmtime::Linker<WasiCtx> → wasmtime::component::Linker<State>
- wasmtime_wasi::add_to_linker → wasmtime_wasi::add_to_linker_sync
- _start typed func call → wasmtime_wasi::bindings::sync::Command::instantiate + call_run

Config now sets wasm_component_model(true). State struct implements WasiView
(ctx + table). app.wasm must be a WASI 0.2 component; core modules are no
longer supported.
This commit is contained in:
Marco Allegretti 2026-03-11 15:03:16 +01:00
parent d425fa8328
commit e56daf6570

View file

@ -55,32 +55,61 @@ fn run_module(_wasm_path: &std::path::Path) -> anyhow::Result<()> {
#[cfg(feature = "wasmtime-runtime")] #[cfg(feature = "wasmtime-runtime")]
fn run_module(wasm_path: &std::path::Path) -> anyhow::Result<()> { fn run_module(wasm_path: &std::path::Path) -> anyhow::Result<()> {
use anyhow::Context as _; use wasmtime::{
use wasmtime::{Config, Engine, Module, Store}; Config, Engine, Store,
component::{Component, Linker},
};
use wasmtime_wasi::{
ResourceTable, WasiCtx, WasiCtxBuilder, WasiView, add_to_linker_sync,
bindings::sync::Command,
};
let engine = Engine::new(&Config::default()).context("create Wasmtime engine")?; struct State {
let module = Module::from_file(&engine, wasm_path).context("load Wasm module")?; ctx: WasiCtx,
table: ResourceTable,
}
let mut linker: wasmtime::Linker<wasmtime_wasi::WasiCtx> = wasmtime::Linker::new(&engine); impl WasiView for State {
wasmtime_wasi::add_to_linker(&mut linker, |cx| cx).context("add WASI to linker")?; fn ctx(&mut self) -> &mut WasiCtx {
&mut self.ctx
}
fn table(&mut self) -> &mut ResourceTable {
&mut self.table
}
}
let wasi = wasmtime_wasi::WasiCtxBuilder::new() let mut config = Config::new();
config.wasm_component_model(true);
let engine = Engine::new(&config).context("create engine")?;
let component = Component::from_file(&engine, wasm_path)
.with_context(|| format!("load component {}", wasm_path.display()))?;
let mut linker: Linker<State> = Linker::new(&engine);
add_to_linker_sync(&mut linker).context("add WASI to linker")?;
let ctx = WasiCtxBuilder::new()
.inherit_stdout() .inherit_stdout()
.inherit_stderr() .inherit_stderr()
.build(); .build();
let mut store = Store::new(&engine, wasi); let mut store = Store::new(
&engine,
State {
ctx,
table: ResourceTable::new(),
},
);
println!("READY"); println!("READY");
let instance = linker let command =
.instantiate(&mut store, &module) Command::instantiate(&mut store, &component, &linker).context("instantiate component")?;
.context("instantiate module")?;
let start = instance
.get_typed_func::<(), ()>(&mut store, "_start")
.context("get _start export")?;
start.call(&mut store, ()).context("call _start")?;
Ok(()) command
.wasi_cli_run()
.call_run(&mut store)
.context("call run")?
.map_err(|()| anyhow::anyhow!("wasm component run exited with error"))
} }
fn package_store_roots() -> Vec<PathBuf> { fn package_store_roots() -> Vec<PathBuf> {