With Node.js 13.7.0 we finally have a standard way to make dual-packages which support both ESM and CJS with backwards compatibility with older Node.js versions, via conditional exports.
Category: Node.js
Dual Packages in Node.js with Conditional Exports
Resolving modules in JavaScript ESM
In JavaScript ES modules we can’t rely on CommonJS-style module resolution to add extensions to our import statements. Even Node.js has recently dropped automatic extension resolution in an effort to be more compatible with the ESM specification. Bare imports for Node modules is still possible, but as a side-effect dual-modules are no longer possible, except via deep-imports (import foo from 'bar/module.mjs';
).
Obviously nobody wants to write these out manually, but this presents some new challenges for transpilers, which unfortunately no transpilers have yet tried to solve.
So what can we do about this?
How to get the real require function in Node.js, when using a bundler
Recently I wanted to create a JavaScript module that would use the zlib module in Node, and fallback on pako in browsers. Seems simple enough, but actually proved somewhat difficult. Browser bundlers rewrite the CommonJS require function and by default shim the Node built-in zlib module with a less-performant pseudo-asynchronous pure-JS implementation. So how can we accomplish this you ask?
Adding a needed feature to Node.js's zlib module
Necessity is the mother of pull requests, so that’s what I did.
As you may know, Node.js is the JavaScript web server. As such, one of the necessary features for it to have is a zlib compression and decompression module. That module is actually pretty neat. It features both a syncronous and an asyncronous API backed by native-code which makes it much more efficient than JavaScript-based alternative.