Latest news? Someone stuck a boat in the Suez canal. That's novel and an interesting problem to watch. I keep thinking about the queueing problems this will create when they uncork it. If you want to gain a better understanding of queues I think playing Factorio helps.
On BEAM Radio me and my lovely co-hosts have just shipped the Steven Nunez origin story. Steven is a goddamn delight. He also writes. And he does stuff at GitHub.
I'm glad to see people have a continued interest in my mentorship program. If you think you might need it, you know where to find it.
Easy things aren't always great
But they are easy
This time I'll try to be more beautiful
And more amusing
- Maylynne, Catch Me
Let's be a bit technical shall we?
I've tried to build and abandoned at least one CMS in Elixir. I had chosen an approach of building something that would work with the static generator Hugo because it seemed good. I've since run into bugs, weird corners and have found that the world of existing themes I wanted to leverage is an absolute mess of special cases and built-just-for-my-needs.
I think the most compelling technical case right now is building a "headless" CMS, that is a thing that manages content without necessarily rendering it to a specific frontend. It typically provides an API and can be used to populate apps, single page web applications (SPAs) or render to a static site generator (SSG). I think
Elixir would be exceedingly effective at this.
My preliminary plan for what I'd like to build is something I want to dogfood for Underjord.io. I want to be able to edit content in the browser, generate it out to static pages for performant CDN delivery as well as maintain some more dynamic parts of the site with straight Elixir + Phoenix.
To create a good foundation for this I think custom content types are absolutely critical. Being able to create posts, pages, comic strips, whatever you feel like publishing, deciding what fields should exist and not have to define that as an Ecto schema module up front is table stakes for a headless CMS. Some exploration tells me that this can be done with Ecto's schemaless features.
What would this mean?
Well, we need to store a definition of the content type with its name, fields and constraints in something other than a schema module. My thinking is to make a library that helps bridge such a format (a JSON:able map/struct) into Ecto calls. So this would give us a sort of dynamic schema.
What makes up a dynamic schema? What does it need to do? It needs to describe the table structure and it needs to provide a way to create that table. Essentially migrations. My thinking is to limit the complexity by not allowing particularly destructive changes. Essentially you should be able to add a field, and archive a field (make it optional, remove them from the schema, but not from the table). The sum of your alterations is your schema/content type. A microcosm of event sourcing.
So the metadata
associated with a field would be used to generate the type information Ecto wants along with calls to validations such as required, potentially foreign key associations and similar. We should be able to build something that allows us to basically generate Ecto Changesets that are a bit more dynamically defined.
You still end up using Repos and Changesets, we just replace the Schema.
Now thinking beyond a library, what would the CMS do? Well, importantly it would bring in a lot of opinions to avoid some common footguns. I've wanted to solve the WordPress Merging Problem for some time. I'm not sure there's a
truly graceful solution. But it can definitely be gracefully mitigated. One thing is to avoid numerical auto-incrementing IDs. This helps allow one to import and export pieces of content without conflicts and collisions. I'd likely use UUIDs and strongly recommend adding unique slugs to prettify for URLs.
Another part of the CMS, a huge part, would be the editing experience. Both editing Content Types and creating content requires good generic UI which is quite tricky. Handling images in rich text, handling file uploads. This is where so much work goes in. My last effort was using normal SSR views. I think LiveView has some potential to make some of this easier and faster. But it definitely does not solve itself. Most devs are fine with markdown, until we need to add an image.
As for
integration the CMS could do largely what Oban Pro and Live Dashboard do in introducing a set of routes that you can bring into your application. Letting you run the CMS at something like /content. Sure you might run the headless CMS on its own, especially if you aren't an Elixir dev but like how it works. The real power comes with being a part of a magnificent monolith. By being embeddable and bringing an incredible amount of power for building products.
It also needs either REST or GraphQL to be meaningfully useful with apps and other software. That's absolutely doable but also not a trivial amount of work.
As you might notice this kind of project has a slightly exponential scope. This is one of the reasons I've abandoned it before.
I
still want to do it. I think it would benefit Elixir, it would benefit my work and it would be cool tech that could do neat things.
So how do I think it could be done? Useful piece by useful piece. The dynamic schema definition library and all its utilities for runtime handling of that. One useful piece. A foundational piece. The UI for building Content Types. Useful in its own right. The UI for editing content of a Content Type. Very powerful. A good API in Elixir for hooking into all of this. Now we are getting somewhere. External APIs for wider use. Very cool.
I want to transition Underjord.io off of Hugo and build it to be a prototype in this direction. If it never goes further, maybe I just get a half-assed workflow that suits me. If I make decent progress maybe there is more to
it.
I don't want to expose my hopes and dreams on the blog entirely but this is a more private space, I don't mind sharing my thinking, even when I know it is quite likely to not reach completion. So this is would be Underjord.io rebuilt to be a PETAL stack monolith to run my very tiny empire.
I want to be able to support my publishing workflows from Elixir entirely. And that means getting the press of the button that sends the "Go! Publish!" signal to be a granular signal in a system I enjoy using and find sanely maintainable. I'll try to summarize the types of things I want in this system that a headless CMS would be foundational in achieving:
- Simple content editing in a web browser. Especially fixing typos.
- Generate the static parts of the site with Still, a very promising SSG for Elixir.
- Serve the static content from disk, in case CDN falls over.
- Push content to CDN edges by serving it with something like Cloudflare Workers.
- Be able to build dynamic parts of the site with Phoenix and LiveView.
- Integrate the Wisps into the application, allowing more fun stuff.
- Auth via Telegram or GitHub.
- Experiment with opt-in Web Notifications for publishing.
- Experiment with a Telegram Channel and other interesting publishing flows.
- Experiment with interesting web tech like WebSub and such.
- Integrate something like ProWritingAid for better editing. CI for writers ;)
This would let my site be more dynamic, more interesting and would let me do odd things like send sensor metrics to my site and do things with them. Experiment with JAMstack style hybrid workflows based on LiveView.
I apologize for this being a bit rambley and I hope the general idea made it through somewhat cohesively. I have a lot more thoughts on this whole thing and I just wanted to try to present it and get some feedback. I appreciate all of you that reach out to me via lars@underjord.io or on Twitter where you can find me as @lawik.
Thank you for your attention, I appreciate it.
- Lars Wikman