QuickJS backend
jco componentize --backend quickjs builds components with
componentize-qjs, which embeds
the QuickJS-NG JavaScript engine.
The alias --backend qjs selects the same backend. Your WIT world defines the
component’s imports and exports, including custom interfaces.
Installation and version ownership
componentize-qjs is a regular Jco dependency. Installing Jco includes the backend
and its packaged runtime; you do not need a separate QuickJS CLI installation.
The package selects a native compiler binding for the build machine. See
componentize-qjs for supported
platforms. Commit your package manager’s lockfile to pin the backend alongside Jco.
Start a project with Jco and the Preview 2 shim used by the transpiled component:
mkdir quickjs-app
cd quickjs-app
npm init -y
npm pkg set type=module
npm install --save-dev @bytecodealliance/jco
npm install @bytecodealliance/preview2-shim
Generate declarations, compile, and run on Node.js
Save hello.wit:
package example:hello;
world hello {
export greet: func(name: string) -> string;
}
Implement the export in hello.ts:
export function greet(name: string): string {
return `Hello, ${name}!`;
}
Generate declarations and build with the synchronous QuickJS runtime for this synchronous world:
npx jco guest-types hello.wit --world-name hello -o types
npx jco componentize hello.ts --backend quickjs --backend-qjs-disable-async --wit hello.wit --world-name hello -o hello.wasm
npx jco transpile hello.wasm -o transpiled
guest-types generates declarations for authoring against the WIT world; the
backend generates its runtime bindings during componentization. TypeScript
entries are bundled and have their type syntax erased automatically, without
semantic type checking. Run your project’s type checker separately when needed.
Save run.mjs:
import { greet } from './transpiled/hello.js';
console.log(greet('components'));
Run node run.mjs; it prints Hello, components! without experimental Node
flags. Transpiling describes how WASI imports are mapped to the
Preview 2 shim and how to supply custom host imports.
Synchronous and async runtimes
QuickJS embeds an async-capable Component Model runtime by default, even when
your WIT exports are synchronous. That output requires a host with the necessary
async support. Pass --backend-qjs-disable-async to select the packaged
non-async runtime for synchronous components, as in the Node.js example above.
This is a componentization choice, separate from jco transpile --async-mode.
It does not convert async WIT functions to synchronous functions. Keep the
default runtime when your world uses Component Model async features and select
a host and transpilation configuration that support them. See the upstream
async examples.
WASI imports and stubs
The embedded runtime can add WASI imports beyond those written explicitly in
your world. Inspect the finished component with jco wit hello.wasm to see its
complete requirements.
For code that does not use WASI, --backend-qjs-stub-wasi replaces WASI imports
with trapping stubs. For example, the greeting can be built with:
npx jco componentize hello.ts --backend qjs --backend-qjs-disable-async --backend-qjs-stub-wasi --wit hello.wit -o pure.wasm
Calling a replaced WASI function traps. This option does not emulate filesystem, console, clock, or other host services; use the normal runtime and supply its imports when the application needs them. It does not remove custom non-WASI imports from your world.
StarlingMonkey’s --disable and --enable feature switches, --engine, AOT,
and engine-debug options are not supported by this backend. Use QuickJS’s
backend-specific switches and jco componentize --help for the Jco CLI surface;
the standalone componentize-qjs CLI has a different set of options.
Modules and Node.js compatibility
For JavaScript entries, pass --bundle to bundle local modules and npm packages
with Jco. TypeScript entries already take this path:
npx jco componentize app.js --backend qjs --bundle --wit wit -o app.wasm
Bundling also supplies Jco’s experimental
Node.js compatibility adapters for supported
node: imports. These can introduce additional component imports, and their
runtime requirements still apply; selecting QuickJS does not embed Node.js.
QuickJS’s host timer adapters require the async runtime and are omitted when
--backend-qjs-disable-async is set.
Both backend initialization and module evaluation happen while preparing the component snapshot. Put work that must happen at runtime in exported functions. See Bundling for module resolution and Rolldown configuration, or scaffold a project to generate an implementation skeleton from WIT.