Hello, world! After a lengthy hiatus, I'm back online.
After leaving it alone for the better part of a decade, I decided I’d missed writing enough to get serious about rebuilding my personal website.
Much of my technical background is in full-stack content management system (CMS) development, and most of the systems I’ve worked with have been LAMP stack. I’ve been fortunate to have gained a lot of great experience in this space, but I’ve been wanting to switch it up.
In my mind, end-user software development is largely about about the building blocks and tools you choose to do the job. You only can do brilliant work when you love what you do, and choosing your tools is not unlike pulling together the ideal set of Lego, K’nex, Lincoln Logs, or, if you’re from an older generation, ERECTOR, to spill all over the floor when it’s time to build something.
So, always in pursuit of the best tools, I came up with a few parameters for my new website:
- I wanted to work with a CMS that I’d yet to
- Ideally, said CMS would be a different language than PHP, so I can branch out of the world of LAMP and learn how to build a production server for Node apps
- I wanted to use a Javascript component framework for the frontend application, along with goodies like PostCSS and TailwindI wanted the CMS to be a headless implementation, serving data to the frontend application over API calls
- I wanted to use a database other than MySQL/MariaDB
So I’m talking about two applications: a frontend, and a backend. Really, each app has its own backend and frontend, but one app serves Svelte UI/precomposed pages, and the other serves up data for the Svelte to present in the more human-friendly manner you’re reading now.
If you, too, are from a PHP-ish background, this may or may not weird you out. Some of the older, more mature PHP CMS communities made varying efforts to deliver some path to headless and decoupled content delivery options, but I was never delighted by this feeling that I had to undo out-of-the-box functionality in some way to get there.
Drupal would be my defacto choice if I were targeting LAMP — IMO, it is best-in-class amongst higher-level PHP systems, and you can start building against it as a headless backend pretty quickly if you use an existing Drupal distro like Contenta. But I want to do something new (to me), here.
The content management systems popping up and thriving in the Node.js ecosystem were catching my attention. Strapi is slick, as is Keystone. Ghost was an interesting older contender that I’ve had an eye on for a while, but it quickly became one of those over-commercialized products that sort of obfuscate the path to self hosting the open source project. The idea of using Decap CMS (formerly Netlify CMS) with an embedded SQLite database is pretty cool, though I was surprised to find the admin UI was not responsive.
Ultimately, PayloadCMS got my attention, and held it. It checked all my boxes, and the more I read documentation and tried it out, the more it became clear that this was most of what I loved about building with Drupal, but it was already headless (i.e. rather than responding with entire browser-ready webpages like a traditional monolithic CMS setup will do, it simply sends your content as data for a client app to present). Payload felt like someone had boiled down the Drupal backend development experience to its purest essence.
Rather than build new content types via an admin user interface at all, Payload has the developer describing content types in Typescript configuration files. It then handles spinning up a collection in MongoDB, exposing your data over GraphQL and/or RESTful endpoints, and delivering a clean UI for content editors to add and edit content within.
There’ll be posts about this down the road, but let’s get on to that frontend.
the frontend
With Payload locked in for the backend/CMS, we’ve got instant content APIs to develop against. I need to push that data through some sort of view layer to create the end product you’re reading now.
Svelte got my attention sometime during 2.0 release. Even then, it was so intuitive and a joy to use. I realize React was born during a very different time in Javascript’s progression, but my experience with React just never felt great, and I always though being called ‘React’ without being reactive out of the box is a little silly (they know this, and joke about it).
As I got deeper into Svelte over time, I’d eventually learn that its creator had a similar background to mine, and had worked in digital storytelling for some big time publications (NYT). In an interview with The New Stack, Rich talks about the history leading up to Svelte, and his own pursuit of the best tools to do this job. I’d been one of those folks doing it in Flash. I was starting to feel like I was in the right room.
Sveltekit
If you’re not familiar: you can think of Sveltekit as a user interface machine. It’s the server powering the frontend. It gives me a whole bunch of great things, but here are some highlights:
- a router for the entire user experience (e.g. /contact renders a page composed of Svelte components, including a form and some content)
- the ability to decide between different rendering strategies — server-side rendering (SSR), client-side rendering (in your browser), or pre-rendering at build time. And you can choose which strategy is used for each route individually. That is cool.
- a full stack JavaScript environment dedicated to churning out front end UI, which lets me easily make the most of PostCSS contrib (like Tailwind) and other modern JavaScript goodness
- local development is powered by Vite, and it all just sort of works
Together, Payload and Sveltekit are just plain fun to work with. And I like the extra inherent layer of security/insulation you get by being able to have a server-to-server connection ready to utilize when the payload-in-transit is sensitive in nature.
Imagine a page in a government website where you can edit your user profile, dense with personal information. We can use Sveltekit’s +page.server.js file to make a request from one backend to the other. Then this data can be securely sent along to the user for whom you were fetching it, and the original data source was never exposed on the client.
For fetching insensitive data, you can also make calls straight from the browser. Sveltekit’s +page.js file will run on the client (and also on the server, when SSR happens), so if you’re just on a /blog page, where the content you’re requesting from your backend is being presented publicly anyway, you can skip Sveltekit’s backend and just query Payload (or whatever other data sources) from the browser.
For this site, I’ve been challenging myself to completely insulate the CMS from direct user traffic by using +page.server.js exclusively for all GraphQL requests. At the end of the day, making a request to my homepage means you make a request to Sveltekit, which fetches data from PayloadCMS (or the cache), then sends the components and data to your browser to make up the page you see. One frontend, two backends. You’ll sometimes see Sveltekit’s peers/competitors referred to as ’backends for frontends,’ which is certainly accurate.
If you, like me, come from the world of monolithic content management systems and CRUD apps, the idea of having a dedicated UI app serving your interface can be sort of jolting up front. It certainly was for me, and I’ve seen the confusion from other software engineers when I’ve tried to evangelize this transplant of the V in MVC. It’s worth mentioning that you don’t have to deliver a Svelte UI via Sveltekit (which would mean hosting it in a Node environment).
You can feasibly bake it right into, say, a Drupal or Wordpress theme. At the end of the day, it’s just JS that needs to get to the end user’s browser, which your existing LAMP stack has always been perfectly capable of.
Compared to the CMS monolith, it’s a different way to think about content, but with the right tools, it all feels so zippy, and is pure joy to work with.