from Hacker News

NPM and NodeJS should do more to make ES Modules easy to use

by bcherny on 6/20/24, 11:40 AM with 218 comments

  • by bastawhiz on 6/20/24, 1:36 PM

    The simplest solution is to stop requiring the top level package to be a module. Allow es modules to be require()-ed. It's be synchronous and slow and ideologically impure, but it'll make it so that millions of projects (mostly private!) will be able to start adopting es modules without a massive refactor. Anyone with a project of significant age or size looks at ES modules now and thinks "fuck it". There's no return on investment to convert (other than less pain while trying to upgrade or adopt new libraries). It's a big undertaking with loads of risk (modifying import order isn't safe!) and the payoff is "it's the shiny new thing".

    I had been using adminjs at work. Their new major version was ESM-only, and it was easier to _write a new admin panel from scratch_ than it was to refactor our entire codebase to be ESM just so we could upgrade one library. I expect that's the situation at hundreds of thousands of other companies.

    Like for all the belly aching that happened over async functions (and the whole function color rant), synchronous and asynchronous functions work together just fine through plain old promises. You can easily use async functions alongside functions that use old fashioned callbacks. ESM vs CJS is a file coloring (versus function coloring) problem, but there's no interoperability. There's no escape hatch when you just need one file to use another file but their colors are incompatible.

  • by knallfrosch on 6/20/24, 1:08 PM

    I don't know which is which. I don't care. I don't understand the benefit of a top-level await if I can simply await in a different file. I use Typescript which adds a layer in-between anyway. At work, we use Angular, which (I think) uses both Typescript and maybe esbuild. Or Webpack. Does it compile to ESM, or CJS? Who knows, and it will change in 2 years again anyway.

    All of that is something that I consider to be platform-level. It's insane that millions of feature-writing devs are expected to know all these arcana.

    Then again, it might be fixed™ soon Ⓡ

    https://joyeecheung.github.io/blog/2024/03/18/require-esm-in...

  • by jakubmazanec on 6/20/24, 3:42 PM

    I followed advice of Sindre Sorhus [1] and moved all my packages and apps to ESM year ago and couldn't be happier. Only Jest and ts-jest were problematic, so I replaced them with Vitest. I also never encountered problems because of the so-called dual-package hazard [2]; but IMO this isn't that much different than when you have two copies of React in node_modules - it's simply an npm/dependencies problem, not ESM problem.

    [1] https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3...

    [2] https://nodejs.org/api/packages.html#packages_dual_package_h...

  • by jeswin on 6/20/24, 1:37 PM

    ES Modules are better in every way.

    But I do believe they got the syntax wrong - should have been "from fs import { readFile }" so that auto-complete works. Python got that right, but that's the only thing Python got right ;)

  • by gbuk2013 on 6/20/24, 1:35 PM

    Can someone explain to me what the advantages of ESM actually are to me as a backend dev who uses import / export syntax in TS already?

    Parent article mentions static analysis and synchronous loading on startup but that has never been an issue for me despite building some large and complex Node apps over the years.

    I’ve looked into this in the past but all I could find are strong opinions without solid technical reasoning.

  • by can3p on 6/20/24, 1:29 PM

    I think the module imports apis are a python2/3 moment for node.js ecosystem. There is no clearly superior way and as a consequence not too many people care, however it hurts for real.

    The proposal to disable node.js style imports will just split ecosystem and make a large part of industry stick to ancient version / make a fork. Is that really worth the gain? Just check how long it took some bigger projects to migrate from python2 to python3

  • by apitman on 6/20/24, 7:08 PM

    My only complaint about the current state of ESM is that I can't figure out how to resolve the following:

    1. I'm developing a library that depends on d3js

    2. I want the library to be usable without any build tools. Just clone my repo and host the files from a static server. Or just import directly from jsdelivr

    3. I also want people to be able to use NPM to install my library if they so choose

    The problem is if I vendor d3js, then developers who consume my library via NPM might end up with 2 copies of d3js in their app, if their app also uses d3 directly. But if I don't vendor it, then my ESM-only users have to use an import map to resolve the bare specifier in the browser, which is kind of ugly and confusing.

    More details: https://stackoverflow.com/q/78645299/943814

  • by righthand on 6/20/24, 1:47 PM

    Why does it matter that people use ES modules instead of requires? They’re compatible enough. Javascript is weird because it has this directive for browsers to keep compatibility, but then has proponents for language changes that people try to force on everyone through framework/library use and design. All to the benefit of someone reading code the way they want to read code.

    It hasn’t changed because it’s not a real problem. This is like forcing main as the default branch in git.

  • by Aeolun on 6/20/24, 1:03 PM

    Or you can use Bun and have it handle all the nonsense. Or esbuild, but then you get a big blob, which isn’t really usable for a lot of things.

    The extensions were always silly to me. Who changes only a few files to esmodules? You either change your whole project or not at all.

  • by catapart on 6/20/24, 1:17 PM

    Just use JSR[0] and only deal with npm when a project forces you to do things backwards. Since JSR packages are available on npm, there's nothing lost.

    [0]https://jsr.io/

  • by TheRealPomax on 6/20/24, 4:42 PM

    At the very least, they finally should switch over to ESM-by-default and announce that 2 or 3 major versions in advance. "From Node 25 all code is assumed ESM unless you have `"type": "commonjs"` in your package.json" is not a particularly difficult message to send out and would stop people from writing new projects using the now legacy CJS (super great that it existed back when JS had nothing even close to a dependency model, but it should have been retired once ESM went from stage 4 to "this is literally and officially how JavaScript works")
  • by h1fra on 6/20/24, 5:12 PM

    The fact that `npm init` still not default to `type: module` is baffling
  • by ramesh31 on 6/20/24, 1:03 PM

    >NodeJS can officially drop support for require and module.exports in a future version, creating a bit more pressure to migrate.

    This will never, ever happen. Too much of the foundational ecosystem relies on it.

  • by PaulHoule on 6/20/24, 6:36 PM

    This is timely to me because I am in the middle of modernizing a project that was ejected from CRA years ago and now won’t build in Node 18.

    I’ve worked on a few big React projects but haven’t really looked much into how the build works, I found out upgrading one thing forced me to upgrade other things and I wound up making a lot of changes by hand to the build scripts and figured I’d probably screw something up. Dependencies changing from CommonJS to ESM was probably the most common problem that can frequently solved by version bumps (at risks of adopting changes you don’t want)

    At some point I decided to try the alternate path of switching to Vite for a build system since I’ve had good luck working with it for some VR side projects.

    It’s funny how you can code on front-end Javascript and not need to learn about CommonJS until something like this hits.

  • by lenerdenator on 6/20/24, 1:47 PM

    Surely, this will be the thing tacked onto JavaScript that will make it easy to scale and reduce toolchain complexity......
  • by fwlr on 6/20/24, 2:06 PM

    Bun put a lot of work into making both “import” and “require” always work regardless of whether it’s given a commonjs or an ESM target. I’d say that’s half of the right idea: make only import work with anything.

    Another angle that might be effective: take the most popular aspect of commonjs - `require(‘extensionless-string’)` - and tie it to the least popular aspect, .cjs extensions.

  • by o11c on 6/20/24, 4:29 PM

    As someone who only dabbles in JS, one problem is that ESM makes polyfills impossible. And polyfills are mandatory in the JS ecosystem.

    It's quite meaningful for dependencies to be fetched asynchronously, but sometimes you really need something to be executed in the order it's written.

  • by preya2k on 6/20/24, 2:33 PM

    And then here is one of the biggest backend JS frameworks (NestJS) clinging to CJS/holding off on migrating to ES modules. https://github.com/nestjs/nest/issues/13319
  • by ulrischa on 6/20/24, 2:47 PM

    The whole node npm ecosystemand tooling is so bad and broken. No other language is so frustrating. JavaScript was bad in the early years took a good way but is now stuck again. I tried webcomponents with lit. All very easy in the beginning. But when you try to use an external stylesheet you hit the wall of the modern js world: css can not be imported in js without a massive tool stack. I whish tue main focus would be tool- and buildless. This is really what is lacking
  • by 999900000999 on 6/20/24, 6:10 PM

    I'm tempted to say we need a complete reset of the NodeJS ecosystem.

    It will never happen because it would require coordination and money, but instead of having millions upon millions of different NPM packages, many of which are downright harmful, we should have a careful selection of maybe the top 20,000 or so.

    And then maybe call the next generation of node something else, maybe ProJS.

  • by pictur on 6/20/24, 4:53 PM

    if you look at most npm packages, you can see that versions that do not support es modules are downloaded more. and it's been like this for years. an example package: https://www.npmjs.com/package/p-queue?activeTab=versions
  • by meego on 6/20/24, 5:34 PM

    Barely a third of "high-impact" packages on npm are ESM. And that's with a generous definition of what an ESM package is. [1]

    [1]: https://github.com/wooorm/npm-esm-vs-cjs

  • by montroser on 6/20/24, 2:21 PM

    Node should just do like bun and support intermixing both. It was a mistake to force this schism -- untold hours of frustration and busywork for maintainers and developers with no hope of actually "completing" a mythical full transition to the new world.

    And for what? In Node specifically, it's not as if esm actually solves any real problem! In the greater ecosystem, sure it has some benefits, but Node doesn't even have to choose. Just support both at once, like bun and build systems have for a while, and let's move on from this nonsense.

  • by byt3h3ad on 6/22/24, 4:00 AM

    totally unrelated, but for the first time did i see a discuss here to threads. i had to double check if it was really the threads by instagram.
  • by plopz on 6/20/24, 4:16 PM

    not being able to mock es modules in tests is a real pain
  • by zazaulola on 6/20/24, 10:19 PM

    Jesus, what the hell?!

    Why do you dislike `require()` so much?

    Just imagine a person who doesn't write modules in Node.JS, but he would like his small scripts to be placed in one JS-file - without any additional directories and `package.json`. His script, for example, updates data for a desktop widget, is easily bypassed by standard nodejs modules and he has hundreds of such scripts in his folder. Why does he need all this `import` overhead?

  • by pcloadletter_ on 6/20/24, 1:35 PM

    How are the deer in Nara?
  • by tobyhinloopen on 6/20/24, 8:59 PM

    It’s such a waste of time to have this change so often. Can we just stop changing things? Require and module.exports was fine.
  • by replete on 6/20/24, 3:03 PM

    Completely disagree on getting rid of .mjs, .mts, .cjs, etc. This has actually solved a lot of the problems we had of mixed module loading IMO
  • by mirekrusin on 6/20/24, 1:16 PM

    And yet approximately 100% of js/ts devs are using ES module syntax and don’t write blog posts about it. Magic.
  • by rezokun on 6/20/24, 1:10 PM

    Or JS ecosystem should drop ES modules since they have only brought pain and unnecessary complexity without real benefits for years.