Since learning React, I've willingly thrown myself into the embrace of starry-eyed fandom. Not quite to the level of getting a tattoo of my obsession, but more than willing to show pictures of my work as if they were photos of my children to strangers. Like a proud parent watching their little ones pick up a Fisher Price hammer for the first time, I encourage my React-lings to treat every web problem as a nail and beam while they smash it into working order. I never once ask if React is the correct answer or even the easiest, so, naturally, when a CMS-shaped nail appeared, we got to work.
We looked at the different aspects that cause a content management system to become bloated in part one. In part two, we will dive into the murky waters of excessive features. We will do a little more experimenting and a lot more thinking—maybe even taking a few pictures of our React-lings along the way to be shared or included in this year's Christmas card.
An idea for a future post: AI Christmas card generator??
The learning curve that accompanies React can be a non-starter for some. If you are unfamiliar with the framework, a developer may return to something more comfortable to achieve complicated requirements. Especially when doing client work, we are rarely afforded the time needed to learn something new, and this is precisely when a project can fall into the trap of "Master of None" from part one. When returning to our comfort zone, we start rearranging and renovating what we have into what we want—usually without checking if what we wish will even fit into the space. But, like moving a too-big couch up a too-small staircase, we still attempt to make it work by gouging, scraping, pivoting, and partially disassembling it on the way.
This is called "feature bloat." We fill our programs with more feature furniture than butts to sit on them, and this is a problem and a symptom of an inside-out design pattern. The application assumes that the page it's rendering needs everything until it's told differently. An example of the inside-out approach in WordPress is with their filters and hooks—how it handles injecting work into the render loop. There are over 400 default hooks and filters that do more work than we need for most pages. Even just checking if there is work to be done can waste time and resources.
I worked on a project that had over 100 feature flag checks. It was impossible.
So, we started experimenting with the idea of "feature delegation" instead of bloat. We wanted to take a more outside-in design approach allowing the core to conduct the application while the page dictates what it needs. Our core is mainly a YAML interpreter that stands at about 330kb, and it will stay there regardless of how long the page is or how many different pieces are needed. We made the render loop more efficient by completely eliminating it.
We took a simplified run of WordPress' render loop:
Request -> index.php -> query_posts() -> new WP_Query() -> query() -> get_posts() -> the_post() -> setup_postdata() -> apply_filters() -> wp_reset_query() -> wp_reset_postdata() -> HTML -> Response
and made it into this:
Request -> [url].exo -> useExothermic() -> buildTemplate() -> HTML
With our outside-in experiment, one question came up frequently:
"How do we create a dynamic app if the core will never change?"
We needed an abstraction layer that kept track of where our components were. We decided to use YAML and define our components as
!custom tags. And since YAML is just a text file, we had the side-effect of manipulating our structure whenever we wanted to without needing to recompile the bundles.
- !section class: row w-100 items: - !col class: col col-6 align-items-center content: | Coder<span>•</span> Wheelman<span>•</span> Dragon slayer<span>•</span> - !col id: me class: col col-6 d-flex align-items-end content: | !(/images/pxArt.png)
------- Rendered React code ------- <Section className="row w-100"> <Col className="col col-6 align-items-center"> Coder<span>•</span><be /> Wheelman<span>•</span><be /> Dragon slayer<span>•</span> </Col> <Col id="me" className="col col-6 d-flex align-items-end"> <img src="/images/pxArt.png" /> </Col> </Section>
Can be turned into:
- !section class: row w-100 items: - !col class: col align-items-center content: | Coder<span>•</span> Wheelman<span>•</span> Dragon slayer<span>•</span> - !section id: me class: row w-100 content: | !(/images/pxArt.png)
------- Rendered React code ------- <> <Section className="row w-100"> <Col className="col col-12 align-items-center"> Coder<span>•</span><be /> Wheelman<span>•</span><be /> Dragon slayer<span>•</span> </Col> </Section> <Section id="me" className="row w-100"> <img src="/images/pxArt.png" /> </Section > </>
Effectively re-arranging components with a simple text editor, no Webpack or Babel, and all at runtime.
There is always a ramp-up period when starting something fresh. You have to hook up the routes, judge which state management to use, wait for packages to load, and so on. We wanted to focus on getting pages up with as little bootstrapping as possible. The building blocks come predefined yet generic, the routes are handled by the
.exo files, and the states are managed for you. Add the core library to a page, define a few blocks in the
index.exo file and you're done. You can structure your landing page and subsequent pages with only these parts and without running
Something that always amazes me is how many different flavors a tech stack can come in. Some will say theirs is better than another for reasons, but they all do just about the same thing, although in just about every configuration you can imagine. We wanted to be as agnostic as possible from the schema to the server, backend, microservices, containers, databases—everything. YAML and Markdown will get you started, but if you want to keep your blog authors in WordPress, then keep them in WordPress. Build out a plugin to handle the back and forth, and it's yours. It doesn't make sense to force a workflow change if you don't need to. The rivalries and infighting that result from preferring one thing over another don't make sense in the end when it's all just text on a screen.
By separating the different facets of the application from each other and from the core library, security patches can happen when they need to. Authorization and authentication can be anything you want or nothing at all. Hugely complicated roles and memberships should never have existed in the first place. When content and page layouts become separated, and when Exothermic eventually goes the way of the TRS-80 computer, you can bring your pages to wherever the hell the future has in store next.
Plugins will take center stage now that the lights are set and the cast has been—cast. Exothermic is meant to be a launching point, a substrate, for attaching whatever else you want it to do and plugins are how you'll make it happen. There is currently an example of a plugin that handles blog posts that you can reference.
On the roadmap, we've also started putting together what we're calling the Layer Engine, which allows you to create more reusable components across multiple pages. Hopefully reducing any extra copy-paste. This is specifically targeted at how content management systems currently treat templates. The templates enforce the reusable parts of a site by punching holes into what can be changed by the developer. They are restrictive by design and cause significant collections of one-offs to get around their limitations. With the Layer Engine, we want to relook at this and make it better.
I'd also like to see some kind of GUI to manipulate the
.exo files, but we'll see what happens there.
Lastly, we want to go further with making everything as agnostic as possible. This started another experiment we're calling Sandwich Shop, where you can turn any piece of code into a microservice—with your choice of cheese, and served hot or cold.