A recurring question from some htmx contributors is why htmx isn’t written in TypeScript, or, for that matter, why htmx lacks any build step at all. The full htmx source is a single 3,500-line JavaScript file; if you want to contribute to htmx, you do so by modifying the htmx.js
file, the same file that gets sent to browsers in production, give or take minification and compression.
I do not speak for the htmx project, but I have made a few nontrivial contributions to it, and have been a vocal advocate for retaining this no-build setup every time the issue has arisen. From my perspective, here’s why htmx does not have a build step.
🔗Write Once, Run Forever
The best reason to write a library in plain JavaScript is that it lasts forever. This is arguably JavaScript’s single most underrated feature. While I’m sure there are some corner cases, JavaScript from 1999 that ran in Netscape Navigator will run unaltered, alongside modern code, in Google Chrome downloaded yesterday. That is true for very few programming environments. It’s certainly not true for Python, or Java, or C, which all have versioning mechanisms where opting for new language features will force you off of deprecated APIs.
Of course, most people’s experience with JavaScript is that it ages like milk. Reopen a node repository after 3 months and you’ll find that your project is mired in a flurry of security warnings, backwards-incompatible library “upgrades,” and a frontend framework whose cultural peak was the exact moment you started the project and is now widely considered tech debt. Who’s to blame for this situation is for someone else to decide, but, in any case, you can eliminate this entire problem class by not having any dependencies beyond the JavaScript runtime.
A popular way to write JavaScript today is compile it from TypeScript (which I will use frequently as an example, because TypeScript is probably the best reason to use a build system). TypeScript does not run natively in web browsers, so TypeScript code is not protected by ECMA’s fanatical devotion to backwards compatibility. Like any dependency, new major TypeScript versions are not guaranteed to be backwards compatible with the previous ones. They might be! But if they aren’t, then you need to do maintenance if you want to use the modern development toolchain.
Maintenance is a cost paid for with labor, and open-source codebases are the projects that can least afford to pay it. Opting not to use a build step drastically minimizes the labor required to keep htmx up-to-date. This experience has been borne out by intercooler.js, the predecessor to htmx which is maintained indefinitely with (as I understand) very little effort. When htmx 1.0 was released, TypeScript was at version 4.1; when intercooler.js was released, TypeScript was pre-1.0. Would code written in those TypeScript versions compile unmodified in today’s TypeScript compiler (version 5.1 at the time of writing)? Maybe, maybe not.
But htmx is written in JavaScript, with no dependencies, so it will run unmodified for as long as web browsers remain relevant. Let the browser vendors do the hard work for you.
🔗Developer Experience
It is true that the TypeScript developer experience (DX) is better than the JavaScript developer experience in many respects. It is not true that the TypeScript DX is better in every respect, and the tendency of software engineers to view progress as a teleology of capability rather than choices with tradeoffs sometimes blinds them to the cost paid for the DX aspects they like. For instance, a small tradeoff you ma