[HN Gopher] NPM and NodeJS should do more to make ES Modules eas...
       ___________________________________________________________________
        
       NPM and NodeJS should do more to make ES Modules easy to use
        
       Author : bcherny
       Score  : 195 points
       Date   : 2024-06-20 11:40 UTC (11 hours ago)
        
 (HTM) web link (borischerny.com)
 (TXT) w3m dump (borischerny.com)
        
       | ramesh31 wrote:
       | >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.
        
         | game_the0ry wrote:
         | > This will never, ever happen.
         | 
         | I hope for the sake of the nodjs ecosystem, you are wrong.
         | 
         | Fragmentation issues are one of the many reasons that nodejs
         | struggle with adoption.
        
           | baq wrote:
           | > nodejs struggle with adoption
           | 
           | Woah there. If nodejs is struggling for adoption I don't know
           | what isn't.
        
             | game_the0ry wrote:
             | Let e put it differently: nodejs would have _more_ adoption
             | if it had less perceived instability.
        
           | bastawhiz wrote:
           | If it does happen, it'll only cause more fragmentation.
           | Because lots of projects and libraries simply won't upgrade.
           | Look at Python: it took them _decades_ to get folks to
           | upgrade to py3k because they broke the old code. Do it to
           | Node and it 'll be decades of fragmentation.
        
           | dgb23 wrote:
           | Breaking code that doesn't need to be broken is the biggest
           | redflag for a platform or foundational library.
        
         | jeswin wrote:
         | > Too much of the foundational ecosystem relies on it.
         | 
         | Not saying it needs to be done, but this can possibly be
         | handled via a tranpiler layer. It might make CommonJS a bit
         | slower to startup (but fully functional), which is an added
         | incentive to move.
         | 
         | Again, I don't have any opinion on whether this is a good
         | thing. Like you said, too many modules depend on it.
        
           | mistercow wrote:
           | You don't really even need a transpiler. Require is basically
           | just a function which loads a file, wraps it in some
           | boilerplate, and evals it. You could just rip that runtime
           | code out of node and provide it as a compatibility library.
        
           | bastawhiz wrote:
           | > but this can possibly be handled via a tranpiler layer. It
           | might make CommonJS a bit slower to startup (but fully
           | functional), which is an added incentive to move.
           | 
           | "The new version runs your old code slower and it's enough to
           | notice" would be a death blow to the ecosystem. No major
           | company is going to upgrade to that. It's already a project
           | to drag a major codebase kicking and screaming to a new LTS
           | release of your runtime (even if it makes code faster), do
           | you really think folks will invest the time to work to make
           | their code run slower unless they invest even more effort and
           | modify ~every module in their codebase?
           | 
           | ESM isn't implicitly good. The benefits of ESM are almost
           | entirely theoretical for pretty much everyone who is content
           | with CJS. I manage codebases right now that total half a
           | million lines of typescript and js and I think I simply
           | wouldn't notice any improvements from converting any of the
           | code. The point being: this isn't a problem for me or people
           | in similar situations, it's a problem for the folks working
           | on Node and the standards. Forcing folks to upgrade or making
           | their code worse to exert any kind of pressure _does nothing_
           | to help anyone.
        
         | tqwhite wrote:
         | An insanely bad idea.
        
       | Aeolun wrote:
       | 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.
        
         | jasfi wrote:
         | I look forward to the day when Bun can run Next.js. Apparently
         | the main showstopper is in the Next.js router.
        
           | evilduck wrote:
           | I'm not steeped in the history of this issue but I
           | periodically run a maintained and up to date NextJS app via
           | Bun in a dev env just to monitor performance and
           | compatibility. It uses the app router and the edge runtime
           | middleware, hosted from a Docker container. I haven't seen
           | massive benefits using Bun since Next doesn't use the Bun-
           | specific libraries that make their performance numbers great,
           | but I haven't seen any game breaking issues either, it runs
           | and all the app's E2Es pass.
        
         | afavour wrote:
         | > Who changes only a few files to esmodules? You either change
         | your whole project or not at all.
         | 
         | Transition. It's a much lighter lift to transform a project
         | piece by piece than do the whole thing.
        
         | lefrenchy wrote:
         | Does it actually handle it though? I use bun to run my remix
         | app at work and I have run into ESM/CJS issues.
        
         | dimgl wrote:
         | Bun handles all of the nonsense but the catch is that it blows
         | up both in dev and in production. Wake me up when Bun doesn't
         | segfault/fail to work at all.
        
       | knallfrosch wrote:
       | 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(tm) soon r
       | 
       | https://joyeecheung.github.io/blog/2024/03/18/require-esm-in...
        
         | dboreham wrote:
         | Now we see the benefit of having adults in charge, e.g. as is
         | the case with golang for example.
        
           | throwitaway1123 wrote:
           | Go has the benefit of not having to reach a distributed
           | consensus amongst a variety of individual browser vendors.
           | Try compiling a large Go project with tinygo to get a glimpse
           | of what it's like to have to deal with multiple independent
           | runtimes [1]. If the browser vendors had been able to ship
           | ES4 or ES5 with module support between 1999 and 2009, then
           | Node probably would have implemented it from the very
           | beginning, and there would be no dichotomy between CJS and
           | ESM.
           | 
           | [1] https://github.com/evanw/esbuild/issues/1111
        
         | dimgl wrote:
         | The whole point of this is that ESM was very poorly handled.
         | It's irrelevant to TypeScript, esbuild, Webpack, etc. That
         | tooling handles the complexity for you and sometimes that
         | backfires. I've run into a lot of headaches with the TypeScript
         | compiler.
         | 
         | The fact that you don't know whether your codebase uses
         | TypeScript, esbuild or Webpack is disappointing. It means that
         | those worries have been handled for you and you don't care to
         | learn them, which is never a good stance if you work with this
         | on a daily basis. But I somewhat agree that it should all be
         | vastly simpler.
         | 
         | I also kind of agree with the downvoted/flagged comment re:
         | Golang. The way the JavaScript ecosystem works is highly
         | dependent on the way Node is handled. And Node has, for many
         | years, made ESM needlessly complicated.
        
           | knallfrosch wrote:
           | > The fact that you don't know whether your codebase uses
           | TypeScript, esbuild or Webpack is disappointing. It means
           | that those worries have been handled for you and you don't
           | care to learn them
           | 
           | En contraire. The problem is that some years ago I did learn
           | the basics, but the ground has shifted underneath my feet
           | multiple times. There's not really an incentive to learn the
           | finer points of ESM-vs-CJS if Typescript hides the input into
           | the system, Angular has its own ideas about modules, uses
           | Webpack or babel internally and then spits out CJS anyway.
           | 
           | The whole JS ecosystem is nice if you edit 10 files by hand,
           | but I just don't know what I should do with the knowledge
           | that I should "require cjs" when I need Typescript for type
           | safety and it'll only let me "import ts" anyway.
        
         | Shacklz wrote:
         | > All of that is something that I consider to be platform-level
         | 
         | I agree with this, but the whole point of the blog-post is that
         | the "platform" currently handles this rather poorly.
         | 
         | I have yet to see a frontend-project that was bigger than some
         | three-person-garage-hobby that didn't occasionally run into CJS
         | versus ESM issues. Maybe not something that pops up on the
         | radar of all the devs in the project but at least at the level
         | of folks who take care of the setup and whatnot, it often pops
         | up in rather painful fashion. Case in point; a few angular-
         | versions back, umd-bundles were dropped, which at least for the
         | project I worked on caused me quite a lot of headache as some
         | of our tool-chain (most notably our testing-setup) relied on
         | angular shipping commonJS-compatible modules.
         | 
         | It's currently also a major pain for anyone publishing an npm-
         | package, even if it's primarily intended to be run on node. The
         | kind of incantations one has to do are just insane (especially
         | if you dared to import from node:crypto or want to support more
         | than just the latest lts); I've just stopped bothering after
         | tearing my hair out for a weekend to no avail, even though I
         | really wanted to support ESM as well.
        
       | rezokun wrote:
       | Or JS ecosystem should drop ES modules since they have only
       | brought pain and unnecessary complexity without real benefits for
       | years.
        
         | pavlov wrote:
         | ES modules work natively in browsers, which are the slow-moving
         | ships of the ecosystem. Changing course for them is completely
         | unrealistic.
         | 
         | There's a billion browser clients out there. That ensures that
         | whatever API they ship, an increasing amount of code will be
         | written directly against it. Everybody else just needs to adapt
         | or be seen as incompatible with the baseline of JavaScript.
        
           | rezokun wrote:
           | Show me a real product on the web that does not compile or
           | bundle and uses native modules for code delivery. It's a dead
           | technology that only fragments the ecosystem and makes life
           | harder.
        
             | jsmith99 wrote:
             | Many bundlers output module format - it makes features like
             | code splitting (chunking into separate files) convenient.
        
               | rezokun wrote:
               | ES modules mean you don't need to bundle your code; you
               | just include your index.js in HTML, and all 30,000 JS
               | files of your project come to the user's browser without
               | trouble or delay (let's wish them luck, lol). Since
               | you're bundling, it doesn't matter which module type you
               | use; CJS has worked with code splitting perfectly for
               | over 10 years. However, it's a pain every time you try to
               | import a CJS library in your ESM or vice versa. The truth
               | is, you can't just drop all legacy CJS packages in most
               | real-world projects.
        
               | pavlov wrote:
               | _> "all 30,000 JS files of your project come to the user
               | 's browser without trouble or delay (let's wish them
               | luck, lol)"_
               | 
               | If only there was something in the HTTP protocol to make
               | it more efficient to load multiple requests from the same
               | server. Alas that must be a pipe dream, and every little
               | image and script is loaded separately.
               | 
               | Oh wait, it's not 1996 anymore...?
        
               | tracker1 wrote:
               | I hear there's this new HTTP 2 spec that might be able to
               | do something like that... but obviously we need to wait
               | on browser support
               | 
               | /s
        
             | pavlov wrote:
             | The web is not just for "real products". It's also a
             | platform with tens of millions of hobbyists and dabblers
             | writing HTML and JavaScript.
             | 
             | I promise you they will use any feature that's documented
             | on MDN as being available in all browsers. And ES modules
             | do make life easier for someone who's just writing HTML and
             | JS and doesn't know anything about build tools.
             | 
             | IMO, it's the wrong attitude that we should focus on the
             | professional ecosystem and forget about this use case.
             | Probably most people writing front-end code got their start
             | by creating a HTML file in Notepad (or equivalent) and
             | loading it via file:// into the browser.
        
             | WorldMaker wrote:
             | It's a _great_ development experience today: no waiting for
             | bundlers, easy inner dev loop, let the Browser do all the
             | loading just like Web 1.0 and JS development was maybe
             | supposed to feel.
             | 
             | It will become more common in products. There are going to
             | be startups that see that great development experience and
             | long for some returns towards "just FTP it to the web
             | server as-is" CI/CD processes. There are going to be more
             | product owners everywhere (startups, Enterprise) that think
             | that HTTP/2+ adoption (or even HTTP/1.1 properly
             | configured) is acceptable in the real world and that they
             | are done with most of the needs for bundling.
        
         | jeswin wrote:
         | IMO, it's the best thing to happen to Node. It (kinda) unifies
         | browser and server syntax, and across competing server-side JS
         | frameworks (Node, Deno, Bun). CommonJS was clearly a NodeJS
         | thing.
         | 
         | We embraced ESM a couple of years back. It was a bit harder
         | earlier on; for example our test frameworks didn't support
         | mocking ESM code well enough. But now there's hardly anything
         | to complain about. There's no going back really - we wouldn't
         | want to.
        
           | 123yawaworht456 wrote:
           | >IMO, it's the best thing to happen to Node. It (kinda)
           | unifies browser and server syntax, and across competing
           | server-side JS frameworks (Node, Deno, Bun). CommonJS was
           | clearly a NodeJS thing.
           | 
           | what the fuck was the point of unifying this particular thing
           | at such a great PITA cost, when obviously none of node APIs
           | work in the browser?
           | 
           | should things like Buffer be removed too? the browser only
           | has Uint8Array, after all.
        
         | afavour wrote:
         | Couldn't disagree more. It's wonderful having the same module
         | syntax on server and client.
        
         | game_the0ry wrote:
         | Huh? You need to elaborate a bit before making a statement like
         | that, friend.
        
       | mirekrusin wrote:
       | And yet approximately 100% of js/ts devs are using ES module
       | syntax and don't write blog posts about it. Magic.
        
         | tqwhite wrote:
         | According to the article, three quarters of the npm projects do
         | not use ESM. Their programmers must be very magical.
        
       | catapart wrote:
       | 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/
        
         | creesch wrote:
         | Neat to get to know JSR, but doesn't this have very little to
         | do with the contents of the article you responding to? While I
         | know NPM is in the title, the actually article is about module
         | imports which JSR doesn't change.
        
           | catapart wrote:
           | The article is saying "this ecosystem should change because
           | it doesn't do specific things that make sense for it to do".
           | 
           | JSR says "here's a way to leave the original ecosystem alone,
           | but have a better-fitting ecosystem that does the things you
           | want". (not sure about the 'jsr doesn't change' bit? It
           | literally requires ES modules, in lieu of common js modules).
           | 
           | Seems pretty relevant, to me, but YMMV. I understand it's not
           | a direct answer, but it seems as relevant as "here's
           | typescript" to someone saying "we should add types to
           | javascript".
        
         | jmondi wrote:
         | I have mixed feelings about the JSR requirement for explicit
         | typing. Other than that, it is pretty great!
        
           | catapart wrote:
           | Hm? This is news to me. As far as I know, you can just
           | publish pure javascript. I know that it's going to give you a
           | worse 'score' if you don't have types, and it may require
           | explicit typing of TS (but, strictly, so does TS), but I
           | wasn't aware that there was not any way to publish to JSR
           | without types. I'll have to look in to that, thanks!
        
         | nox101 wrote:
         | jsr seems great! I hope they work out their kinks but I'm
         | really glad someone is trying to push things forward.
        
       | can3p wrote:
       | 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
        
         | cxr wrote:
         | The difference is the language/standard in question neither
         | originated with NodeJS nor is NodeJS now nor has it ever been
         | led by the people behind the language/standard (unlike
         | Python)...
         | 
         | When you hear "NodeJS", you really need to bethinking of it in
         | the same category as IE (wrt browser behavior) or Visual C/C++.
         | It's but one, often (knowingly/deliberately) quirky, non-
         | standard implementation by a group that doesn't necessarily
         | have your best interests at heart or the interests of those
         | outside their own platform umbrella.
        
       | pcloadletter_ wrote:
       | How are the deer in Nara?
        
         | bcherny wrote:
         | Cute, when they aren't trying to eat my phone.
        
       | gbuk2013 wrote:
       | 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.
        
         | afavour wrote:
         | IMO the game changer in your scenario is when type annotations
         | are added as a standard JS feature:
         | 
         | https://github.com/tc39/proposal-type-annotations
         | 
         | At that point (and with ES modules) you'd be able to run your
         | TS code directly without any transpilation necessary. I'd
         | _love_ to remove all the build process junk from my projects
         | and have them run quicker.
         | 
         | I've written a few projects as plain ESM JS with JSDoc type
         | annotations and it truly is a joy to bypass build steps. JSDoc
         | type annotations do get annoying as a project grows to a
         | certain size, though.
        
           | gbuk2013 wrote:
           | When I see "stage 1" and "if they stick within a certain
           | reasonably large subset of the language" the cynical old dev
           | in me starts waving a YAGNI sign. :)
        
             | afavour wrote:
             | Honestly as you read through the proposal the immediate
             | impression is "they're just describing TypeScript syntax",
             | which is... fine, I think? But I do feel like it would be a
             | considerably quicker process for Node to just add the
             | ability to parse a TS file than it will be to go through
             | this formal approval process.
        
               | eyelidlessness wrote:
               | The process is standardizing the ECMAScript language. It
               | would make types (as comments) standard for all JS
               | runtimes, not just Node. I don't think the community at
               | large wants _more non-standard Node stuff_ , as that's a
               | frequent point of pain and complaint (see OP article as
               | an example).
        
           | wokwokwok wrote:
           | > The aim of this proposal is to enable developers to run
           | programs written in TypeScript, Flow, and other static typing
           | supersets of JavaScript without any need for transpilation,
           | 
           | > if they stick within a certain reasonably large subset of
           | the language. <-------- !!!!!!!!!!
           | 
           | js + type annotations !== typescript
           | 
           | The most recent discussion sums this up with, I think _this_
           | comment:
           | 
           | > EAO: Okay. So the sense I get overall of this whole
           | proposal, that it's more of a - it's a solution looking for a
           | problem that it's trying to solve a year ago when this got
           | accepted for Stage 1, the problem statement that was in fact
           | considered then was only effective we made up or made
           | concrete during the meeting itself, and then - so what it
           | looks like now is that since then, that problem statement has
           | evolved to this current form of unifying or unforking
           | JavaScript and somehow then presenting type annotations as a
           | way of achieving this result. However, I've not been able to
           | find any conversation anywhere or description of how in
           | practice this unification is supposed to happen as a
           | consequence of accepting type annotations.
           | 
           | No one had a good answer to that, because there isn't one.
           | 
           | Anyhow, tldr; this has basically nothing to do with any
           | tangible reason to think ESM is good or useful in anything
           | other than a massively broad, speculative 'maybe in the
           | future' kind of way.
           | 
           | ...it is most certainly not any kind of advantage or reason
           | to use ESM for anyone, right now.
        
             | afiori wrote:
             | Being able to copy paste typescript snippets in the browser
             | console is enough of a benefit in my opinion
        
             | WorldMaker wrote:
             | > js + type annotations !== typescript
             | 
             | It's _very_ close though. The proposal is well written and
             | covers the cases where existing Typescript code would not
             | parse correctly /work as intended under the proposal. Most
             | of those cases are pre-1.0 Typescript features still in the
             | language for backwards compatibility but generally frowned
             | upon and that you probably already have strict warnings and
             | linter errors preventing you from using today. The big
             | exception is a lot of TS codebases heavily use `enum` and
             | I've still not seen enough suggestions to tighten the
             | linter warning against it. (But there are at least some of
             | us suggesting avoiding TS `enum` today.)
        
           | rty32 wrote:
           | I would argue the benefit is just making everything much
           | simpler. You never need to think about module systems and
           | interoperability -- there is only one module system to deal
           | with.
           | 
           | That proposal seems to have stalled, and I doubt it's going
           | anywhere. Here is the thing: people want hard, strict
           | compiler checks that can be enforced at all time, not Python-
           | style type hints. If you want JavaScript but type checked,
           | Typescript is the de-facto standard. Either do "checkJS" or
           | convert the project to Typescript. In fact, the latter is
           | much better in terms of expressiveness.
        
             | tqwhite wrote:
             | It only makes it simpler if you have a new project and can
             | be ESM pure. If you are working with existing code or need
             | non-ESM modules, everything is _much_ more complicated.
        
           | an1sotropy wrote:
           | Fwiw the github page for that proposal isn't linking to what
           | seems to be the most recent discussion *. I thought type-
           | annotations-as-comments was a no-brainer, but it seems messy.
           | The Sept 2023 discussion shows that it is complicated by the
           | current variety of annotation schemes (TypeScript is not the
           | only one), and the parsing subtleties, which gave rise to
           | unresolved questions about what is the basic motivation.
           | bummer.
           | 
           | * https://github.com/tc39/notes/blob/main/meetings/2023-09/se
           | p...
        
         | Quothling wrote:
         | There isn't that much difference on the backend if you use Node
         | and Typescript. ESM is the standard for JavaScript and you'll
         | probably run into situations where you can't use a new
         | JavaScript feature with CommonJS as early as you can with ESM.
         | There are disadvantages and advantages to how the modules load
         | on Node, but ESM is generally improving faster than CommonJS.
         | 
         | If you're looking into other runtimes ESM used to be the way to
         | go because of Deno, but these days you're likely either running
         | Node or Bun and both work well with CommonJS and ESM.
         | 
         | If you do both frontend and backend work, or if your team has a
         | lot of cross-over between the two sides of the ecosystem, then
         | it'll likely be easier for you to use ESM on both ends as
         | CommonJS isn't supported by browsers.
         | 
         | I think the primary reason CommonJS is still around is mostly
         | because Typescript replaces it's import/export module system
         | with something that's basically similar in syntax to the way
         | ESM does it untill it gets transpiled into Javascript. If
         | people actually had to work with CommonJS modules in 2024 then
         | I think they'd likely go insane.
         | 
         | Not everyone will agree with me on this, but I don't think
         | there is a reason to rewrite old projects into ESM unless you
         | have a very good reason to do so. That being said, there isn't
         | really a good reason to start new projects with CommonJS
         | either... Unless you have a really good reason to do so.
        
         | WorldMaker wrote:
         | A big technical reason especially specific to using Typescript:
         | not transpiling to CJS speeds up your Typescript builds.
         | 
         | It also opens up more options when Typescript is just "type
         | stripped" rather than transpiled to an incompatible module
         | syntax. You probably still want a full Typescript compile at CI
         | time to get robust typechecking, and you'll have the Typescript
         | LSP doing its thing in your IDE still, but you can use type-
         | stripping tools like esbuild for very fast type stripping in
         | some portions of your inner dev loop.
         | 
         | The static analysis that ESM supports is handy because it opens
         | up technical benefits like Tree Shaking. Your apps might run on
         | SSDs, you probably don't have a lot of reasons to bundle them,
         | you likely aren't worried about on disk size, you might not be
         | worried about bundle publish size to npm, and so you might not
         | think Tree Shaking applies to you, but V8 under the hood of
         | Node is still going to do Tree Shaking of _memory_ and garbage
         | collection for you with ESM in ways that it simply cannot with
         | CJS. I 've seen some real memory performance gains in Node apps
         | just switching from CJS to ESM already, and V8's ESM
         | optimizations only seem to get better as more ESM is deployed
         | in the wild.
         | 
         | There are more, smaller technical benefits, but "type stripping
         | not transpiling" and "in memory tree shaking" are strong ones
         | that are easy to overlook.
        
         | paulddraper wrote:
         | > 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?
         | 
         | 1. The downstream users of your backend library can use ESM JS.
         | 
         | 2. You can author (or output) isomorphic code that works in
         | Node.js and other environments.
         | 
         | 3. Static analysis tools can more reliably understand your
         | dependency graph, e.g. find unnecessary code/modules/packages.
         | 
         | 4. You can use a custom load API to do customized operations.
         | E.g. import a YAML file as a JavaScript object.
         | 
         | If none of these apply to you individually, then you don't have
         | a lot to be gained.
        
       | bastawhiz wrote:
       | 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.
        
         | throwAGIway wrote:
         | What about the createRequire function?
        
           | bastawhiz wrote:
           | Why should I need to go out of my way to do this? Why do I
           | need to care what kind of module I'm importing and reach into
           | the stdlib to run code? It should just work.
        
             | throwAGIway wrote:
             | To be frank I don't care about these questions, perhaps
             | you're right and it should, but whatever. It's a solution I
             | used in the three cases it was necessary that blocked
             | moving my codebase to ESM.
        
               | sureIy wrote:
               | You're missing the point. Of course createRequire is a
               | solution, it's always been. The problem are tools and
               | sub-dependencies that you can't touch.
        
         | afavour wrote:
         | > 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
         | 
         | A middle ground answer would be using import() in CJS to
         | asynchronously require the ESM module. It would require some
         | hacking around your loading flow to ensure the module loads
         | before you try to do anything with it but would still be
         | preferable to rebuilding the entire thing.
        
           | bastawhiz wrote:
           | I don't disagree! But is there really an argument (other than
           | an ideological one) for why it needs to be an awaited import?
           | Why does it matter that it's async?
        
             | eyelidlessness wrote:
             | ESM (as standardized, not necessarily as implemented in
             | Node) treats import specifiers as URLs. That alone would
             | inherently be async because network requests are async
             | across basically all JS runtimes. ESM was also later
             | extended to support top level await, making module
             | execution itself async.
             | 
             | Node has recently taken a more pragmatic approach, by
             | treating local specifiers as potentially synchronous,
             | allowing sync require() of ESM... which then fails _if_ the
             | required module uses top level await.
        
               | WorldMaker wrote:
               | "Sometimes works, but can also blow up at runtime after
               | any upgrade" seems to me like a "pragmatic cure" that is
               | worse than the existing "disease" of needing to treat all
               | ESM imports as async and/or migrating all uses of
               | `require()` to `await import()`. If incrementally moving
               | a CJS code base to use `await import()` in more places is
               | too hard then you probably have other problems you've
               | overlooked for too long (bad promise usage, callback
               | waterfalls, etc).
               | 
               | (But I'm a hardline "all you need is type=module" sort
               | and think a CJS=>TS emitting ESM "rip off the bandaid"
               | approach to CJS legacy libraries works and is
               | fundamentally easier than most of the "pragmatic"
               | solutions to CJS/ESM interop. It is past time to jettison
               | CJS out the airlock.)
        
               | zarzavat wrote:
               | Fetching code at runtime over the network makes sense in
               | a browser, it doesn't make sense outside of a browser and
               | would actually be a huge security risk without all of the
               | security features that browsers have. So it just
               | reinforces the perception that ESM was only designed for
               | browsers.
               | 
               | Both TC39 and node utterly cocked this up. The design of
               | ESM is bad, async imports are a stupid idea, and node's
               | implementation has been beset by ideology.
        
             | tqwhite wrote:
             | I'd say it's exactly the opposite. Neither require() or
             | import require an async code structure. The biggest reason
             | I avoid ESM like a plague is that many of my projects are
             | not, and do not need to be, async. Adding import() is a
             | huge hassle because it is async.
             | 
             | Adding an importSync() function would be a perfect
             | solution.
        
               | sureIy wrote:
               | importSync exists and it's called import statement.
        
               | tqwhite wrote:
               | That's a pretty douchey thing to say.
        
           | IggleSniggle wrote:
           | That was my first thought, and what I attempted first in my
           | project. But it turned out that rewriting everything, while
           | being incredibly tedious, was significantly easier to reason
           | about and ensure continuity than developing my own bespoke
           | dependency loader in a large project where not all portions
           | are well understood.
        
           | ComputerGuru wrote:
           | I have a custom loader that can operate in both sync and
           | async mode with the same syntax; it started off as a single
           | loader to load AMD and CommonJS but I've been meaning to add
           | ESM support as well (it was more opaque than I liked when I
           | last tried, required too much browser magic).
           | 
           | https://github.com/mqudsi/loader
        
         | microflash wrote:
         | > 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.
         | 
         | This is already available in Node.js 22 [1] with `
         | --experimental-require-module` flag.
         | 
         | [1]: https://nodejs.org/en/blog/announcements/v22-release-
         | announc...
        
           | jauntywundrkind wrote:
           | Before Node had any/experimental module support (April 2019,
           | https://nodejs.medium.com/announcing-a-new-experimental-
           | modu...), I'd been using std-things/esm loader for Node.js,
           | which seemed to have no problem allowing CJS and ESM to
           | interop, require and import each other. In my experience it
           | worked flawlessly. https://github.com/standard-things/esm
           | 
           | It's wild to think about: esm has taken nearly a decade to be
           | feasible for folks to use, without heavy encumbrance; it was
           | the key feature of es-2015/es6!
           | 
           | It took many more years for import-maps to become a thing,
           | such that we could start using modules in a modular fashion;
           | we've had to use bundlers/codemods to re-resplve
           | dependencies, unless you've been going to go Deno's original
           | path of just hitting absolute urls wherever they be. There's
           | still no standing proposal for how we get import-maps on
           | service-workers & shared workers; modules still are not a
           | ubiquitous feature of the core web & JavaScript ecosystems. 9
           | years latter. https://github.com/WICG/import-maps/issues/2
           | 
           | It's been hard being a webdevs, when the future remains so
           | partially implemented.
           | 
           | The article's exploration of the bomb ecosystem is telling.
           | And is much of the reason I hope JavaScript Registry (jsr)
           | project might succeed. Npm will never escape it's past. CJS
           | is going to be in there for a long time. Being on a registry
           | where everything is esm & typescript, that sounds divine.
           | https://deno.com/blog/jsr-is-not-another-package-manager
        
             | z3t4 wrote:
             | Did anyone actually want ES modules, and are anyone using
             | ES modules in production today? I don't think so except for
             | transpiling languages that compile and bundle the JS. The
             | only argument against lazy loading is that single threaded
             | UI's will freeze for a few ms when the code loads, but if
             | you compare that to the time it takes to fully load a
             | modern website that point is moot.
        
               | apitman wrote:
               | There are a few hiccups, but I've found ESM to be a huge
               | win overall. The killer feature for me is the ability to
               | write code that can be imported in a browser without any
               | sort of build step. You don't even need node/npm. Just
               | download the file/directory from somewhere and import.
               | It's perfectly feasible to build a complex browser app
               | with many dependencies using nothing but git submodules.
               | 
               | The main thing you're missing out on is the optimizations
               | that come with bundlers. But they should be treated as
               | just that: optimizations. You shouldn't be required to
               | use a bundler just to develop/distribute JS programs.
        
               | jauntywundrkind wrote:
               | (Most) everyone was already using bundlers at this point.
               | Tree shaking was much easier to do after the dependency
               | graph became computeable. Which it wasn't with CJS;
               | require could happen anywhere with any parameters. And
               | require happening anywhere while being sync was kind of a
               | non-starter. That freeze is amplified by most projects
               | having hundreds of not thousands of requires across it's
               | dependency graph.
               | 
               | There's definitely some truth to your gripes. Back in
               | 2015 there was a ton of latent hope http/2 push and ESM
               | would let us get away from bundling & perhaps even
               | needing build steps at all. That hasn't panned out.
               | 
               | Indeed, push was removed entirely!
               | https://groups.google.com/a/chromium.org/g/blink-
               | dev/c/K3rYL... Except it's still the core backend for
               | Push API. Alas, fetch, in spite of many years of asking
               | for it, never got the ability to observe a Push request,
               | so devs literally never had a chance to explore the
               | possible content update/content discovery use cases that
               | make so so much sense in Web Push Protocol. Crying waste
               | & shame; Push had promise outside of asset delivery but
               | it never got a chance (except the deeply browser-
               | intermediated Push API).
               | 
               | There are a variety of tools & options for bundlers to
               | emit bundled esm. Which would nicely make your bundle
               | usable by multiple different consumers.
        
               | apatheticonion wrote:
               | Bundler developer here: some bundlers (like Parcel) use
               | esm imports within their generated runtime output to
               | facilitate loading dynamic bundles.
               | 
               | It's a bit simpler (and I'd assume faster) than the
               | traditional approach of dynamically creating a script tag
               | at runtime.
               | 
               | Additional features like access to import.meta lets you
               | get the path to the current script which also helps
               | bundlers with resolving the paths to dynamic imports
               | without requiring the developer to specify the base path
               | explicitly.
               | 
               | There are problems though, for example you cannot retry
               | an import() if the internet drops. The failed import is
               | cached so the browser will fail the import again on
               | retry, even if the connection is restored
               | https://github.com/fatso83/retry-dynamic-import
        
           | tqwhite wrote:
           | EXACTLY!!!
           | 
           | (Though I'd be happier with importSync() to identify the use
           | of ESM packages.)
        
             | paulddraper wrote:
             | Implementing it in require() allows a library to migrate
             | from CJS to ESM, without breaking any of its downstream
             | users.
        
           | alexose wrote:
           | That's awesome! I can't wait to try this.
           | 
           | Maybe I'm in the minority, but using NPM packages that have
           | changed over to modules continue to be one of my biggest
           | annoyances in NodeJS:                  npm install node-fetch
           | const fetch = require('node-fetch');        Error
           | [ERR_REQUIRE_ESM]: require() of ES Module              npm
           | install node-fetch@2
        
             | throwitaway1123 wrote:
             | You might just be using the node-fetch example as a stand-
             | in to make your point about esm/cjs, but the fetch api is
             | built in to Node (since v16.15) and is no longer even
             | considered experimental as of Node 21+.
             | 
             | https://nodejs.org/docs/latest-v22.x/api/globals.html#fetch
        
         | tyleo wrote:
         | By god do I agree with this. I feel like all my most diabolical
         | ESM issues are beating the tsconfig.json, webpack.js, and
         | package.json into shape to get ESM and legacy working.
        
         | TheRealPomax wrote:
         | Although on a payoff note, it's not even the shiny new thing,
         | it's almost a decade old. We really need a Python 2.7 style
         | "no: we're done with this. Don't uplift your code as much as
         | you deem necessary, but we're moving on. You've had a decade by
         | now" event for Node.
        
         | hn_throwaway_99 wrote:
         | The whole thing feels like IPv6 adoption to me: Make v2 of a
         | thing that is undeniably better, but downplay/ignore the
         | migration strategy and then just complain that people are lazy
         | if they haven't migrated yet.
        
         | cxr wrote:
         | > There's no return on investment to convert
         | 
         | Nothing except doing things the standard way so that standards-
         | compliant language implementations (and other tools) can work
         | with them instead of targetting IE^H^H NodeJS's non-standard
         | quirks.
         | 
         | > the payoff is "it's the shiny new thing"
         | 
         | NodeJS's reality distortion field has claimed another.
         | 
         | Ecmascript modules are going on 10 years old at this point.
         | (For comparison, that's more than the amount of time that
         | NodeJS existed when modules weren't a part of the language.)
        
         | akira2501 wrote:
         | > It's be synchronous and slow and ideologically impure
         | 
         | Sure. It also "just works" at the CLI. Sometimes I just want to
         | test code quickly at the CLI. I'm not into "architecting" this
         | part of my code as much as ES thinks I want to.
        
       | jeswin wrote:
       | 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 ;)
        
         | ComputerGuru wrote:
         | I feel like it's going to be an inevitable language update to
         | allow that syntax. I'm surprised TypeScript hasn't succumbed to
         | the pressure to support that syntax, but they're really strict
         | about where they allow deviations from the JS superset.
        
           | jeswin wrote:
           | > I'm surprised TypeScript hasn't succumbed to the pressure
           | to support that syntax
           | 
           | They won't do this without consensus in TC39. They shouldn't
           | either; that'd be worse than this niggle.
        
             | ComputerGuru wrote:
             | Whether they should or not and whether that would be bad or
             | not depends on how close of a relationship you believe
             | should/does exist between TypeScript and JavaScript l,
             | specifically in the TS to JS direction.
             | 
             | If I said language foo _that isn't TS_ but transpiled to JS
             | all the same was considering that syntax, people might have
             | a different opinion.
        
               | WorldMaker wrote:
               | Since Typescript 1.0 it has mostly taken the path of
               | wanting to follow TC-39's standards rather than lead
               | them. The most notable exception was an experimental flag
               | for decorators at too early of a stage that's currently
               | playing out in a compatibility war between the too many
               | projects depending on the _experimental_ flag _in
               | Production builds_ versus the actually standardized
               | behavior.
               | 
               | Between that and some remaining warts from <1.0
               | mistakes/incorrect assumptions, there's plenty of
               | evidence that it is a good thing that other than its type
               | system TS focuses on following standards rather than
               | trying to lead them.
               | 
               | There's a place for the language "foos" that want to lead
               | and champion new standards. As an ecosystem we all seem
               | to benefit from Typescript _not_ being that language
               | (anymore, mostly not since 1.0 with the few obvious
               | mistakes aside). It 's a part of what makes Typescript
               | trustworthy as Production tooling. It's also what helps
               | make Typescript mostly "cheap" and "unextraordinary" in
               | Production build pipelines.
        
           | afiori wrote:
           | It is not that big of a deal, you can write
           | import {} from "some/package"
           | 
           | And then go back with working autocompletion
        
         | fwlr wrote:
         | I think that particular issue could be solved with tooling - if
         | you can autocomplete from "package name" to a given exported
         | identifier, you must already have a mapping from "package name"
         | to "exported identifier" somewhere in your machine's memory;
         | duplicate this mapping and swap the keys for values, now
         | "exported identifier" points to "package name" as well.
         | 
         | But I do agree that it should be "from 'foo' import { ... }",
         | because then the code would look nicer.
        
           | jeswin wrote:
           | > I think that particular issue could be solved with tooling
           | - if you can autocomplete from "package name" to a given
           | exported identifier, you must already have a mapping from
           | "package name" to "exported identifier" somewhere in your
           | machine's memory; duplicate this mapping and swap the keys
           | for values, now "exported identifier" points to "package
           | name" as well.
           | 
           | Sorry I don't follow. What the "from ..." syntax does (when
           | typing it) is to narrow down 10k possibilities (the set of
           | all exported functions in all in-scope modules) down to a few
           | dozen. How would this be possible otherwise?
           | 
           | Illustration:
           | 
           | Case 1: import <just about anything is possible here - can't
           | auto suggest>
           | 
           | Case 2: from fs import <only fs functions are in scope, start
           | autosuggesting on keypress>
        
           | afiori wrote:
           | I dislike the assumption that natural languages are a good
           | base for the syntax of programming languages,
           | 
           | In my personal contrarian opinion I would have wanted
           | something along the lines of                   import "url"
           | with {namedImport}, defaultImport;
           | 
           | With other keywords like import assertion mixed at the same
           | level                   import "url" assert {type:"js"} with
           | {namedImport}, defaultImport;
           | 
           | I admit that `with` is not a great choice...
        
           | everforward wrote:
           | A core problem here is that modules are generally a unique
           | key, but exported identifiers are not. My editor does what
           | you're talking about, but can be unhelpful because if I type
           | in "create" I get 83,000 results. That would be much more
           | helpful if it were pre-filtered by module so I get 6 results
           | instead.
        
             | fwlr wrote:
             | I'm so used to fuzzy search at this point that it didn't
             | even occur to me, but yeah, you're right.
             | 
             | I guess tooling can still provide a solution - a snippet on
             | "import", where the first tab stop takes you to the module
             | path string, and the next tab stop jumps back to inside the
             | braces?
        
         | eyelidlessness wrote:
         | I tend to agree, but I've found it mostly doesn't matter as I
         | stopped typing import statements almost altogether. I type a
         | reference to the thing I want to import, in the place I want to
         | use it, choose a suggestion from the editor, and let the editor
         | write the import statement as a side effect. It only _doesn't
         | work_ when dealing with aliases, and even then only when
         | something isn't cached yet.
        
           | eddd-ddde wrote:
           | You can type the real name, import it with autocomplete, then
           | rename the symbol (f2), which creates the alias.
        
             | eyelidlessness wrote:
             | I should've been more clear that I meant import _specifier_
             | aliases. Eg in TypeScript, this is often determined by
             | `paths` in tsconfig.json. It may also be controlled by
             | `imports` in package.json, or any number of other tools and
             | configs.
        
           | paulddraper wrote:
           | That doesn't work so well for default or wildcard imports.
           | 
           | (I'd argue that default + wildcard imports are bad, but ESM
           | went out of its way to have them :shrug:)
        
             | eyelidlessness wrote:
             | It works okay for defaults IME, and yeah I generally avoid
             | both but especially namespace (wildcard) imports.
        
         | jajag wrote:
         | > But I do believe they got the syntax wrong - should have been
         | "from fs import { readFile }" so that auto-complete works.
         | 
         | Personally, I prefer the "import x from y" format because it
         | makes it easier to visually scan where an import is coming
         | from; fair point about auto-complete though.
        
         | tqwhite wrote:
         | Really? I have a project that loads modules based on calculated
         | values. How will you do that in a pure ESM world?
        
           | zarathustreal wrote:
           | You wouldn't, because it's a misunderstanding of what
           | "module" means and how they work. It's like saying "maybe I
           | need this file" - there is no maybe, you either need it (to
           | run conditional logic upon) or you don't.
           | 
           | You get an approximation of conditionally loading a module by
           | simply converting everything to ESM and enabling tree-
           | shaking. When module loading has no side effects this is
           | simple to do. If you're unsure at build time whether you will
           | call a certain function from a certain module and that's the
           | reason you're conditionally loading it, again enable ESM and
           | tree shaking and import the function and call it
           | conditionally except do so at runtime. You'll only get
           | exactly what you need to avoid the bloat of the whole module
           | and your dependency graph will also be more correct as a
           | bonus!
        
             | tqwhite wrote:
             | You are simply wrong.
             | 
             | I've been a full time NodeJS programmer for fourteen years.
             | Module isn't some pure theoretical concept. It is a file
             | that exports something in Node.
             | 
             | There's a ton of 'maybe I need this file' in the world. For
             | example, I have things that are polymorphic by instance. I
             | grab a config entry to decide which of several modules are
             | going to be used. The others are completely unnecessary.
             | 
             | You might say, just add a build step that chooses the right
             | ones. To which I would say, Are you nuts? Why would I screw
             | up a perfectly working paradigm?
             | 
             | To get "an _approximation_ of conditionally loading ".
        
           | recursive wrote:
           | Using dynamic import. Here's some documentation to get you
           | started.
           | 
           | https://developer.mozilla.org/en-
           | US/docs/Web/JavaScript/Refe...
        
             | tqwhite wrote:
             | Dynamic import() is asynchronous. I have things that are
             | not asynchronous.
             | 
             | To rewrite to be asynchronous gets me exactly _nothing_.
             | 
             | In work that is asynchronous, I use import(). It's fine.
             | Also, it gives me nothing but, since that particular thing
             | is already async, why not?
             | 
             | This is a terrible, badly thought out thing that was done
             | by ECMA that harms a ton of developers and that would have
             | been entirely saved if somebody had asked me.
             | 
             | I would have said, add importSync() and there will be
             | literally no problems ever again.
        
         | wvenable wrote:
         | I've been newly doing a lot more front-end development and I've
         | been sort of impressed by the autocomplete. You start typing
         | the name you want to import and it autocompletes the name _and_
         | module that it comes from. That actually seems more useful to
         | me.
        
           | MatthiasPortzel wrote:
           | Yep. Especially with relative imports, it's easier to type
           | `import { myHelperFunc` and let LSP complete `tion } from
           | "../../../util"`.
        
         | samth wrote:
         | We considered that syntax, but `from` was not a reserved
         | keyword already, whereas `import` was, so the parsing situation
         | with the actual syntax was much better.
        
           | cxr wrote:
           | import "./foo_bar.js" (for FooBar)
        
         | danvk wrote:
         | You can work around this by typing your import statement
         | inside-out:
         | 
         | import {} from 'fs';
         | 
         | Then move your cursor back inside the {} and you'll have nice
         | autocomplete. Works with object destructuring, too.
        
         | akira2501 wrote:
         | They've made zero functional difference to me. What do you like
         | about them?
        
       | righthand wrote:
       | 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.
        
         | rty32 wrote:
         | Well, to begin with, they are NOT compatible, in the general
         | sense. What you perceive to be compatible works because of tons
         | of (often dirty and ugly) hacks people put together, with many
         | issues. (Hint: top-level await). Do your research.
        
           | righthand wrote:
           | Hence the "enough" modifier. NodeJS isnt a browser framework,
           | do your research.
        
         | tqwhite wrote:
         | I could not agree more. In fact, the introduction of ESM has
         | been entirely pernicious, causing more problems, not fewer.
         | 
         | Why? Because there is no importSync(). If that existed, it
         | would be easy to interoperate.
        
           | tracker1 wrote:
           | I think it would have been more prudent if Node had chosen to
           | stay closer to Babel compatibility in terms of how it handled
           | ESM + Require. I know there were reasons to break things...
           | but it could have been smoother.
        
             | tqwhite wrote:
             | I don't use Babel so I don't know what that means but I do
             | know that I would not be rage-typing if they had simply
             | made importSync().
        
       | lenerdenator wrote:
       | Surely, this will be the thing tacked onto JavaScript that will
       | make it easy to scale and reduce toolchain complexity......
        
       | fwlr wrote:
       | 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.
        
         | postepowanieadm wrote:
         | But why do you want to break half of a working solution?
        
           | tracker1 wrote:
           | It's closer to how Babel worked out of the box for half a
           | decade before Node added their implementation. It's Node that
           | broke a half-working solution.
        
           | fwlr wrote:
           | In fairness - given a choice and some time to think, I would
           | probably not choose to actively break commonjs. However, if I
           | was tasked with increasing ESM adoption, I would go about it
           | like this.
        
       | montroser wrote:
       | 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.
        
         | Me1000 wrote:
         | "Just" is doing a lot of heavy lifting here. It's so
         | frustrating watching people think it's just because a bunch of
         | smart and hard working people are either lazy or stubborn.
        
           | mardifoufs wrote:
           | I'm completely clueless w.r.t js modules, but I'm wondering
           | how did Bun manage to do it? Does it work well?
        
             | vlakreeh wrote:
             | It works great for 90% of use cases, but getting that last
             | 10% to work is really really hard so Bun (and node 22 which
             | supports the same thing with an experimental) just throws
             | an error in those cases. The most notable thing is
             | `require`-ing an async ESM module from CJS, because require
             | is a synchronous call you cant just async-ify it trivially.
        
       | preya2k wrote:
       | 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
        
         | tqwhite wrote:
         | And, if you read that issue, you will see that they are not
         | because the only real benefit is spiritual, 'more consistent
         | with the future'.
         | 
         | Give them an importSync() and the migration can happen
         | incrementally.
        
       | ulrischa wrote:
       | 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
        
         | cxr wrote:
         | > The whole node npm ecosystemand tooling is so bad and broken.
         | No other language is so frustrating.
         | 
         | Neither Node nor NPM are languages.
         | 
         | > 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
         | 
         | Uh...?
        
       | replete wrote:
       | 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
        
         | WorldMaker wrote:
         | It's probably going to be a bandaid for a while longer, but the
         | problem is "mixed module loading" and we should fix _that_
         | problem rather than rely on bandaids long term. The last .cjs
         | file I 've needed for a while now in type="module" libraries
         | has been for eslint config files and eslint finally supports
         | ESM configs. Everything is just .js, as it should be.
         | 
         | I agree with the article that type="module" should be the
         | default and once it is the well established default the bandaid
         | of .mjs, .cjs, et al extensions should probably provoke a
         | deprecation warning rather than being another long-term tech
         | debt part of Node.
        
       | jakubmazanec wrote:
       | 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...
        
         | simlevesque wrote:
         | People never wanna work or learn. It's not even that big a pill
         | to swallow.
        
       | plopz wrote:
       | not being able to mock es modules in tests is a real pain
        
       | o11c wrote:
       | 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.
        
         | norman784 wrote:
         | I would argue that polyfills are not needed anymore, you are
         | safe using ES2022 or even ES2023.
        
           | tracker1 wrote:
           | Mostly agree with the above, outside some ES3-ish scripting
           | environments (Adobe and others), polyfills for a lot of
           | functionality isn't needed strictly for JS support. And even
           | then, can still be part of bundling or shimmed outside your
           | application script(s).
           | 
           | And if you're bundling, then you can add them into the
           | process. I've been avoiding most things that could require a
           | polyfill since 2018 or so anyway as green browsers are pretty
           | feature complete. As much as I'd like the F# style pipelines,
           | and there are a couple other niceties, I don't miss much.
        
           | Sephr wrote:
           | Polyfills are often necessary because new features are still
           | added to the standard library, and runtimes all have varying
           | levels of support for new features.
        
           | dbalatero wrote:
           | False, I just added one the other day for the scheduler API.
        
       | TheRealPomax wrote:
       | 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")
        
       | pictur wrote:
       | 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
        
       | h1fra wrote:
       | The fact that `npm init` still not default to `type: module` is
       | baffling
        
       | meego wrote:
       | 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
        
       | 999900000999 wrote:
       | 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.
        
         | paulddraper wrote:
         | Isn't the problem that ESM is proving almost too much of a
         | reset?
         | 
         | I'm not sure I understand what you're going for.
        
       | PaulHoule wrote:
       | 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.
        
       | apitman wrote:
       | 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
        
         | noiv wrote:
         | That's when I started vite first time. I think it's the build
         | tool closest to no build tool.
        
       | tobyhinloopen wrote:
       | 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.
        
         | 123yawaworht456 wrote:
         | old thing bad
         | 
         | new thing good
        
       | zazaulola wrote:
       | 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?
        
       ___________________________________________________________________
       (page generated 2024-06-20 23:01 UTC)