16 October 2021

The Javascript "ecosystem" is a hot mess and so is software development in general

I have a small Vue 2 project (an admin UI for dictmaker) that I created with vue cli six months ago. Today, I picked it up again to finish it, and started out by doing a yarn upgrade. Of course, blindly upgrading all dependencies is never a good idea, but this a tiny WIP project with just one dependency that I added, and there is a constant stream of GitHub dependabot alerts every month forcing to upgrade some dependency or other, so what is the worst that could happen? At least that is what I thought.

After the upgrade, the project refused to build with the error Syntax Error: TypeError: eslint.CLIEngine is not a constructor.

Really? A syntax error in a tiny project that was building just fine before the upgrade, and that too, not in the little code I wrote, but in the tooling? Has the Javascript syntax changed completely to the point of breaking in six months despite the layers and layers of transpilation black magic that the build tools have? Do developers have to take the overhead of worrying about the numerous dependencies in the toolchain as much as their own business logic? Turns out, eslint got upgraded to v8 and it has significant breaking changes that is incompatible with projects created with versions of vue cli until whenever. I just want to work on my project and really don’t care about eslint or babel or their million dependencies, but this is a showstopper, so I start Googling.

Thanks to the pages and pages of cryptic stack traces on GitHub issues and Stackoverflow and no clear answers, it does not look it is worth trying to debug and fix the broken build system. I figure I might as well manually port it to Vue 3 (which is out now after many release candidates over many years), and it is the future of Vue. I decide to read up on Vue 3, its new composition API and differences with Vue 2. Of course, all of this because an upgrade has introduced a syntax error on a tiny project that was created just six months ago.

So, vite is the new cool tool with which you create a Vue 3 project. It is fast because it uses esbuild, a tool that is not written in Javascript, ironically.

So, I create a new Vue 3 project with vite and try to add Buefy, the UI lib I was using in the original project. I am familiar with it because the listmonk UI is written in it, and at work, we have been building large scale Vue projects since 2017. Turns out, Buefy does not support Vue 3. I read Buefy’s Vue 3 roadmap which makes it obvious that it is a no-go for now.

Fine, I decide to spend some time learning another UI framework if that means learning Vue 3, which is the future of Vue. ChakraUI is popular, so I check that out, and turns out, that also does not support Vue 3 yet. So, I stop looking for a new UI library because it is clear that the Vue 2 vs. Vue 3 split is going to be a painful fiasco with big projects not being able to rewrite everything to the new Vue 3 way of doing things for obvious reasons, including the ridiculous state of Javascript dependencies.

I decide to forget Vue 3 for now and just stick to Vue 2 + Buefy and recreate the broken project and just copy over the WIP business logic, of which, thankfully, there is little. I don’t want to revert the upgrade on the original project because an upgrade that introduced a syntax error is going to cause problems in the future also. The latest version of vue cli might have the changes to avoid this. But wait, turns out, vite does not support Vue 2!

Okay, back to the not-super-fast-esbuild vue create project. I run a yarn upgrade --all on this new project to see if that updates eslint to v8 and breaks again, and it doesn’t. Clearly, it has been fixed in vue cli (by pinning eslint permanently to v < 8?).

Of course, by this point, I have wasted hours Googling, reading, running, and copy-pasting. This ordeal comes after we recently wasted inordinate amounts at work battling with WebPack for some seemingly trivial change. The issue was such a rabbithole, I am unable to recollect and articulate what the problem was or how it began in the first place.

Really though, why should one even care about all this nonsense that practically changes month on month? How is it acceptable for frameworks, libraries, and build systems to constantly keep getting in the way of actually writing business logic, the whole point of writing software. I genuinely wonder how people keep track of the incessant barrage of Javascript frameworks, frameworks on top of frameworks, build and dev tools, a maze of technologies that compete, conflate, and conflict with each other in impossible ways. How much cognitive bandwidth is required to understand all this?

I don’t mind Vue, really. I don’t mind Javascript either. It is a language with warts (albeit more than its counterparts) like any other language. I have been writing Javascript since 2001, so I have some context on “vanilla”, jQuery, frameworks, and the pre and post build era. While it is a cliché today to say that the Javascript ecosystem is a mess, it, and the culture that enables it, objectively, are a super hot mess. I wrote PHP for many years and it was messy. Python 2 vs. 3 was messy. I wrote many messy things in many messy languages and frameworks for many years. I cannot recollect any language’s ecosystem getting “modernized” like this, becoming this comically complicated that one might think it’s parody. Of course, the symptoms were evident with left-pad.

That people find this level of ludicrous confusion and complexity acceptable is mind blowing. And, to think that there is a whole generation of developers to whom this is the baseline of writing software, who think that this is normal, is genuinely painful. That there are people who knowingly perpetuate such complexity in software development in general, is painful. That reminds me of a developer that I spoke to who only knew how to deploy a static website via a “CI/CD” system connected to a K8s cluster. They did not know that it was possible to cp or rsync an index.html file to a directory on a Linux system running a web server. They were unable to even visualize that fundamental concept because CI/CD and K8s was their baseline.

Maybe a bit dramatically, one is forced to think that all of this complexity, bloat, and hot new bloat to fix previous bloat, is a net loss for humanity. If quantified, the cost in terms of time, effort, energy, and money must be enormous. What a collective, mammoth exercise in intellectual dishonesty. What a monumental waste.

/ End of rant.

Update (17 Oct 2021): So, I started porting the tiny project to the fresh Vue 2 project created with vue cli and installed sass-loader (the defacto Javascript Sass lib) to customize a couple Buefy UI CSS variables. Oops: Syntax Error: TypeError: this.getOptions is not a function. Turns out, sass-loader stopped working with Vue 2 at v10 because subsequent versions require WebPack 5, which Vue 2 apps created with vue cli do not support. However, vue cli v5 will have support for WebPack 5. But, it will have an option to downgrade to WebPack 4 because unlike sass-loader, many other libs would not have support for WebPack 5.

The fix for sass-loader to work with Vue 2 for now is permanently pin it to v10.1.1. That is, a CSS lib is so tightly coupled with the build toolchain that it breaks the toolchain, and that is just one lib. The graph: Vue 2 ↔ Vue 3 ↔ vite ↔ vue cli 4 ↔ vue cli 5 ↔ WebPack 4 ↔ WebPack 5 ↔ sass-loader 10 ↔ sass-loader 12 ↔ ∞ dependencies.

So, I pin sass-loader to v10.1.1 and that throws: Syntax Error: Error: PostCSS received undefined instead of CSS string. A bit of Googling, and it turns out, if sass-loader is being used with WebPack, the sass lib has to be installed manually …

The app compiles.

Edited: 17 Oct 2021