napi 0.1.0 copy "napi: ^0.1.0" to clipboard
napi: ^0.1.0 copied to clipboard

Export Dart functions as native WebAssembly ES modules with JavaScript interop and TypeScript declarations.

napi #

Write Dart functions. Import them directly from WebAssembly in JavaScript and TypeScript.

import { add } from './dist/module.wasm';

add(20, 22); // 42

The imported functions are real Wasm exports. No initialization call or JavaScript entrypoint is required.

Quick start #

Use Dart 3.13.5 or newer and Node 22.19+ in the 22.x line, or 24.5+:

dart pub add napi

Write lib/math.dart:

import 'dart:typed_data';
import 'package:napi/napi.dart';

@napi
double add(double a, double b) => a + b;

@napi
String greet(String name) => 'Hello, $name';

@napi
int checksum(Uint8List bytes) {
  var sum = 0;
  for (final byte in bytes) {
    sum = (sum + byte) & 0xff;
  }
  return sum;
}

Build:

dart run napi:build lib/math.dart --name @example/math --out dist --version 0.1.0

Then import the generated Wasm file from an ES module:

import { add, greet, checksum } from './dist/module.wasm';

console.log(add(20, 22));                     // 42
console.log(greet('Dart'));                  // Hello, Dart
console.log(checksum(new Uint8Array([1, 2]))); // 3

Or install the generated directory as an npm package:

npm install /absolute/path/to/dist
import { add } from '@example/math';
// Also supported: import { add } from '@example/math/module.wasm';

add(20, 22);

Both package entries point to module.wasm. The generated package has no npm runtime dependencies. Keep module.imports.mjs beside the Wasm file: the Wasm module imports these compiler and value-conversion helpers automatically.

TypeScript #

Package imports resolve index.d.ts through exports.types with either NodeNext or Bundler module resolution.

For a relative import such as ./dist/module.wasm, napi also generates module.d.wasm.ts. Enable TypeScript's allowArbitraryExtensions:

{
  "compilerOptions": {
    "strict": true,
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "allowArbitraryExtensions": true
  }
}

The declarations contain the actual exported signatures; no wildcard .wasm declaration is needed.

Supported exports #

Annotate public, synchronous, top-level functions in the entry library. Use explicit return types and required positional parameters. Extra arguments are ignored, as with ordinary native Wasm functions; missing arguments arrive as undefined and fail type checks.

Dart JavaScript / TypeScript Boundary behavior
void void Return type only; returns undefined
bool boolean No coercion
int number Input and output must be safe integers
double number Preserves NaN, Infinity, and negative zero
String string Preserves UTF-16 code units
Uint8List Uint8Array Copies in and out; Node Buffer and cross-realm arrays accepted
T? T | null Accepts null; rejects undefined

Invalid arguments throw TypeError; unsafe integers throw RangeError. Dart ArgumentError and TypeError become JavaScript TypeError, Dart RangeError becomes JavaScript RangeError, and other Dart exceptions become JavaScript Error with a readable message.

The export name then is reserved because dynamic ESM imports treat it as a promise callback. Dart compiler helper names such as $invokeMain and $wasmI16ArrayGet are also reserved; other $ names are allowed. Classes, generics, type aliases in exported signatures, optional/named parameters, futures, streams, and callbacks are not supported in 0.1.0. Ordinary Dart helpers and Wasm-compatible dependencies can be used inside exported functions.

Status and platforms #

0.1.0 is experimental and targets Node's native Wasm ESM integration. Node documents instance-phase Wasm imports as experimental. Synchronous CommonJS require is not supported.

The backend uses Dart's experimental Wasm interop and compiler-generated JavaScript helpers. It rewrites the Wasm import section so Node resolves the helpers, string constants, and built-in string operations through ESM; business logic remains Dart Wasm. It does not implement the Node-API C ABI or produce .node addons.

Tested compiler: Dart 3.13.5. Other SDK versions allowed by the package constraint may change the experimental helper layout; unsupported layouts fail the build with a diagnostic. The generated Node engine requirement is ^22.19.0 || >=24.5.0.

Native browser instance imports and bundler compatibility are not supported in this release. A browser's support for WasmGC or source-phase imports alone does not establish support for import { add } from './module.wasm'. The roadmap tracks platform validation.

The build checks signatures before compiling, supports Dart workspaces, and refuses to overwrite unrelated output directories. Rebuilds stage a complete replacement on the destination filesystem and restore the old package if installation fails. Run dart pub get in the source package or workspace first. Use dart run napi:build --help for options.

Development #

dart pub get
dart format bin lib test example
dart analyze --fatal-infos
dart test
dart pub publish --dry-run

Integration tests build a real package and verify native functions through package, subpath, and relative Wasm imports. Set NAPI_TSC to TypeScript's bin/tsc to include the TypeScript consumer checks; CI supplies it. test/js/browser.html probes native browser loading without a fallback loader.

See the requirements and 0.1.0 milestone.

MIT licensed. Generated host helpers include the Dart SDK's BSD license notice.

2
likes
0
points
691
downloads

Publisher

unverified uploader

Weekly Downloads

Export Dart functions as native WebAssembly ES modules with JavaScript interop and TypeScript declarations.

Repository (GitHub)
View/report issues

Topics

#wasm #node #interop

License

unknown (license)

Dependencies

analyzer, path, yaml

More

Packages that depend on napi