js-component-tools
JavaScript tooling for working with WebAssembly Components
A Bytecode Alliance project
Overview
JS Component Tools provides a JS ecosystem tool for working with the emerging WebAssembly Components specification in JavaScript.
Features include:
- "Transpiling" Wasm Component binaries into ES modules that can run in any JS environment.
- Optimization helpers for Components, including Binaryen and asm.js support.
- Component operations from a JS-native build of Wasm Tools.
The Rust transpiler and Wasm Tools crates are both compiled from Rust into JS using Wasm Component tools itself.
This tool is designed primarily for working with already-created Components, and not for creating Components. For creating Components, see the Cargo Component and Wit Bindgen projects.
Note: This is an experimental project, no guarantees are provided for stability or support and breaking changes may be made in future.
Installation
This is a fully-native JS & Wasm library which can be installed from npm directly.
npm install js-component-tools
JS Component Tools can be used as either a library (e.g. import { transpile } from 'js-component-tools') or as a CLI via the jsct CLI command.
Example
Given an existing Wasm Component, jsct provides the tooling necessary to work with this Component fully natively in JS.
For an example, consider a Component cowsay.wasm:
- cowsay.wasm
Where we would like to use and run this Component in a JS environment.
Inspecting Component WIT
As a first step, we might like to look instead this binary black box of a Component and see what it actually does.
To do this, we can use jsct wit to extract the "WIT world" of the Component (WIT is the typing language used for defining Components).
> jsct wit cowsay.wasm
world component {
default export interface {
enum cows {
default,
cheese,
daemon,
dragon-and-cow,
dragon,
elephant-in-snake,
elephant,
eyes,
flaming-sheep,
...
}
cow-say: func(text: string, cow: option<cows>) -> string
}
}
From the above we can see that this Component exports an interface with a single function export, say, which takes
as input a string, an optional cow, and returns a string.
Alternatively jsct print cowsay.wasm -o out.wat would output the full concrete Wasm WAT to inspect the Component,
with all the implementation details (don't forget the -o flag...).
Transpiling to JS
To execute the Component in a JS environment, use the jsct transpile command to generate the JS for the Component:
> jsct transpile cowsay.wasm --minify -o wunderbar
Transpiled JS Component Files:
- cowsay/cowsay.core.wasm 2.01 MiB
- cowsay/cowsay.d.ts 0.73 KiB
- cowsay/cowsay.js 6.01 KiB
Now the Component can be directly imported and used as an ES module:
test.mjs
import { cowSay } from './cowsawy/cowsawy.js';
console.log(cowSay('Hello Wasm Components!'));
The above JavaScript can be executed in Node.js:
> node test.mjs
________________________
< Hello Wasm Components! >
------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Or it can be executed in a browser via a module script:
<script type="module" src="test.mjs"></script>
There are a number of custom transpilation options available, detailed in the API section below.
JSCT API
Note if using a synchronous API function, the $init method should be imported and awaited first:
import { $init } from 'js-component-tools';
await $init;
This is because the JSCT API is built with top-level await compatibility (via jsct transpile --tla-compat).
The below is an outline of the available API functions, see api.d.ts file for the exact options.
transpile(component: Uint8Array, opts?): Promise<{ files: Record<string, Uint8Array> }>
Transpile a Component to JS.
Transpilation options:
name?: string- name for the generated JS file.instantiation?: bool- instead of a direct ES module, output the raw instantiation function for custom virtualization.map?: Record<string, string>- remap component importsvalidLiftingOptimization?: bool- optimization to reduce code sizecompat?: bool- enables all compat optionsnoNodejsCompat?: bool- disables Node.js compatible outputtlaCompat?: bool- enable compat in JS runtimes without TLA supportbase64Cutoff?: number- size in bytes, under which Wasm modules get inlined as base64.asm?: bool- use asm.js instead of core WebAssembly for execution.minify?: bool- minify the output JS.optimize?: bool- optimize the component with Binaryen wasm-opt first.optArgs?: string[]- if using optimize, custom optimization options (defaults to best optimization, but this is very slow)
opt(component: Uint8Array, opts?): Promise<{ component: Uint8Array }>
Optimize a Component with the Binaryen Wasm-opt project.
parse(wat: string): Uint8Array
Parse a compoment WAT to output a Component binary.
print(component: Uint8Array): string
Print the WAT for a Component binary.
componentNew(coreWasm: Uint8Array | null, opts?): Uint8Array
"WIT Component" Component creation tool.
componentWit(component: Uint8Array): string
Extract the WIT world from a component binary.
JSCT CLI
The CLI is available via the jsct command, providing all the same
functions and options as the API.
License
This project is licensed under the Apache 2.0 license with the LLVM exception. See LICENSE for more details.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions.