Live data from Hacker News

Node Modules at War: Why CommonJS and ES Modules Can’t Get Along

redfin.engineering

121–130 of 152 posts

Re: Node Modules at War: Why CommonJS and ES Modules Can’t Get Along

#121

I use the ESM dependency to load ESM modules as a CJS shim: https://www.npmjs.com/package/esm I highly recommend it. Really let’s you unify on ESM modules without much thought

For those who, like me, wondered how this is possible without hitting the top-level await obstacle mentioned in the article, the options doc includes this line (emphasis mine):

> "await":false - A boolean for top-level await in modules without ESM exports. (Node 10+)

So, yeah, seems to rely on "most ESM modules don't use top-level await". Seems like a useful option to have, thanks!

Re: Node Modules at War: Why CommonJS and ES Modules Can’t Get Along

#122
post #81
post #57

Earlier quoted context omitted.

> should instead have a CJS shim OP wrote, note that it’s easy to write an ESM wrapper for CJS libraries, but it’s not possible to write a CJS wrapper for ESM libraries.

It's not possible to write a nice automated transparent one for arbitrary libraries because of top level await, but it's totally possible for the 95%.

You cannot write a CJS shim for any library because the CJS shim cannot expose any ESM file with a synchronous API because importing ESM always returns a Promise.

You can - and people widely do - compile a CJS version of your library from ESM sources. You'll accept that there may be multiple copies of your library in the program but it does work. But in any case there's no reason to actually author in CJS, everything including the ESM shim can be generated from ESM.

Re: Node Modules at War: Why CommonJS and ES Modules Can’t Get Along

#123

Sorry about nitpicking, but I feel that we shouldn't say that CJS has named exports. It does not. CJS has a single export which might be an object. And objects have named properties/fields. On the other hand, ESM CAN have unnamed "default" export and CAN have arbitrary number of named exports.

> On the other hand, ESM CAN have unnamed "default" export and CAN have arbitrary number of named exports.

To nitpick on the nitpick: ESM only has named exports. It just treats the export named "default" differently in some scenarios and has special syntax for it.

So, roughly:

* CJS: Exports a single value which may or may not be an object. When assigning the exported value to local variables, destructuring can be used to access individual exports properties.

* ESM: Exports a namespace of named bindings. When importing the bindings to local aliases, the name of the alias can be changed using `as`. There's special syntax for importing the binding with the name "default".

It's somewhat unfortunate that the syntax _looks_ so close without being all that close.

Re: Node Modules at War: Why CommonJS and ES Modules Can’t Get Along

#124
post #120

Earlier quoted context omitted.

I made all my Py2 code forward compatible with 2to3. It was mostly a smooth process when you're using the future imports and know what landmines to avoid. It still required manual intervention at times with Unicode support and libraries that have breaking API changes between versions. The end result is something that can be Py3 native whenever I want. 2to3 is the right tool for the job. There is no way to map all Py3…

> There is no way to map all Py3 features back into Py2 so 3to2 would be a broken mess that only supported a subset of the language. Oh but there is. If you can map them to bytecode, you can map them to Python 2, which is a fully capable language. It won't be a one-to-one map, but that's also not required.

Not going to work for async.

Re: Node Modules at War: Why CommonJS and ES Modules Can’t Get Along

#125

I use the ESM dependency to load ESM modules as a CJS shim: https://www.npmjs.com/package/esm I highly recommend it. Really let’s you unify on ESM modules without much thought

Another similar option is `@babel/cli` which also allows using module syntax with require-like semantics. It's a bit more widely supported in other tools which can be an advantage.

Re: Node Modules at War: Why CommonJS and ES Modules Can’t Get Along

#126

You can use ESM (including dynamic import) in node 6+ (without babel) by using https://github.com/standard-things/esm and cut the `.mjs` and "it can't work like that" crap.

You can definitely continue to use transpilers like esm or babel to continue using CommonJS behind the scenes while writing module syntax. But it's not quite the same as using native modules, as implemented by JavaScript engines.

Re: Node Modules at War: Why CommonJS and ES Modules Can’t Get Along

#127
post #120

Earlier quoted context omitted.

> There is no way to map all Py3 features back into Py2 so 3to2 would be a broken mess that only supported a subset of the language. Oh but there is. If you can map them to bytecode, you can map them to Python 2, which is a fully capable language. It won't be a one-to-one map, but that's also not required.

Not going to work for async.

Why not? Provide your own future implementation, transform the async code into a state machine. Babel does exactly this for JavaScript async.

Sure the generated code is a horrific mess to look at but even that's a solved problem with sourcemaps if you need to debug it.

Re: Node Modules at War: Why CommonJS and ES Modules Can’t Get Along

#128
post #76

Earlier quoted context omitted.

It may be the reason, but not the only option. function cpsfoo(cb) {...} function foo() { var thread = this_thread() cpsfoo(x => thread.resume(x)) return thread.yield() } Error and immediate cb invokation handling omitted for clarity. Similar wrapper or wrapper-generator (uncps(f), unpromise(f)) may be done for other primitives.

Sure, it's not the only option, just the better option for Javascript. Your example isn't representative of Javascript. This is an example for something that might come up in Javascript, using async/await: const a = await fetchA(); const b = await fetchB(a); const stuff = await fetchStuff(a, b); const transformedStuff = await Promise.all(stuff.map(someAsyncTransform)); Error handling is just try/catch. Note that you…

They really do though. In the modal case you would just write the same code as in js but without all the extra keywords. If you need fanout you'd call some special function to do that, like you do now.

Re: Node Modules at War: Why CommonJS and ES Modules Can’t Get Along

#129
post #75

Wow that was informative. So ES Modules is really about the Red functions [1] getting module support. I find it fascinating watching our understanding of async computation mature over the years. [1] http://journal.stuffwithstuff.com/2015/02/01/what-color-is-y...

No, this is not correct. The split long predates async in JS The fundamental reason behind the difference between ES modules and CJS is that require() does synchronous I/O in a function, but that's not acceptable in the browser context. So you either need to make require an asynchronous function (meaning with a callback, back in 2010 when this happened) or move the I/O out of the execution of module itself, as import…

Sync xhr is being depricated. Meanwhile Google and Facebook analytics/tracking freeze the main thread for a whooping two seconds. Why not push the module dependencies with http2 push? The problem is not technical. Its big money wanting to break backwards compatibility.

Re: Node Modules at War: Why CommonJS and ES Modules Can’t Get Along

#130
post #73

Earlier quoted context omitted.

The reason why async/await is a good fit for Javascript is that it neatly wraps up asynchronous callback hell and Promises, which were already ubiquitous in Javascript code, because the web runtime enforces non-blocking IO.

Do Promises and async-await work together better than, say, Promises and Lua-like stackful coroutines?

I dont know Lua, but async/await in JavaScript is syntax sugar for a coroutine.
Post reply on HN