Migrate native addon from nan to node-addon-api (N-API)#152
Conversation
Replace nan with node-addon-api in both native source files and the build configuration. N-API provides ABI stability across Node.js major versions, so a binary compiled once continues to load on Node.js 20, 22, and 24 without recompilation. Changes: - binding.gyp: switch include path to node-addon-api, add NAPI_DISABLE_CPP_EXCEPTIONS define - native/can.cc: rewrite RawChannel to use Napi::ObjectWrap<T>, instance methods, Napi::FunctionReference/ObjectReference for persistent listener handles, and napi_env stored for uv_async callbacks - native/signals.cc: rewrite DecodeSignal/EncodeSignal as plain Napi::Value functions - package.json: replace nan dependency with node-addon-api ^8.0.0 - Dockerfile.build-test: new file for verifying compilation on Linux Verified: compiles cleanly on Node.js 22 / Linux arm64 (Debian bookworm) with no warnings. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Run test-parsing and test-signal_conversion (the tests that exercise the migrated can_signals native module) inside the container. The two vcan- dependent test suites (test-raw_basic, test-signal_generation) require a real Linux kernel with the vcan module and cannot run in Docker Desktop. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Regenerate lock file after replacing nan with node-addon-api. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
uv_async callbacks run on the Node.js main thread but are not entered via NAPI, so no HandleScope is open when they fire. Accessing any Napi::Reference value (FunctionReference::Value()) without one causes a fatal: "Cannot create a handle without a HandleScope". Add Napi::HandleScope scope(env) at the top of async_channel_stopped() and async_receiver_ready(), matching the Nan::HandleScope that the previous NAN implementation had in the same two functions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Now that the native addon uses N-API, the same binary should load unchanged across all LTS releases. Adding 24.x to the matrix verifies this on every PR. Dockerfile.build-test reverted to build-only — its purpose is to quickly verify compilation on Linux without a CAN interface. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Thank you for implementing this so quickly — that's much appreciated! Tested on Node.js 22.22.3 / Linux x64. The native addon builds and loads correctly — ABI stability works as expected. However, Additionally, As a result, |
Summary
nanwithnode-addon-apiin both native source files (can.cc,signals.cc) and the build configuration (binding.gyp)node-addon-apiwraps the stable N-API layer, guaranteeing ABI compatibility across Node.js major versions — a binary compiled once for Node.js 20 continues to load on Node.js 22 and 24 without recompilationDockerfile.build-testfor reproducing the Linux build locallyMotivation
Users who upgrade Node.js (e.g. from v20 to v22) currently find the native addon silently broken until they manually rebuild. This is a common pain point for ioBroker adapters and other downstream consumers. N-API eliminates the need to recompile on major version upgrades and makes prebuilt binaries (e.g. via
prebuildify) feasible in the future.What changed
package.jsonnan→node-addon-api ^8.0.0binding.gypNAPI_DISABLE_CPP_EXCEPTIONSnative/can.ccNan::ObjectWrap→Napi::ObjectWrap<T>; static methods → instance methods;Nan::Persistent→Napi::FunctionReference/ObjectReference;napi_envstored foruv_asynccallbacksnative/signals.ccNAN_METHOD→Napi::Valuefree functions; allNan::*replaced withNapi::*Dockerfile.build-testnode:22-bookworm-slimfor verificationTest plan
npm testpasses on a machine with a real or virtual CAN interface (vcan0)🤖 Generated with Claude Code