@napi-rs/wasm-runtime
Runtime helpers and browser polyfills for napi-rs WebAssembly addons.
emnapi compatibility
Use matching versions of @emnapi/core and @emnapi/runtime:
- v1:
^1.7.1. Core includes async work and threadsafe functions and ignores the plugins option. Loading this package does not resolve the v2-only@emnapi/core/pluginsexport. - v2: the peer range is exactly
2.0.0-beta.2or2.0.0-beta.3, and this package bundles the async-work and TSFN plugins from2.0.0-beta.3. They depend on private core context fields, which are the same in both betas (2.0.0-beta.3changed only the TSFN release order).2.0.0-beta.1renamed the context fieldnapiModuletoaddonModule; the bundled plugins accept both names, so bindings that pin a 2.0.0 alpha keep loading. A later prerelease that changes the context again needs a new release of this package.
The v2 peer range stays narrow on purpose. With an open range, npm can hoist a binding's 2.0.0 alpha core next to this package, and then v1 bindings that load through the ESM entry, or through tools that skip the CommonJS copy lookup below, get a v2 core. With the narrow range, npm installs a v1 core for this package when a binding pins another v2 prerelease. The binding's own emnapi copy still runs it, as described below.
The CommonJS entry keeps emnapi copies apart when this package's peers resolve
to a different copy than a binding's own @emnapi/core and @emnapi/runtime
(two bindings pinning different emnapi versions, say):
instantiateNapiModule(Sync)runs the core of the copy whose runtime createdoptions.context. It finds that runtime inrequire.cacheand resolves the core from the module that required it (the binding's loader).getDefaultContext,createContext,MessageHandler, and instantiation without a context use the copy of the calling package when it declares both emnapi packages as dependencies: the CommonJS module that is still loading and required this package, or, in a worker thread, the worker's entry file.- When the selected core is v2, the bundled plugins are replaced by that core's
own
@emnapi/core/plugins. - Anything else uses this package's peers. A context of the other emnapi
generation from no known copy throws a
TypeErrorthat says so.
The ESM entry is resolved by bundlers and cannot do this. It uses the bundled
plugins with the addonModule alias.
For raw instantiateNapiModule / instantiateNapiModuleSync calls loading a
single-threaded napi-rs addon, pass
plugins: [emnapiAsyncWorkPlugin, emnapiTSFNPlugin] from this package. Generated
napi-rs loaders already supply these plugins.
Updating the bundled plugins
Update the exact v2 development dependencies together with the workspace
resolutions. build checks that the resolved core version is the exact
development version and one of the v2 versions in the peer range, and
prepack rebuilds the bundles so a package cannot silently reuse output from
an earlier build. Before a release, compare the new plugin context with the
oldest supported alpha (2.0.0-alpha.3 is the oldest still pinned by published
bindings), and keep the CI matrix covering it. Keep earlier v2 versions in the
peer range while published bindings pin them (rolldown 1.2.16 pins
2.0.0-beta.2); removing one makes npm install a v1 core for this package
next to those bindings.
yarn workspace @napi-rs/wasm-runtime test exercises actual WebAssembly
initialization, async work, TSFN calls from a worker, worker load failures, and
cleanup through both module formats. CI also installs the packed tarball with
real v1 and v2 peers outside the workspace to avoid root resolution overrides.