5 ms·
I disagree. What we gained is a native module system that works the same everywhere (Nodejs, browsers, deno, Bun) vs CommonJS which was really only built for N
by alexghr 3y ago
I disagree.
What we gained is a native module system that works the same everywhere (Nodejs, browsers, deno, Bun) vs CommonJS which was really only built for Nodejs (with compatibility layers for others).
We have a specification for this system and any changes done to it have to follow the same process as any other change done to the language (for better or worse).
We have top-level async support that works across import boundaries. This is less useful on the server, but in the browser? With just a `import thing from "https://example.com/foo.js https://example.com/foo.js"` I get a fully intialised library even if does async requests as part of its initialisation.
What we lost is just this
```
const someInitializedModule = require("module-name")(someOptions);
```
The `app.use()` example can be replicated with an async `import()`. Maybe it's not as elegant as before.
There's going to be a lot pain of transitioning a big ecosystem like Javascript's to ESM but is that really a reason to not evolve the language?
- laurent123456 3y ago> With just a `import thing from "https://example.com/foo.js https://example.com/foo.js"` I get a fully intialised library even if does async requests as part of its initialisation. This is indeed convenient if you want to quickly try a lib. However, what happens in a larger project with dozens of dependencies? Those http requests will get inefficient soon, and you'll be back having to compile everything with Babel or similar.
- alexghr 3y agoI agree, bundling isn't going anywhere for sure, but the web isn't all single-page-apps built with perfect engineering and top-notch frameworks. Plenty of websites are just server-side rendered and just need to sprinkle some client side JS. For them it's perfect to be able to drop in a script and not have to worry about bundling or polluting the `window` object while loading external scripts.
- nesarkvechnep 3y agoEven if we take only the part of the web which is SPAs, 0.1% are well engineered.
- Waterluvian 3y agoIf I’m serious about shipping some production app/page, I want complete control over all of this anyways. I never want to require/import an entire .min.js file. I want to tree shake the 15% of it I need.
- baq 3y agoWhy though? The min.js will be cached if it’s a popular library. Your bundling might as well reduce overall performance.
- ehnto 3y agoThis is a myth in production environments I feel. It's a security risk to import the library on the fly from a source you don't control, and the caching is per user, so you are banking on each specific user having visited a site that happens to have the same version of some library you use from the same domain that you included it from, so that it's cached. You're also now fighting for response time and bandwidth from a public resource you don't control. You are beholden to their traffic spikes, their downtime and their security incidents. Just send it from your servers, or your edge nodes. They already have the DNS hit cached, they are already getting everything else from there. Chances are high you're sending image data that far exceeds the JS library anyway. This is especially prudent if you serve users in your own country, and that country isn't the US. Chances are very high your site's largest response delays are US CDN resources if you use them.
- WorldMaker 3y agoPrivacy concerns led to browsers caching per-user and per-site, so there is even less advantage to "shared CDNs" in 2023's browsers. That said, tree-shaking can sometimes be a premature optimization if your site isn't a SPA with a comprehensive view of its tree to shake. Some MPA designs may still benefit from caching the whole ESM .min.js of a site-wide dependency and letting the browser tree-shake at runtime.
- e12e 3y ago> The min.js will be cached if it’s a popular library. No, it won't any more: https://www.stefanjudis.com/notes/say-goodbye-to-resource-caching-across-sites-and-domains/ https://www.stefanjudis.com/notes/say-goodbye-to-resource-ca...
- lelanthran 3y agoNot every project has dozens of dependencies. Standardised functionality, in this case, is better than needing tooling.
- jarym 3y agoI also disagree with the article, I happen to find ESM modules very useful and although I've had to work around some of the ways I would have previously done things, mostly they weren't good best-practices in the first place.
- jamal-kumar 3y agoReally? I remember using the commonjs module pattern even before nodejs. It basically just felt like it was a way to write javascript to a standard of quality more than anything in those times. Lots of closure enforcement, and everything wrapped in a top-level function - The module imports were just a side effect. "require" is just a top-level first-class function call. I believe I was using it to build crossplatform mobile applications at one point, and there was absolutely no nodejs involved in that. All of that said I'm super happy I moved away from mobile/frontend into backend. Way less annoyances.
- alexghr 3y agoMy bad, my past experience/bias got the better of me here. I only got exposed to CommonJS as a part of Nodejs but it does look like CommonJS was started independently of Node.
- vmfunction 3y agoyes, RingoJS is also using CommonJS, but yeah CommonJS was mainly for Node. However, now we have standard from import that is part of ES standard. Would rather be using that now that most runtime and browser has implemented it.
- vmfunction 3y ago>What we lost is just this >``` const someInitializedModule = require("module-name")(someOptions); ``` That can partially be done such as: import {jason} from 'https://example.com/foo.js?name=jason https://example.com/foo.js?name=jason On the script site use: const url = new URL(import.meta.url); console.log(`${url.searchParams.get("name")`);
- azangru 3y agoHe isn't talking about named exports; he is talking about immediate invocation of the imported module. require("module-name")(someOptions) is instead represented as import { someModule as someModuleFactory } from 'module-name'; const someInitializedModule = someModuleFactory(someOptions);
- WorldMaker 3y agoThe most direct translation is something like: (await import("module-name")).default(someOptions) The biggest issue is import() is async and module proxies aren't allowed to be directly callable so you need to pick an export from the other module to call. But `default` is an appropriate export to call, even if there's no nice shorthand for default imports in the import() case (as there is syntax sugar in the import keyword case for default). Neither of those things seem like deal breakers to me, and have very good reasons for why they are the way they are.