7 ms·
I feel like es modules have killed javascript. They have enough momentum that everything supports them (or needs to support them). But they’re not good enough,
by josephg 4y ago
I feel like es modules have killed javascript. They have enough momentum that everything supports them (or needs to support them). But they’re not good enough, or compatible enough to actually integrate well.
Recent example: bundler X insists on import statements including file extensions. But the typescript compiler refuses to let you import foo.js and won’t rewrite an import of foo.ts to foo.js when you build. There’s giant GitHub issues about this but nobody wants to fix it on their end. In short, everything is awful.
Writing javascript in the browser used to be just the same as nodejs, with the exception that you needed a bundler like browserify - which mostly just concatenated everything together. Now I dread setting up new projects. Will typescript work with svelte? Will this webassembly module work with rollupjs? Will it pull in my type definitions correctly? Will the url path system magically work or break? Urgh.
I feel like I’m no longer competent enough to get arbitrary tools working properly together. We need bespoke build systems now because it seems like they’re the only thing that works any more. And that means I can’t throw together a simple server side rendering system like I used to be able to do.
Bryan Cantrill once joked that javascript was the failed state of programming languages. That doesn’t feel like much of a joke any more.
- RedShift1 4y agoI once set out a simple goal, instead of shipping a production Node package with all the js files and node_modules, just have it all in one js file that can be executed by Node. After trying several compilers and messing with their settings, I ultimately failed exactly because of the different ways to import/export modules. My own code was all esm with .mjs files, but many npm libraries aren't so basically you're stuck.
- fragile_frogs 4y agohttps://github.com/vercel/ncc https://github.com/vercel/ncc
- RedShift1 4y agoTried that one too, failed me as well and I recall correctly due to a different reason. However I see there have been new releases, maybe it's time to try again.
- eurasiantiger 4y agoYou don’t need bundlers or build systems. ES modules work in all modern browsers without any build tooling, imports and all. HTTP/2 mitigates the TCP overhead. You can have an unbundled, unminified web app load quicker than the average bundled and minified React app. Best of all, you can’t use NPM modules so your codebase can stay ultra-clean!
- josephg 4y agoSure, but I can’t run the same code in nodejs for server side rendering. And wasn’t server push for HTTP/2 removed by web browsers? If the browser needs to do a round-trip to the server to fetch every individual javascript file (and it doesn’t even know which files it needs up front) then the result will be way slower than a bundler. I would expect performance to get worse, not better using this approach.
- cityzen 4y agoI don’t get the need to use js for SSR? Why not PHP/Go/Python/Ruby… ?
- danielheath 4y agoIf you use react to create the DOM, you can do SSR in nodejs to re-use the same code. Not clear to me that the added complexity is worth it personally.
- zelphirkalt 4y agoAlso this re-use tricks people into tightly coupling frontend view logic with backend logic, making a mess of everything.
- eurasiantiger 4y agoNo it doesn’t. SSR is typically just a way to pre-render the client app into (critical) static assets that can be delivered to the browser quickly, so it can display at least some content before the client app loads, runs and ”hydrates” the server-generated HTML back into the exactly same interactive app (e.g. a React app) that was used to generate the SSR assets.
- wereHamster 4y ago> Recent example: bundler X insists on import statements including file extensions. But the typescript compiler refuses to let you import foo.js and won’t rewrite an import of foo.ts to foo.js when you build. There’s giant GitHub issues about this but nobody wants to fix it on their end. In short, everything is awful. That's wrong. The latest TS version allows you to import .js files with extensions just fine! In fact, one of their recommendations is that you write the your JavaScript code as you would if they were intended for a browser (which doesn't automatically append any file extension, doesn't support importing directories by appending /index.js, only supports file-relative or absolute imports (outside of import maps) etc).
- josephg 4y agoI wanted to import a typescript file from another typescript file. If I made my import line be “import .. from ‘./foo.ts’” then typescript was happy, but the compiled output still specifies .ts rather than .js. So the import was broken (that file didn’t exist in tsc’s output directory). My other option was to “import .. from ‘./foo’”. Then typescript worked but the bundler I was using refused to import the file at all - since it was missing an extension in the import statement. And apparently extensions are technically required by the spec. The real solution would be for the typescript compiler to rewrite import statements. Like, import foo.ts should be rewritten to import foo.js. There’s a GitHub issue talking about this[1] that was closed because the typescript authors think this is someone else’s problem. I ended up just giving up and trying a different bundler - which had equally different, but equally frustrating problems. The ecosystem is a disaster. [1] https://github.com/microsoft/TypeScript/issues/40878 https://github.com/microsoft/TypeScript/issues/40878
- wereHamster 4y ago“import .. from './foo.js'” TypeScript doesn't rewrite (that part of) your code (it downcompiles ES features if necessary, but won't rewrite import specifiers). Write import specifiers as you would in regular JS code intended for the browser (ie. relative or absolute paths, including file extension, no directory imports, …). > […] but the bundler I was using […] Trying to write code that's understood by both bundlers AND produces working output when processed directly by TypeScript is a bit too much to ask at this time. Maybe we'll get there, eventually, but unless it's plain ES2022 code (intended directly for browsers, not targeting bundlers or TS or test runners etc) you have to write the code with a specific intent.
- zelphirkalt 4y agoThe thing you described about tsc not liking file endings ... I wasted a whole free day on this and my whole motivation for a side project. How the f is tsc not able to output whatever module for.at I need in 202X??? And that means you need an extra tool to do the job. Good luck setting up shitty bundlers for another whole day, until you finally get a simple output directory with normal JS file, one per ts file and simply deliverable to the browser. It is such a PITA. It makes me question whether all the type safety of TS is actually worth the trouble. Once I start writing plain JS, I slowly but surely get the feeling of that project being lost, unless I use a proper programming lang and output to JS. Maybe one of these days I will learn Clojure or something. All just because the JS ecosystem of tools sucks so much. And this is what people put up with all day long. How have we strayed so nuch from the path?
- wonderbore 4y agoYou see, it's not that ESM killed JavaScript, all the hacky build tools did. ESM was in the pipeline for an eternity and everyone took their sweet time to support it. You can use ESM without issue in browsers, Node and using proper ESM bundlers like Rollup, as long as you don't expect `import 'a/b'` to arbitrarily load `./node_modules/a/b.js` or `./node_modules/a/b/index.js` npm also keeps actively harming the community by not validating packages in any ways whatsoever, so everyone keeps pushing broken crap into the ecosystem.
- josephg 4y agoMaybe the right way to think about it is that ESM is python3 for the javascript world. If javascript had ESM from the start, it would be fine. And maybe once every package in npm is rewritten for ESM, it'll be fine. But in the meantime, we have essentially 2 mutually (sort of) incompatible programming languages which share a name and a package repository. > You see, it's not that ESM killed JavaScript, all the hacky build tools did. The problem is that ESM added a massive extra amount of complexity to all those hacky build tools, because suddenly we have 2 different kinds of javascript code and people expect their code to be mutually compatible. That is really complex. - Typescript's canonical way to import things (import foo from './blah') is incompatible with ESM imports (because imports must have file extensions). - Nodejs has a plethora of options to configure packages to support combinations of ESM and CJS[1]. Half of those options are deprecated. Lots of tools read package.json - but don't parse all those different options consistently with nodejs's implementation. - Eg: wasm-pack only knows how to compile code "for the web" or "for nodejs". (You want a package that works everywhere? Adorable.) The web version creates an ESM module, but doesn't specify "type": "module" in package.json - so even though it could work with nodejs, it doesn't. - Lots of packages in npm are broken in either CJS or ESM mode. And there's no way to tell without trying them. Essentially, we went from having a simple, extensible system (commonjs + bundlers) to a very complex system. The number of people who understand all that complexity has dropped by orders of magnitude. Now I feel less capable of creating working code than I was a few years ago. Its an unmitigated disaster for the ecosystem. Maybe in a few years, everything will be using ESM. But until then, I want off this ship. [1] https://nodejs.org/dist/latest-v18.x/docs/api/packages.html#determining-module-system https://nodejs.org/dist/latest-v18.x/docs/api/packages.html#...