Hi, my name is Kane, and today I want to share a project that I've been building in the Node.js organization, a conformance test suite for Node API. But first, a few words about me. My name is Kane, as I said, and I am a developer experience engineer at 11labs. I built developer experiences for people building on top of the voice agents and the other services that we have. And before that, I maintained the Atlas Devices SDK, formerly known as Realm.js at MongoDB. I'm a proud father of three, based in Roskill, just west of Copenhagen. I also like to build in public, and I do a lot of open source. Callstack sponsors me for this in particular, and I have GitHub sponsorships open if you want to join them. You can find me on BlueSky as well.
And let's start with something that you might be familiar with. You've written a native Node.js add-on, perhaps. It works perfectly fine in Node.js, and your CI is green, and you ship it. But does it work on Deno? Does it work on React Native, which recently also supported Node API via Hermes? The honest answer is you probably don't know, and that is the problem that I set out to fix.
Let me back up and explain how we got here. Let me start with getting on the same page of Node, what Node API is, and starting with what it is not, because it's often confused. It is not the Node.js runtime APIs, things like File System, Path, Process. It is a C API to access JavaScript. It is API stable. That means that you can compile it once, and your add-on once, and then you can reuse it across new versions of Node.js. The headers for the C API, it ships on npm. So, one package, that's all you need. And it contains these library files in two layers. One is the engine-specific part, and this is the js-native-api.h, creating values, calling functions, managing memory, for example, and then the runtime-specific part, which is more specific to Node.js. Runtime APIs, like buffers, async work, lifecycle events. Originally, Node API was designed to abstract V8 for Node.js internals, and basically, you could write your implementation once, and then you wouldn't have to link directly against the V8-specific version. For other runtimes now, they started adopting this. BAN and DINO, not necessarily in that order. And then later, React Native by Hermes, and this other implementers as well. This is the remarkable thing. You have one C header designed for one runtime that is now becoming a de facto standard in the industry.
Comments