The Node ecosystem still has tooling problems
maxleiter.com
maxleiter.com
There’s just so much shit. Everyone made their own system. There’s .js .ts .mjs .cjs extensions. Theres’s tsc and jest and npx and create-react-app. These are just the tip of the iceberg. If I try to update the build system to use newer versions of the software, all sorts of stuff will break. The really shocking part, for me, is that I feel like it’s easier to set up my build system for C than for JS.
This was a product the company I was working for inherited from a merger. They bought the company for this product.
It was a nightmare of bad software practices. Still using Gulp in 2020 was only the tip of the iceberg.
There is value in an ecosystem that lets you do it "your way," rather than enforcing convention. It's not for everybody though.
I don't buy the argument that the existence of separate binaries for the typescript compiler, test runner, packaging system, etc. is somehow unbearably confusing, I would almost prefer that over certain other languages where one magic command does it all. Although if you like that, you could try `bun`.
The language contains so many lurking horrors, accreted over the years, that it might even seem irrational to assume otherwise.
I suspect this sense of ephemerality then pervades the entire extended ecosystem, including all JS derivatives, reducing everyone's time horizon to maybe the next eighteen months at best. Thus the roulette wheel of broken tools keeps spinning.
If you have a team or teams of engineers, having one or two people deal with all the dev-ops stuff makes a lot of problems go away.
But if you have a large C++ project for example, you probably need more than a couple people focusing on build and target dev-ops work, or at least a lot more of their time.
It’s a lot easier to get a frontend person to help out with the backend dev-ops than it is to hire a new C++ guru and wait a bunch of time to catch up on the nuances of your build systems/org/whatever.
Anecdotally, I see the people who balk at Node are usually enterprise Java devs, backend Python devs, or junior Go/Rust enthusiasts.
At the end of the day, all these languages can interoperate with all the others in a bunch of different ways, and an organization’s ability to engineer and maintain systems is mostly orthogonal to its choices of “driver” technologies.
> At the end of the day, all these languages can interoperate with all the others in a bunch of different ways, and an organization’s ability to engineer and maintain systems is mostly orthogonal to its choices of “driver” technologies.
I think people say that in an interest to keep the peace, but the assertion doesn't stand up to close scrutiny. Poor technological choices kill companies, or at the very least, make them perform more poorly. Choosing the right technology is a core skill for technology companies.
The problem is that each company is a goddamn unique snowflake. Company X has a bunch of front-end developers and spends most of their money on headcount. Company Y has a bunch of back-end developers and spends most of their money on infrastructure. The "best language for a project could be R, Python, Go, Rust, C++, TypeScript, C#, Java, or something else. Picking the wrong language can sometimes be outright disastrous compared to picking a good language. But most of the time, there's no clear "best" language.
Even though there's no clear "best" language, these people balking at Node may have a point.
Aside: any shop operating under the assumption that devops is a function you assign to someone, has already failed devops 101.
Unfortunately a proven playbook for struggling devops teams is to just fire all the devops and infra folks, which seems to help with platform stability, recruiting, and velocity year over year.
Any reference to “devops team” is also automatically failing at devops. It’s not a job, a task, or a team. I don’t spare much time for folks encumbered by a silo mindset. It’s the antithesis of a service/product-team approach, and (to the actual point) does nothing to oppose the myopia I’m accusing the JS ecosystem of.
TypeScript (tsc) should display a hide-able message on invocation that states: "TypeScript isn't straightforward. It's a vast ecosystem all its own that accommodates several million developer's individual needs. It can be overwhelming. You don't have to use it."
I won't opine on the dumpster fire that is ESM support in Node - that's a completely separate topic and head-through-wall session.
In comparison any frontend framework is much more difficult to learn. Typescript itself is just Javascript with types and the fancy parts of the type system are rarely ever required.
I also think there's enough resources out there for someone, who isn't in a hurry, to grok TS enough to put together a project that will compile. But skills and comprehension aren't uniform - I've seen many a junior fresh out of bootcamp look at a tsconfig.json file like it was voodoo. That's why I think it's fair to say "Hey, you don't have to use this."
The type system is super flexible and I agree it takes time to learn, but you can get a lot of value out of the basics from day one.
I've not actually tried this but I suspect even with the most lenient configuration and no type annotations you'd still get limited value over plain js through type inference and flagging of obvious bugs
It's their job to learn technology of the time and it's your job to teach them... Everything is a voodoo for fresh boys.
"I'm making progress, boss. The error output from the build is smaller than the input source code now."
The trend is the same in business. Stripe no longer has business partners; they have an “ecosystem.” The same with banks that provide wholesale banking services through a set of retail businesses - they are no longer wholesale banks but “ecosystem players”. This kind of jargon really dilutes the meaning of words and makes it hard to understand what is really meant.
Rant over, sorry.
Apart from my rant, it’s funny to see Node and JavaScript doing what almost killed Perl 20 years ago. There are so many ways of doing things, so many bespoke frameworks and packages (doing OO in Perl, anyone?), so many odd dialects that it fragmented the language and people got frustrated. The same is happening to JS right now, although with some important differences. There is hardly a fragmentation of usage via formal “dialects” in JS; rather, the problem is in the sprawl of libraries and “infrastructure” services, many of which are solved problems (e.g. Gulp reinventing what Make is really good at; Yarn reinventing what npm is supposed to do, etc). The supposed “ecosystem” is fragmenting day by day from its inherent complexity, and it’s exactly what caused web developers to flee from Perl to more simple, consistent alternatives.
Perl is a dumpster fire for real programming, that’s why it died.
I also do Typescript for a living, and on the contrary, the ecosystem (yes) keeps improving. I use Parcel 2 on my projects and it’s amazing. I’ll try Vite someday but it’s not a priority because Parcel works.
For your other examples, well yarn is less relevant today but it helped drastically improve npm.
As for Make, do you really think it’s a perfect solution? I use it but it’s syntax is opaque, it doesn’t support env files easily, it’s not even really cross platform because of GNU make/BSD make. It’s dishonest to think there’s no reason to reinvent Make
Perl was the first language I seriously learned. It wasn't really an ecosystem. More like moss slowing growing on an old tree. It was so niche as to be endemic.
In contrast, Javascript is a bustling ecosystem. It has a genome that is constantly evolving, extremely rapidly, not unlike how pop and rock music have evolved through the decades. It's very much a living, breathing system, and a fascinating case study of group dynamics and organisms trying to optimize for some local maximum while still being a part of a bigger system in the abstract.
Organic life is beautiful and messy because there was no predefined "best answer" and it's all just information vs information, algorithms and processors trying to find their place in a vast, cold world, scavenging what little energy the sun happens to shine their way. Javascript really isn't so different. It's utterly chaotic BECAUSE it's alive.
Fixed it for you.
The node ecosystem embodies mediocrity. There is no design, no testing, no stability, no benchmarks, no RFCs, no plan to produce a coherent product. Instead, you're giving a half baked set of features that are abandoned within 8-12 months. Not invented here syndrome runs wild, and over-engineering any solution is seen as a mark of accomplishment.
Simple things, like displaying static text, now require 25mb of js files for whatever framework the author is currently playing around with as a hobby. I miss the days of the web where you could just load a page in under 25kb.
[1]: https://docs.docker.com/develop/develop-images/multistage-bu...
Also you need to keep those huge images, if you want to have any reasonable caching. Otherwise builds will take forever.
Ah, yes, the old web where there was "no design, no testing, no stability, no benchmarks".
Don't get me wrong. I liked the old days when content was just HTML, but when it comes to building applications, the old ways were just terrible. You could push JS files without even checking that it's valid syntax.
There's an overabundance of interesting and great software on js, but yet we fixate on cherrypicked bad examples of things one doesn't like.
One of the things happening in that community at the moment was their second major attempt to bring the JavaScript / Typescript and Node ecosystem onboard as a semi official language. It has been a 4 year effort so far and they had to make a bunch of compromises along the way as you can see in the design section of the projects readme here https://github.com/aspect-build/rules_js
Watching the walls they would continually run into where the answer would essentially be “Node is very unlike other language runtimes” was illuminating and I suddenly started to understand why projects like Deno want to actually leave Node behind as a fundamentally unfixable mess and start again with a bit more planning this time around to avoid all of those issues.
Also, no direct DOM access. You still need a Javascript proxy for that.
The only reason I started and continue to use JS is because of TypeScript. There is no world in which I'd use pure JS over TS.
"Open source" and "proprietary" are not antonyms. Something can be both open source and proprietary, like XUL. TypeScript is one of them. (So are the NodeJS APIs, for that matter.)
If you use vanilla JS in standard modules most of this goes away.
Sure TS helps, but tests are “better”
I don't do typescript, I don't use frameworks (unless you consider express to be a framework).
I use vanilla web components on the front end, if I need reactivity and frequent re-renders I might sprinkle in a bit of lit-html, depending on the component.
Debugging and development are brain dead simple, just sticking to the standards.
I had a new developer come into my code base and he said "I couldn't believe it at first, you just write something and it does it... Wow!".
He was so used to piles of frameworks and build systems and stuff, he'd never been in a code base that just... ran.
- src/.ts: Compile with esbuild in webpack
- tests/.test.ts: Compiled with babel
- jest.config.ts: Compiled with ts-node
- webpack.config.ts: Compiled with ts-node
In an ideal world, one tool should do everything but I doubt that will ever happen
Not so long ago at $DAYJOB we even migrated a big legacy project from webpack to esbuild in no time.
Also, there's no official Vue 3 support for esbuild so that's a problem for some of my projects
Being on OSX helps a lot with the “just works” part though.
There are scaffolding tools that help configure all the JavaScript frontend stuff you need, but the problem is you run them once and you can’t ever run them again to change/add stuff.
So I built Confgen which is sort of like create-react-app except it’s idempotent:
https://github.com/erikpukinskis/confgen
It’s very alpha, but I would love to get ideas/ bug reports on GitHub.
It’s also currently Vite-only, but I’m open to a possible webpack/babel mode in the future.
As a Node.js developer myself I even noticed that some of the best solutions is nodejs plus other language.
Examples
uwebsockets.js uses some c++ code. it is faster and has better api than express, fastify, hapi, koa, and has builtin websockets support.
esbuild uses golang code. it is faster than webpack and babel for bundling and minifying javascript code.
Is it just the Node ecosystem that has these types of problems?
I think a couple of reasons for that is that it's untyped, and not compiled. Both of those mean that basic correctness checking ends up happening on the user's machine, rather than the developer's.
Ironic you say this, since the whole blogpost is complaining about setting up compiler pipeline to target NodeJS.
The issue is that Node.js source code is not compiled to a target language like native code or bytecode. As such, there's no package repository from which you can retrieve compiled packages - you're forced to deal with the same build process as the developer of the package. If that weren't the case, the compiler pipeline that the post is complaining about would be eliminated for package users.
In fact, the author of this package could have avoided some of his pain by publishing a library with the compiled JS code, which would eliminate all the config of higher layers. But the JS ecosystem doesn't support making that distinction, there's no source package repo vs. compiled package repo (afaik - I don't use it more than I have to, because it all sucks.)
> As a funny historical quirk, back in 2011 there was an interview with Ryan Dahl, the creator of NodeJS, who mentioned that the perceived difficulty in writing a new IO manager for GHC was a factor in the development of a new language called NodeJS. When asked why he chose Javascript, for the project, he replied:
>> Originally I didn’t. I had several failed private projects doing the same on C, Lua, and Haskell. Haskell is pretty ideal but I’m not smart enough to hack the GHC.
The interview itself is in [2].
[1]: https://www.stephendiehl.com/posts/decade.html [2]: https://www.bizjournals.com/boston/inno/stories/news/2011/01...
Unfortunately that left everything else up to the community to solve: establishing a “good” standard library, building, debugging, packaging, bundling, dealing with the Node/Browser duality in a meaningful way, creating usable network frameworks, UI frameworks and surely much more.
And they’ve all ended up reinventing that 100 times (like the curse of lisp) in 200 different ways, all recursively based on Node, while standing on the shoulder of non-giants trying to solve one of the other problems mentioned above, possibly standing on the shoulder of someone else who has already tried to solve what you are trying to solve now.
Calling it a clusterfuck probably isn’t sufficient, yet at the same time it seems to work, so it’s simultaneously a sort of modern day miracle.
Disclaimer: have set up quite a few node build-pipelines.
I'll speak for Maven as it's the most popular build tool and most straightforward. With gradle it would be worse.
To build two configurations you ideally want at least two modules. So multi-module projects. Weak point for maven. Doable, but with lots of quirks.
Last time I checked, to publish Java library, you would need to GPG sign it. This fact alone is a serious stuff. Pushing library to internal repository is easier.
Tooling in maven is terrible. Plugins are archaic, some of those seen last commits 10 years ago. I don't even know which tools to autoformat Java code are popular nowadays. I think that most people just use their Idea to format before commit with shared style or something like that. I think it's good enough.
Github bot to update dependencies and deploying demo site - I don't know, never did that, but I couldn't imagine it being easier with Java either.
So Java tooling has its share of quirks.
Most sane tooling I ever saw was for go, as long as you're ready to adjust your expectations and requirements to happy path.
What's unique for node is huge numbers of tooling attempts. Java has Ant, Maven, Gradle. I don't think I've ever heard about anything else. Bazel may be. Well, may be Makefiles for some old beards. JavaScript guys just can't stop trying to invent new tools. And this fragments ecosystem and user base. I don't know why is that. I've never heard of alternative Rust build system, for example.
But not for gradle.
> Last time I checked, to publish Java library, you would need to GPG sign it. This fact alone is a serious stuff
Why is it a problem? This is partly the reason why the Java ecosystem wasn’t hit by all the malicious package fiasco.
> Github bot to update dependencies and deploying demo site
Never felt a need for this, but contrary to your misrepresentation, even maven plugins have a healthy ecosystem and being part of the 3rd biggest language, I would be honestly surprised if no such plugin would exist.
Even worse, JS can actually modify itself. You can take defined functions that have definite common behavior. and overwrite them to arbitrary ones.
The equivalent to a low level language like C would be writing your code with half C, half custom macros that are #defined at random places in the code libraries that you pulled in that change core C instructions, and instead of regular C code you are concatenating strings with assembly instructions that would then be put into a file and ran.
No other language that I know of allows for this.
oh that and installing thousands of packages in the project root instead of a sensible place that could be shared per version like bundler and rubygems.
Sane package managers don't try to solve for this problem; they make it clear when you're using bad software.
> oh that and installing thousands of packages in the project root instead of a sensible place that could be shared per version like bundler and rubygems.
Look into pnpm. It does precisely this in a way that's compatible with node.
Honestly the information is out there to address most people's gripes.
Exactly, but not discoverable. I came to know of esbuild, vite, pnpm etc.. only because of reddit and HN.
Just standard stuff, nvm, nodenv, npm and npx wrapper.
To be happy with a tool like this, you need to use the vanilla output. If you need anything more you’ll be in a world of hurt. But unfortunately often real world apps begin to need something more.
Perhaps this time will be different? I hope so but I’m not optimistic.
Maybe people will discover GUIs one day, it's only been 30 years.
That has to do both with design decisions - a typed, compiled language has a big edge here - and differences in how the respective ecosystems were designed and developed.
As for GUIs, I'll paraphrase an old quote I saw on Usenet once: if you need to point at something to communicate, you're at the cognitive level of a preverbal child.
visual stuff (vs. text) is about massive parallelism and compression. see Rudy Arnheim for example. or Tufte. or video games. or excel. or a good "foreign" film. or VR once it doesn't suck.