Skip to content

RFC on WASI preview 2 for plugins proposal #962

@jeffcharles

Description

@jeffcharles

This proposal is for Javy to adopt WASI preview 2 and the component model as a build target for its plugins but have the plugin initialization process output a core Wasm module. The Javy CLI will also continue to emit core Wasm modules.

What problems does it solve?

WASI preview 1 is slated for deprecation in mid-2026. We want to make sure Javy's plugin architecture is not depending on build targets that will be discontinued. We think WASI preview 2 is currently the best candidate target. wasm32-unknown-unknown is not feasible due to rquickjs requiring a libc for compilation. When future versions of WASI build targets are released, we believe it should be straightforward for plugins to use those build targets with minimal changes.

What changes will be required?

What would be involved with updating a Javy plugin?

  1. Add the following WIT file in a wit directory adjacent to your Cargo.toml:
package examplenamespace:my-plugin@1.0.0;

world my-javy-plugin {
    export compile-src: func(src: list<u8>) -> list<u8>;
    export initialize-runtime: func();
    export invoke: func(bytecode: list<u8>, function: option<string>);
}
  1. Add wit-bindgen as a dependency to your plugin.
  2. Update your plugin file to look like the following:
use javy_plugin_api::{
    javy::Runtime,
    javy_plugin, Config,
};

wit_bindgen::generate!({ world: "my-javy-plugin", generate_all });

fn config() -> Config {
    // Set your config as before.
    Config::default()
}

fn modify_runtime(runtime: Runtime) -> Runtime {
    // Modify your runtime as before.
    runtime
}

// This will provide implementations for all required exports.
struct Component;

// This will provide default implementations for all required exports on `Component` with `config` and `modify_runtime` being called.
javy_plugin!("my-import-namespace", Component, config, modify_runtime);

// Actually exports the functions.
export!(Component);
  1. Compile the plugin to wasm32-wasip2 instead of wasm32-wasip1.
  2. Initialize the plugin with javy init-plugin ....

Will the Javy CLI support plugins that are components or emit components?

No, these are out-of-scope for this change. If you want to use JavaScript Wasm Components, you should consider using ComponentizeJS.

Plugin API changes

The Javy CLI will be updated to consume plugin APIs that are defined using component exports. The component model requires export names to use kebab-casing as opposed to underscore separators with the exception of the memory reallocation function. This means the names and signatures of the functions expected to be exported by plugins by the Javy CLI will change in the following ways:

Old signature New signature (component) New signature (module)
compile_src: func(bytecode_ptr: u32, bytecode_len: u32) -> () compile-src: func(bytecode: list<u8>) -> list<u8> compile-src: func(u32, u32) -> u32
initialize_runtime: func() -> () initialize-runtime: func() -> () initialize-runtime: func() -> ()
invoke: func(bytecode_ptr: u32, bytecode_len: u32, fn_name_ptr: u32, fn_name_len: u32) -> () invoke: func(bytecode: list<u8>, function: option<string>) -> () invoke: func(u32, u32, u32, u32, u32) -> ()
canonical_abi_realloc(old_ptr: u32, old_size: u32, alignment: u32, new_size: u32) -> u32 cabi_realloc(old_ptr: u32, old_size: u32, alignment: u32, new_size: u32) -> u32 cabi_realloc(old_ptr: u32, old_size: u32, alignment: u32, new_size: u32) -> u32

Plugins using the existing plugin API will not work with new versions of the Javy CLI. Those plugins will need to be updated to use the new plugin API to work with new versions of the Javy CLI.

Additionally, dynamically linked modules compiled with an old plugin cannot be linked with a new plugin due to the changes to the invoke signature. However, dynamically linked modules compiled with an old plugin can continue to be linked with that older plugin.

What will the code changes look like?

This draft PR demonstrates what I have in mind for the changes. Look at the test plugin to get an idea of the scope of the changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions