Skip to content

Instantly share code, notes, and snippets.

@guest271314
Created August 17, 2024 19:22
Show Gist options
  • Save guest271314/037c08540e4b56eebe858e24efc26900 to your computer and use it in GitHub Desktop.
Save guest271314/037c08540e4b56eebe858e24efc26900 to your computer and use it in GitHub Desktop.
When version updates to JavaScript libraries mean you have to re-write code by hand, again

Designing and writing a software library is akin to building a house

I'll begin by likening writing source code of a library to building a house.

A general contractor has to make every move count. From selecting subcontractors to ordering materials, scheduling phases of construction, reading approved plans, contacting architects and engineers when questions or issues arise in the field on site, making sure subtractors get paid, keeping the owners happy, passing inspections, managing time, and importantly, thinking about how access, and repair whatever is being built and installed, because the general contractor is still on the hook years after the actual structures are completed per the approved plan, not doing things twice so you don't pay for it, literally.

In general, that same idea and question carried over to all trades during the installation process: How the hell do we or the next guy tear this out or fix this when something goes wrong?

JavaScript libraries: Runtime agnostic or runtime specific?

In software library composition domain, specifically in the JavaScript programming language world, there are tools that are designed to make compilation and bundling easier.

There's Webpack, esbuild, Rollup and others.

But before we get to that point, we might ask some questions among ourselves

  • Do we really need to use the internal modules of a single JavaScript runtime if we want our library to be used by multiple JavaScript runtimes?

  • Are there options available to implement the feature that are available in multiple JavaScript runtimes?

  • Do we use Node.js because that is the major player in the JavaScript runtime domain, and other JavaScript runtimes such as Deno and Bun are not worth the time and effort to consider writing source code for?

Now, I'm not sure if these questions are asked during design meetings before starting the project, because I mainly write my own code, by myself.

I could see how those questions could not be asked if the maintainers themselves did not use Deno, Bun, or other JavaScript runtime.

However, on the other hand, Deno and Bun do exist, and people are using those JavaScript runtimes, so it might be prudent to consider the farthest reach for the library.

Example

There's Node.js's crypto module that various libraries depend on in source code.

The problem is node:crypto is an internal Node.js-specific implementatio that cannot be polyfilled or exported.

One alternative approach available to solve that problem is to use yet another external dependency.

Another alternative approach is to use webcrypto object defined on node:crypto, e.g., import { webcrypto } from "node:crypto".

Deno, Bun, and Node.js each implement Web Cryptography API.

Now the library source code can be run in Node.js, Deno, and Bun by deciding to utilize Web Cryptography API instead of Node.js-specific internal modules.

You'll find similar issues with usage of node:os, which also can't be bundled.

Here I go again, re-writing by hand, line by line

In my individual case, I had previously hand written substitutions of Web Cryptography API for node:crypto. The library updates the algorithm. I have to rewrite the forked code - again. If Web Cryptography API were used, which exposes the same capabilities as node:crypto in standardized form, I could just use the library in Deno and Bun out of the box. That's not the case though. SO, back to the line by line edit.

Version updates: Are we thinking about backwards compatibility for currently deployed applications?

Of course, that also illustrates what happens when libraries are updated without consideration of existing code already deployed that won't work the next day when backwards compatibility is not thought about, and the code to run must be used in the application that validates the current code before executing.

If you and your team are thinking about writing a JavaScript library, and have an idea that you want your library to be runtime agnostic, even if you and your team only use Node.js yourself, consideration of the guy downstream that has to rewrite your code to be able to be used in Deno and Bun might be an additional question you can discuss.

Possible considerations for the future JavaScript library developer

It's a thoughtful adjustment to use existing Web API's that have been implemented in the given JavaScript runtime for Node.js, Deno, or Bun specific internal modules - and your library still gets to run in all of those JavaScript runtimes by using Web API's, a net gain for the library and developers downstream, with no disadvantages. The decision to use Web API's also means people downstream are not doing things twice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment