April 30, 2019

Serialport Spring Update

Serialport turns 9 this year. Back when it started NodeJS was a different environment than it is now. JavaScript was a different programming language than it is today. Since then I've pushed some major changes over the years to keep us modern. I made the (then) painful decision to drop old versions of node even though some devices would never see the updates to newer runtimes. Sticking to supporting only the LTS (Long Term Support) versions of NodeJS made it possible for us to take advantage of newer features.

When Node v0.12 was end of lifed we were able to drop a lot of the legacy code behind. It allowed me to rewrite the streams layer with streams 3. We were always compatible with streams 2 but it was a custom stream implementation. It also prompted me to split out the bindings layer and make a promise based api for lower level operations. This shook out a lot of bugs and made the code, and testing a lot easier. (And since then bindings are being used on their own!)

Node 4 was a unification of IOJS and NodeJS. IOJS was able to bring many advancements and features from JavaScript into node itself (as well as breaking with a lot of past decisions). Node 6 was the first in a new breed of NodeJS where we had a proper release cycle. Odd release numbers were for experimenting, and even ones were for long term support and stability. Each even release meant we had new features we could take advantage of with minimal breakage of old code. Node 5 and Node 6 was the first try at making that work, and to great success.

Today we say goodbye to Node 6. It's reached it's end of life and is no longer supported. This means we can now take advantage of newer features brought to us in Node 8. This includes speed and stability, some great language features, and most notably for serialport, N-API.

N-API is an ABI compatibility layer binary modules for NodeJS. This means an @serialport/bindings build for NodeJS 8 will work on 10, 12 and hopefully into the future. Right now serialport builds 30 versions of our binary bindings. I'll be frank. It's slow, flaky and it sucks. On my other projects the CI finishes before I can check github, but on serialport it takes about 40 minutes. Our test suite takes less than 10s. With N-API we can drop the number of builds to 6 (64 and 32 bit builds for Windows, Darwin and Linux). But it's not just good for developing serialport, it's good for everyone who uses it. In theory, electron will "just work", and we can easily bundle the 6 builds in the npm package itself removing the need for downloading anything during install.

I had a call with the N-API working group yesterday where they guided my hand a bit. The biggest takeaway is that I can't use node's libuv, as while it might be ABI stable (not a guarantee?) node isn't guaranteed to use the save version of libuv in the future.

The steps as I see it;

  • We can consider node-addon-api vs the c function calls.
  • We can replace all use of uv_work_t with napi_async_work
  • We have to rewrite serialport not use use uv_poll_t on Darwin and Linux
  • We can keep prebuild which we use for publishing and downloading the binaries is already N-API aware, so we need to tell it we are now N-API compatible.
  • From there we can look into bundling the binaries on publish (harder than it sounds).

When all binary packages are using N-API users will have a lot less trouble using them. I'm excited for this future.

Github issues:

Other things I'm thinking about:

  • My two failed typescript ports (changing everything at once is hard)
  • Changes to the api that bring a better cross platform experience but are breaking changes
  • A build step that works with lerna
  • async iterator interface
  • new bindings interface similar to web-serial

-Francis

Roborooter.com © 2024
Powered by ⚡️ and 🤖.