Updated stack, but only temporary…
What I learned about the website ecosystem and myself.
Shortly after I went on hiatus, I went down a rabbit hole trying to find my future stack for creating websites, incorporating the things I learned in the meantime. I could have simply gone for some hosted service, like Squarespace or hosted Ghost, which be some metrics would have been the better option. One of the goals, however, was to own and run the stack myself.
I still looked at the services whether they can provide some form of temporary solution, but they usually failed at some pretty basic requirements, which I wasn’t willing to skip on – at least not as much as they would have required me to do.
So for now, I’m still with Eleventy, updated to 3.0.0, on a clean project. Whether I will continue to tweak it to do my bidding or move somewhere else, still remains to be seen. I spent most of my time during evaluation with Astro, which I liked for different reasons, but ultimately ran into some issues that were just too frustrating and even those crazy LLMs couldn’t help with.
The stuff I looked at:
- Eleventy, as it was my starting point, version 3.0 exclusively
- Astro, incl. 5.0
- Next.js, SvelteKit and Nuxt (although by the time I reached Nuxt, I was a bit tired already)
- Ghost. Yes, at one point I was like screw it, if it works, why bother with the others
In the end, none of them could satisfy my needs fully and provided quite a few frustrations with the overall JavaScript ecosystem along the way. Here is what I learned.
Markdoc is the future, but not here yet
There is basically just one implementation and it has some caveats. Integrating it into the various frameworks is painful and even with Astro, which has an official integration, you will hit bumps in the road.
One source of frustration was footnotes. The recommend against using the commonly used Markdown formatting, but do not provide an out of the box solution for the recommended way (defining a custom tag). The problem with this is such a tag is not easy to get right. Most examples you can find are pretty basic forms of “take this block delimited by tags, process it and replace the block including the tags with the result and move on”, but footnotes need to remember some stuff along the way. To this day, I’m not even sure if the default library API allows for this kind of processing.
Anyways, the good thing is, it motivated me to start working on an alternative implementation. I’m still prototyping it, but as soon as it becomes somewhat useable, I will release it as MIT.
The JavaScrip-TypeScript divide
As mentioned in other places, I’m agnostic to the static vs. dynamic typing debate, preferring gradual typing myself. The problem with statically typed languages, if the type system is not allowing for some simple escape hatch, it makes them almost unusable for exploratory programming.
In the ecosystem of JavaScript and TypeScript there is some divide at the moment which makes the development experience pretty rough. Unfortunately you can’t have a balanced discussion without taking the wrath of either side, mostly from the hardcore TypeScript folks.
There is also this implicit push towards TypeScript within many projects these days, which almost boils down to “if you’re serious about development, use TypeScript”. It rubs me the wrong way a lot more than any of the DX issues.
Unfortunately you can’t really enjoy Vanilla JavaScript development anymore, unless you’re willing to forgo on many useful libraries. Remember, I don’t do JavaScript/TypeScript full-time, but it seems like you have to in order to navigate all these paper cuts. Also, I do develop in other statically typed languages, mostly Swift, but also some Go and Rust, but neither of them is giving me the same level of grief and frustration as TypeScript for some reason.
JavaScript Tooling divide
This is a double edged sword. On the one hand the fragmentation ensures some levels of innovation of the DX, but it makes part-time development harder than it needs to be. At this point you can spend 4 weeks in the ecosystem and see documentation preferring one of the following:
- Node.js and npm (the de-facto standard)
- Use pnpm instead of npm (which will be harder to setup in the future)
- Use yarn instead of npm (same here, but yarn seems to lose some support in the community)
- Bun
- Deno
You’re constantly translating instructions in your head if the documentation doesn’t include one of the options, when it comes to package managers.
When it comes to Bun and Deno, you have the added challenge that some packages (or parts of it) simply expect Node.js and compatibility is not quite there yet. Allegedly Deno 2.0 improves on that, but I have no first-hand experience.
“Full-stack frontend” in JS makes sense
Contradiction? No. It’s the nature of the technology, unless you go SPA+API all the time, which doesn’t always give the nicest user experience, whether you like it or not.
Massively simplified, we’re currently seeing two developments:
- Backends are returning to send HTML over the wire instead of only JSON data. Now with thin JS layers that make lightweight interactions easier without going full React, Svelte or what have you.
- Frontends gain functionality via their meta-frameworks that was usually restricted to backends, like Django, Rails and so forth.
Those meta-frameworks, like Astro, Next.js, Sveltekit and so forth, will gain a better DX over time to control what happens on the server, on the client, or ahead of time, to improve the user experience massively. At least it seems so.
Not enough good practices output by default
It’s still too opaque in many cases, how to get an output to the browser that truly adheres to current good practices. Since this is a moving target, all these frameworks should do a better job to guide the developer what they should do to improve. It’s not just (technical) SEO or media handling, mind you, but for more content heavy site they still lack a lot:
- Accessibility: this is the biggest ask, since some of it needs to happens outside of the scope of these frameworks. Still a bit more guidance would be appreciated.
- Meta data: I wish every framework would come with some better guides how to handle the various meta data annotations. It’s basically copying from other projects.
- RSS and sitemaps: I noticed this during an excursion gathering the RSS feeds from a list of note-worthy personal homepages. It didn’t really matter what tech stack was used, but about 10-15% had some horrible misconfiguration, including some having simply the wrong URLs in some fields. If you advertise your framework as being an option for static sites or blogs, I expect you to do this not as an afterthought.
You may argue that it comes with the territory of using these frameworks instead of something like Wordpress, Squarespace or Ghost. You get more flexibility instead and pay that with more manual configuration of details. I don’t mind that, but then the documentation leaves you hanging or you realise that the recommended plugin / library expects things to be handled a certain way and the flexibility goes out of the window. You’re fully right, and now you can guess at what point I started looking at running Ghost 😉
Brittle plugins
I had problems with brittle plugin or library ecosystems (even first-party or recommended) with virtually all of the options. On the one hand it’s advertised as an advantage, since there is a sanctioned way to diverge from the default setup. On the other hand, when it doesn’t work or has unexpected site-effects, you feel forced back into the default way. You kind of get frustrated that all this flexibility seems to be just one arm’s length away for some reason.
Seriously, this was the main source of “I might as well roll my own” frustrations. I have to cut the authors of these frameworks some slack though. At some point as the maintainer, you have to say no to things.
More straight-forward content management
Eleventy, Astro and arguably Ghost do this right ot a certain degree, although Ghost in its default guise is very limited. The other frameworks, being more generalist frontend (meta-)frameworks, depend on external solutions, mainly some headless CMS services.
The content collections found in Astro (esp. the new 5.0 way) and Eleventy do a good job for local Markdown. What Astro could do better is take advantage of the front matter flexibility of Markdown. The content definition via Zod is too strict, if you don’t know the shape of every content type yet, therefore you also can’t experiment easily with new content types. Eleventy has a mighty advantage here.
Going forward
In the end I went back to Eleventy. It’s a lot more basic than others but considering the state of the overall JavaScript ecosystem, this is an advantage. You still have to jump through hoops, but it’s far less brittle than all the others when you move off the beaten path. It doesn’t feel like home yet, so while I declare the current state “good enough”, I will still look into the other solutions more deeply.
I’m still leaning towards Astro as the best balance between something like Eleventy and something like Next.js/SvelteKit. That said none of the options has won me over in a clear way.