top | item 29140222

(no title)

aravindet | 4 years ago

There is a valid discussion to be had about whether the Node.js ecosystem disruption of moving from CJS to ESM is worth the benefits, but the assertion that it's technically worse isn't accurate. A few things ESM does better in Node.js:

1. Asynchronous dynamic import() vs. blocking require(): allows the program to continue while a module is being dynamically loaded.

2. Circular dependencies: ESM correctly resolves most of them, while CJS does not. [example below] I believe this is possible because ESM top-level imports and exports are resolved before JS execution begins, while require() is resolved when called (while JS is already executing.)

3. Reserved keywords `import` and `export` vs. ordinary identifiers require, exports and module: Allows tooling to be simpler and not have to analyze variable scope and shadowing to identify dependencies.

I haven't really encountered #3, but I can say I've benefited from #1 and #2 in real-world Node.js projects using ESM.

----

Circular dependencies example:

   // a.js
   const b = require('./b.js');
   module.exports = () => b();

   // b.js
   const a = require('./a.js');
   module.exports = () => console.log('Works!');
   a();
Running this with "node b.js" gives "TypeError: b is not a function" inside a.js, while the equivalent ESM code correctly prints 'Works!'. To solve this in CJS, we have to always use "named exports" (exports.a = ... rather than module.exports = ...) and avoid destructuring in the top-level require (i.e. always do const a = require(...) and call it as a.a() elsewhere)

discuss

order

No comments yet.