{"id":29419898,"url":"https://github.com/bytecodealliance/componentizejs","last_synced_at":"2025-07-12T01:13:23.641Z","repository":{"id":66007581,"uuid":"602301938","full_name":"bytecodealliance/ComponentizeJS","owner":"bytecodealliance","description":"JS -\u003e WebAssembly Component","archived":false,"fork":false,"pushed_at":"2025-07-03T16:34:07.000Z","size":31137,"stargazers_count":304,"open_issues_count":33,"forks_count":37,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-07-03T17:41:32.325Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bytecodealliance.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-02-15T23:16:30.000Z","updated_at":"2025-07-03T16:34:11.000Z","dependencies_parsed_at":"2023-12-01T21:59:48.439Z","dependency_job_id":"2f177b91-0998-440a-b83a-89f37b085426","html_url":"https://github.com/bytecodealliance/ComponentizeJS","commit_stats":null,"previous_names":["bytecodealliance/componentizejs","bytecodealliance/componentize-js"],"tags_count":45,"template":false,"template_full_name":null,"purl":"pkg:github/bytecodealliance/ComponentizeJS","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytecodealliance%2FComponentizeJS","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytecodealliance%2FComponentizeJS/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytecodealliance%2FComponentizeJS/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytecodealliance%2FComponentizeJS/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bytecodealliance","download_url":"https://codeload.github.com/bytecodealliance/ComponentizeJS/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytecodealliance%2FComponentizeJS/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264922908,"owners_count":23683705,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-12T01:13:20.837Z","updated_at":"2025-07-12T01:13:23.628Z","avatar_url":"https://github.com/bytecodealliance.png","language":"Rust","readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003e\u003ccode\u003eComponentizeJS\u003c/code\u003e\u003c/h1\u003e\n\n  \u003cp\u003e\n    \u003cstrong\u003eESM -\u003e WebAssembly Component creator,\u003cbr /\u003evia a SpiderMonkey JS engine embedding\u003c/strong\u003e\n  \u003c/p\u003e\n\n  \u003cstrong\u003eA \u003ca href=\"https://bytecodealliance.org/\"\u003eBytecode Alliance\u003c/a\u003e project\u003c/strong\u003e\n\n  \u003cp\u003e\n    \u003ca href=\"https://github.com/bytecodealliance/jco/actions?query=workflow%3ACI\"\u003e\u003cimg src=\"https://github.com/bytecodealliance/jco/workflows/CI/badge.svg\" alt=\"build status\" /\u003e\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n## Overview\n\nProvides a Mozilla SpiderMonkey embedding that takes as input a JavaScript source file and a WebAssembly Component [WIT World](https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md),\nand outputs a [WebAssembly Component](https://github.com/WebAssembly/component-model) binary with the same interface.\n\n\u003e **Note**: This is an experimental project, no guarantees are provided for stability or support and breaking changes may be made in future.\n\n## Example\n\nSee the end-to-end example workflow for [creating a JS component and running it in Wasmtime or Node.js](EXAMPLE.md).\n\n## Explainer\n\nFor background on the concepts involved, see https://bytecodealliance.org/articles/making-javascript-run-fast-on-webassembly.\n\nThe goal of this project specifically is to provide a comprehensive dynamic bindings system for creating arbitrary WebAssembly Components from JavaScript. That is, to provide full flexibility over the resultant JS environment and WIT World.\n\n### Wizer Pre-Initialization\n\nAdaption follows the standard [Wizer technique](https://github.com/bytecodealliance/wizer) in pre-initializing a snapshot of the runtime against the source and bindings.\n\nThe snapshotting process executes the JS engine initialization, globals and parsing and compiling of the source code. Currently we also evaluate the top-level of the source so that the executed exports of the top-level ES module are provided already initialized.\n\nAs a result, at runtime - only the  bytecode is being executed, without any initialization costs. _This makes on-demand Wasm execution of JS incredibly fast._\n\n### SpiderMonkey Embedding\n\nAs a dynamic language with quirks, JavaScript cannot be compiled directly into bytecode without including a comprehensive ECMA-262 spec-compliant runtime engine. Componentization of JavaScript thus involves embedding the JS runtime engine into the component itself.\n\nSpiderMonkey is chosen here as a JS engine with first-class WASI build support, using an embedding of the [StarlingMonkey Wasm engine](https://github.com/fermyon/StarlingMonkey). The total embedding size is around 8MB.\n\nOne of the security benefits of the component model is complete code isolation apart from the shared-nothing code boundaries between components. By fully encapsulating the engine embedding for each individual component, this maintains comprehensive per-component isolation.\n\nAs more components are written in JavaScript, and there exist scenarios where multiple JS components are communicating in the same application, the plan for optimization here is to share the SpiderMonkey engine embedding between them. This can be done without breaking the shared-nothing semantics by having the engine itself loaded as a shared library of the components. Sharing functions via same SpiderMonkey build, not memory.\n\nEstablishing this initial prototype as a singular flexible engine foundation that can be turned into a shared library is therefore the focus for this project.\n\n### Weval AOT Compilation\n\n\n\n## Platform APIs\n\nThe following APIs are available:\n\n* **Legacy Encoding**: `atob`, `btoa`, `decodeURI`, `encodeURI`, `decodeURIComponent`, `encodeURIComponent`\n* **Streams**: `ReadableStream`, `ReadableStreamBYOBReader`, `ReadableStreamBYOBRequest`, `ReadableStreamDefaultReader`, `ReadableStreamDefaultController`, `ReadableByteStreamController`, `WritableStream` `ByteLengthQueuingStrategy` `CountQueuingStrategy`, `TransformStream`\n* **URL**: `URL` `URLSearchParams`\n* **Console**: `console`\n* **Performance**: `Performance`\n* **Task**: `queueMicrotask`, `setInterval` `setTimeout` `clearInterval` `clearTimeout`\n* **Location**: `WorkerLocation`, `location`\n* **Encoding**: `TextEncoder`, `TextDecoder`, `CompressionStream`, `DecompressionStream`\n* **Structured Clone**: `structuredClone`\n* **Fetch**: `fetch` `Request` `Response` `Headers`\n* **Forms, Files, and Blobs**: `FormData`, `MultipartFormData`, `File`, `Blob`\n* **Crypto**: `SubtleCrypto` `Crypto` `crypto` `CryptoKey`\n\n## Usage\n\nInstall and run as a Node.js library:\n\n```shell\nnpm install @bytecodealliance/componentize-js\n```\n\n```js\nimport { componentize } from '@bytecodealliance/componentize-js';\nimport { writeFile } from 'node:fs/promises';\n\nconst { component } = await componentize(`\n  import { log } from 'local:hello/logger';\n\n  export function sayHello (name) {\n    log(\\`Hello \\${name}\\`);\n  }\n\n`, `\n  package local:hello;\n  interface logger {\n    log: func(msg: string);\n  }\n  world hello {\n    import logger;\n    export say-hello: func(name: string);\n  }\n`);\n\nawait writeFile('test.component.wasm', component);\n```\n\nSee [types.d.ts](types.d.ts) for the full interface options.\n\nThe component iself can be executed in any component runtime, see the [example](EXAMPLE.md) for an end to end workflow in Wasmtime.\n\n### AOT Compilation\n\nTo enable AOT compilation, set the `enableAot: true` option to run [Weval][weval] ahead-of-time compilation.\n\nAOT compilation can also be configured with the following options:\n\n| Option                 | Type                                | Example         | Description                                                              |\n|------------------------|-------------------------------------|-----------------|--------------------------------------------------------------------------|\n| `aotMinStackSizeBytes` | `nubmer | Number | bigint | BigInt` | `2_007_846_092` | The minimum stack size (via `RUST_MIN_STACK` to set when running `weval` |\n\n[weval]: https://github.com/bytecodealliance/weval\n\n### Custom `weval` binary for AOT\n\nTo use a custom (pre-downloaded) [`weval`][weval] binary, set the `wevalBin` option to the path to your desired weval binary.\n\n### Custom `wizer` binary when AOT is disabled\n\nTo use a custom (pre-downloaded) [`wizer`](https://github.com/bytecodealliance/wizer) binary, set the `wizerBin` option to the path to your desired wizer binary.\n\n### Async Support\n\nTo support asynchronous operations, all functions may optionally be written as sync or async functions, even though they will always be turned into sync component functions.\n\nFor example, to use `fetch` which requires async calls, we can write the same example component using an async function:\n\n```js\nexport async function sayHello (name) {\n  const text = await (await fetch(`http://localhost:8080/${name}`)).text();\n  console.log(text);\n}\n```\n\nComponentizeJS will automatically resolve promises returned by functions to syncify their return values, running the event loop within the JS component to resolution.\n\nThis asynchrony is only supported for exported functions - imported functions can only be synchronous pending component-model-level async support.\n\n### CLI\n\nComponentizeJS can be used as a CLI directly, or via the `jco componentize` command:\n\n#### Direct use\n```\nnpm install -g @bytecodealliance/componentize-js\n```\n\nExample:\n\n```sh\ncomponentize-js --wit wit -o component.wasm source.js\n```\n\nSee `jco componentize --help` for more details.\n\n#### Use via `jco componentize`\n```\nnpm install -g @bytecodealliance/jco @bytecodealliance/componentize-js\n```\n\nExample:\n\n```sh\njco componentize source.js --wit wit -o component.wasm\n```\n\nSee `jco componentize --help` for more details.\n\n## Features\n\nThe set of enabled features in the engine can be customized depending on the target world and expected capabilities.\n\nThe default set of features includes:\n\n* `'stdio'`: Output to stderr and stdout for errors and console logging, depends on `wasi:cli` and `wasi:io`.\n* `'random'`: Support for cryptographic random, depends on `wasi:random`. **When disabled, random numbers will still be generated but will not be random and instead fully deterministic.**\n* `'clocks'`: Support for clocks and duration polls, depends on `wasi:clocks` and `wasi:io`. **When disabled, using any timer functions like setTimeout or setInterval will panic.**\n* `'http'`: Support for outbound HTTP via the `fetch` global in JS.\n\nSetting `disableFeatures: ['random', 'stdio', 'clocks', 'http']` will disable all features creating a minimal \"pure component\", that does not depend on any WASI APIs at all and just the target world.\n\nNote that pure components **will not report errors and will instead trap**, so that this should only be enabled after very careful testing.\n\nNote that features explicitly imported by the target world cannot be disabled - if you target a component to a world that imports `wasi:clocks`, then `disableFeatures: ['clocks']` will not be supported.\n\n## Using StarlingMonkey's `fetch-event`\n\nThe StarlingMonkey engine provides the ability to use `fetchEvent` to handle calls to `wasi:http/incoming-handler@0.2.0#handle`. When targeting worlds that export `wasi:http/incoming-handler@0.2.0` the fetch event will automatically be attached. Alternatively, to override the fetch event with a custom handler, export an explicit `incomingHandler` or `'wasi:http/incoming-handler@0.2.0'` object. Using the `fetchEvent` requires enabling the `http` feature.\n\n## API\n\n```ts\nexport function componentize(opts: {\n  sourcePath: string,\n  witPath: string,\n  worldName: string,\n  debug?: bool,\n  debugBuild?: bool,\n  engine?: string,\n  preview2Adapter?: string,\n  disableFeatures?: ('stdio' | 'random' | 'clocks' | 'http')[],\n}): {\n  component: Uint8Array,\n  imports: string[]\n}\n```\n\nConverts a JS source into a component binary.\n\nImports provides the list of used guest imports only, while the StarlingMonkey engine may pull in additional\nimports. Direct component analysis should be used to correctly infer the real imports list.\n\n## Contributing\n\n### Pre-requisites\n\n* `git submodule update --init --recursive` to update the submodules.\n* Stable Rust with the `wasm32-unknown-unknown` and `wasm32-wasi` targets\n  installed.\n* `wasi-sdk-20.0` installed at `/opt/wasi-sdk/`\n\n### Building and testing\n\nBuilding and testing the project can be performed via NPM scripts (see [`package.json`](./package.json)):\n\n```console\nnpm install\nnpm run build\nnpm run test\n```\n\nBefore being able to use `componetize-js` (ex. via `npm link`, from `jco`), you'll need to run:\n\n```\nnpm run build:weval\n```\n\nThis will produce a few files, most importantly `lib/starlingmonkey_embedding_weval.wasm`.\n\nTo clean up a local installation (i.e. remove the installation of StarlingMonkey):\n\n```console\nnpm run clean\n```\n\n# License\n\nThis project is licensed under the Apache 2.0 license with the LLVM exception.\nSee [LICENSE](LICENSE) for more details.\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in this project by you, as defined in the Apache-2.0 license,\nshall be licensed as above, without any additional terms or conditions.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytecodealliance%2Fcomponentizejs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbytecodealliance%2Fcomponentizejs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytecodealliance%2Fcomponentizejs/lists"}