contributor-context
Contributor context for coding agents working in this repository. Human contributors should start with `README.md` and…
<!-- GENERATED from docs/playbooks/integration/nodejs.md by scripts/build-agent-skill.mjs. Do not edit. -->
$ npx -y skills add crossbind/crossbind --agent claude-codeHow it fires
How this agent gets triggered: by you, by Claude, or both.
Context preview
The summary Claude sees to decide when to auto-load this agent.
<!-- GENERATED from docs/playbooks/integration/nodejs.md by scripts/build-agent-skill.mjs. Do not edit. -->
<!-- GENERATED from docs/playbooks/integration/nodejs.md by scripts/build-agent-skill.mjs. Do not edit. -->
> Persona 2 sub-playbook. The user's project is a plain Node.js application or library — no Vite, Webpack, Rollup, RN, etc. Detection: crossbind build script targets `-e node`, or the project's `package.json` declares `main`/`module`/`bin` without bundler deps.
Build crossbind artifacts for the Node runtime (`-e node`) and `require`/`import` the loader from any Node script. No bundler integration; the build is invoked directly via `crossbind build`.
| File | Role | |------|------| | `package.json` | + `crossbind`, optional `@crossbind/port-<name>`; declare a `build` script that runs `crossbind build -e node` | | `crossbind.config.{js,mjs}` *(new at root)* | Project-level crossbind config (deps to consume, paths) | | `src/native/` *(if user wraps own C++)* | `.h` + `.cpp` source | | `<entry>.js` (e.g. `index.js`) | `require`/`import` the built loader | | `dist/<name>-<target>.node.{js,wasm}` | Build output |
pnpm add -D crossbind@beta pnpm add @crossbind/port-<name>@beta # optional # Single-thread build pnpm crossbind build -p wasm -a wasm32 -r st -e node -b release # Multithread build (Node worker_threads) pnpm crossbind build -p wasm -a wasm32 -r mt -e node -b release # Run node index.js
Mirror `examples/backend-nodejs-wasm/` (single-thread) or `e2e/backend-nodejs-multithread/` (multithread).
`package.json`:
{
"scripts": {
"build": "crossbind build -p wasm -a wasm32 -r st -e node -b release",
"start": "node src/index.js"
},
"dependencies": {
"@crossbind/port-<name>": "^x.y.z"
},
"devDependencies": {
"crossbind": "^2.0.0"
}
}`crossbind.config.mjs`:
// If consuming prebuilt packages:
import Matrix from '@crossbind/example-lib-prebuilt-matrix/crossbind.config.js';
export default {
general: { name: 'my-node-service' },
dependencies: [
Matrix,
],
paths: {
config: import.meta.url,
output: 'dist',
},
};Entry script `src/index.js` (CommonJS):
const initNative = require('../dist/my-node-service-wasm-wasm32-st-release.node.js');
initNative().then(({ Native }) => {
console.log(`Result: ${Native.sample()}`);
});ESM equivalent:
import initNative from './dist/my-node-service-wasm-wasm32-st-release.node.js';
const { Native } = await initNative();
console.log(`Result: ${Native.sample()}`);The exact output filename is `<general.name>-<target.path>.<runtimeEnv>.{js,wasm}`. For st-release: `<name>-wasm-wasm32-st-release.node.js`. For mt-release: `<name>-wasm-wasm32-mt-release.node.js`.
The st-release build also writes `dist/node/wasm.mjs` and its `.d.mts`: one ES module that exports every bound class, function and constant, filled when `initNative()` resolves, so init options still reach the runtime:
import { initNative, Native } from './dist/node/wasm.mjs';
await initNative();
console.log(`Result: ${Native.sample()}`);A library publishes that module under a path of its own, as `@crossbind/example-lib-prebuilt-matrix/node/wasm` does. The loader is CommonJS with a `.js` extension, so the build writes `dist/package.json` with `"type": "commonjs"` when the output directory has none; it keeps loading as CommonJS inside a `"type": "module"` package.
A Node.js app can import its native code the way a bundler app does: its own header, a package's header, a `conan:` header, a `.rs` file or a `cargo:` crate.
import { initNative, Native, NATIVE_ANSWER } from './native/native.h';
import { Matrix } from '@crossbind/example-lib-prebuilt-matrix/Matrix.h';
import { zlibVersion } from 'conan:zlib/zlib.h';
import { Counter } from './native/counter.rs';
import { Version } from 'cargo:semver';
await initNative();While developing, start the app through `crossbind/node/dev`, and it builds when it needs to:
node --import crossbind/node/dev src/index.mjs node --watch --watch-path=src/native --import crossbind/node/dev src/index.mjs # build and restart on save
`crossbind build -e node` itself finds these imports in the app's sources and binds them, constants and a dependency's functions only by the names imported, as a bundler does ([binding rule 9](../../api/cpp-binding-rules.md)). It writes the hooks that serve them, `dist/node/<format>.register.mjs` beside the entry, where `<format>` is `wasm` for the st-release wasm build and `napi` for an addon build. A deployed app starts with those, since `crossbind` is a dev dependency it may not have; they need nothing but `dist` and never build:
node --import ./dist/node/napi.register.mjs src/index.mjs
`NODE_OPTIONS="--import=./dist/node/napi.register.mjs"` does
Import C++ and Rust like JavaScript modules (WebAssembly & React Native)
Contributor context for coding agents working in this repository. Human contributors should start with `README.md` and…
<!-- GENERATED from docs/api/app.md by scripts/build-agent-skill.mjs. Do not edit. -->
<!-- GENERATED from docs/api/build-state.md by scripts/build-agent-skill.mjs. Do not edit. -->
<!-- GENERATED from docs/api/conan.md by scripts/build-agent-skill.mjs. Do not edit. -->
<!-- GENERATED from docs/api/cpp-binding-rules.md by scripts/build-agent-skill.mjs. Do not edit. -->