npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bytecodealliance/rolldown-plugin-jco

v0.1.0

Published

Rolldown and Rollup plugin for using the Jco WebAssembly component toolkit

Readme

@bytecodealliance/rolldown-plugin-jco

Easily import functionality provided by WebAssembly Components from JS/TS projects that bundle with Rolldown/Rollup, inspired by unwasm.

This plugin transpiles each component with Jco (i.e. jco transpile) to an ES module, then adds the generated bindings to the module graph, emitting core WebAssembly modules as bundler-managed assets, along with functions you can use directly.

WebAssembly components are WebAssembly binaries that conform to the Component Model, which enables cross-language robust types, interface/contract driven development, async behavior, and much more.

WebAssembly components are distinct from WebAssembly modules generated by emscripten or wasm-bindgen. You can read more about WebAssembly components in the WebAssembly Component Book, maintained by the Bytecode Alliance.

Install

After installing your bundler of choice (rolldown/rollup), you can install the plugin via NPM

pnpm add -D @bytecodealliance/rolldown-plugin-jco

Rolldown

To use the plugin from rolldown:

// rolldown.config.mjs
import { defineConfig } from "rolldown";
import jco from "@bytecodealliance/rolldown-plugin-jco";

export default defineConfig({
    input: "src/main.js",
    platform: "node",
    plugins: [jco()],
});

For Node.js WASI components, the plugin also emits self-contained worker artifacts owned by the Preview 2 and Preview 3 shims. No shim-internal worker entry or copy step is required in application configuration.

Rollup

The plugin uses the Rollup-compatible plugin API, so the same configuration works in Rollup:

// rollup.config.mjs
import jco from "@bytecodealliance/rolldown-plugin-jco";

export default {
    input: "src/main.js",
    plugins: [jco()],
};

Importing and using WebAssembly Components

Given a WebAssembly Component calculator.wasm with the following WIT:

package jco:examples;

interface calculator {
    /// Errors that may occur during the course of using `add()`
    variant add-error {
        overflow,
        underflow,
        other(string),
    }

    /// Addition of two signed integers
    add: func(a: s32, b: s32) -> result<s32, add-error>;
}

world component {
    export calculator;
}

The default export is a way to instantiate the component, providing it all the imports it needs.

import instantiate from "./calculator.wasm";

const component = instantiate();
console.log(component.calculator.add(1, 2));

For components without any imports (the calculator.wasm example case), you can use the relevant interface from the component right away, because component model exports are available as named imports:

import instantiate, { add } from "./adder.wasm";

console.log(add.add(1, 2));
// assert(instantiate().add === add);

To group all imports, under one name, you can use a namespace import:

import * as component from "./adder.wasm";

console.log(component.add.add(1, 2));
// assert(component.default().add === component.add);

Dynamic imports are also supported:

const component = await import("./adder.wasm");
// assert(component.default().add === component.add);
console.log(component.add.add(1, 2));

?component is accepted as an explicit marker when it is useful to distinguish component imports:

import component from "./calculator.wasm?component";

Other Wasm query conventions such as ?url and ?module are left to other plugins (e.g. unwasm).

Typescript types

TypeScript projects can opt into a generic default-import declaration:

{
    "compilerOptions": {
        "types": ["@bytecodealliance/rolldown-plugin-jco/wasm"]
    }
}

[!WARN] Precise component TypeScript declarations are not yet supported, but will be in a future version

Custom instantiation

Components with imports can use Jco's custom instantiation API. Enable async or sync instantiation in the plugin configuration:

jco({
    transpile: {
        instantiation: "async",
    },
});

The default function's first argument loads a bundler-emitted core Wasm asset, the second supplies the component-model imports, and the optional third argument overrides core Wasm instantiation:

import instantiate, { run } from "./hosted.wasm";

const instance = await instantiate(async (url) => WebAssembly.compile(await (await fetch(url)).arrayBuffer()), {
    "example:host/api": {
        getValue() {
            return 42;
        },
    },
});

console.log(instance.run === run); // true
console.log(run());

In custom mode, named component exports are live ESM bindings. They are undefined until instantiation succeeds and update automatically afterwards.

Avoid destructuring a namespace object before instantiation, because ordinary object destructuring captures the initial value rather than the live binding.

The default function also returns the complete component instance for convenient local destructuring:

const { run: localRun } = await instantiate(loadCoreModule, imports);

A failed instantiation leaves every named binding unset and can be retried.

After a successful instantiation, another call throws because one imported module cannot represent multiple component instances.

Because lifecycle instantiation is the default export, a component-model export named instantiate does not collide with it:

import instantiateComponent, { instantiate } from "./component.wasm";

await instantiateComponent(loadCoreModule, imports);
instantiate(); // the component-model export

In eager mode (when transpile.instantiation is not set), components are instantiated as the module loads, named exports are immediately available, and calling the default function simply returns the component namespace.

Options

Here are the options that are accepted by this plugin:

jco({
    include: ["src/**/*.wasm"],
    exclude: ["src/core-wasm/**"],
    transpile: {
        minify: true,
        map: {
            "example:host/*": "./src/host.js#*",
        },
    },
    name(id) {
        return "my-component";
    },
});

FAQ

Some things to keep in mind, when using this plugin:

  • include and exclude use the standard Rollup plugin filter syntax.
  • transpile is forwarded to Jco. The plugin owns name and outDir because generated files are managed inside the bundler graph.
  • transpile.instantiation selects Jco's "async" or "sync" custom-instantiation mode.
  • name optionally controls the name passed to Jco. By default the plugin combines the input basename with a stable path hash to avoid collisions.
  • Input files must be local WebAssembly Component files available at build time.
  • Plain "core" Wasm modules are not valid inputs; exclude them or route them to a plugin that prioritizes core wasm such as unwasm.
  • Components are deduplicated and may be inlined
  • Only ESM module output is supported

Jco's normal WebAssembly System Interface ("WASI") mappings apply. Components that use WASI therefore retain the corresponding Preview 2 or Preview 3 shim imports in the generated module, and those runtime packages must be resolvable by the consuming build.