homepublicmail
{{platform}}
jam-platform.devsymbiotejs.org
mail[email protected]send@rnd_pro_chat
RND-PRO.com

It was really possible?

Hello everyone!

My name is Alex, and I am the author of a frontend library for creating UI components agnostic of frameworks - Symbiote.js. I’m not the only developer, but I am the primary contributor responsible for the concept, development, documentation, developer relations, developer experience, and everything else. In other words, I’m the maintainer. I work on all this in my free time away from my other job, where I am a full-stack R&D engineer and tech lead.

Today, I would like to talk about how Symbiote came to be and why it exists at all, given the vast array of libraries and frameworks for the frontend, many with a much larger audience and support from major IT companies. After all, we engineers really dislike the proliferation of unnecessary entities around us, and we immediately start waving Occam's razor threateningly. Right? (sly squint)

React

I created my first application in React many years ago when it hadn’t yet attained the status of the leading solution in the industry and the default library. In those glorious times, I worked on a startup team that was developing an application for live communication between doctors and patients. I joined the project at a time when the basic architectural decisions had already been made, and the technologies were finalized. My immersion in React was in hard battle mode, where I was not only writing code but also working on UX. My colleagues told me how cool React was conceptually, but one thought wouldn’t leave my mind (okay, far from the only one)...

JSX Syntax. After all, this is a markup language. We already have HTML for that. Moreover, smart guys taught us that it’s better to separate logic from presentation. But here, everything is jumbled together, with multi-level nesting... My IDE glitched. The new format of files wasn’t well-supported yet, and syntax highlighting keeps breaking. The mind also breaks in complex cases. Yes, yes, I know, decomposition, but I’m working "in a team," and in a team, opinions on decomposition can differ.

Could we achieve practically the same thing using simple, vanilla HTML and JS?

Alright, let’s keep this question in mind and move on.

Virtual DOM. Yes, the native browser DOM is slow, let’s say. It’s not entirely true, but let’s go with it. But aren’t we using the same DOM API, which we called slow earlier, to synchronize the virtual DOM with the actual browser DOM? So, we’ve created a new entity that doesn’t replace what we were fighting against but instead consumes memory and other resources?

Could we write a library that works efficiently with the DOM without creating a resource-intensive solution for it?

That’s the second question we keep in mind.

State. There’s the local state of a component, which seems straightforward. Then there’s the global state of the application. It can be quite complex and can itself be subjected to decomposition: divided into elements, each of which can have its connections with other elements.

For example, in your application, there might be a global state, one of whose segments is dedicated to storing user data, another for storing localization variables, a third for determining the current UI state, and so on. Each widget or micro-frontend can have its own state.

Additionally, when working with data, something like "consistency" is crucial - you shouldn’t have situations where related segments of state rely on different versions of data at the same moment in time.

But the data itself can have totally different sources of truth and reasons for dynamic updates: something comes from the server, something depends on user actions, and something is fetched via some third-party APIs. Total async is one of the main complexities of the frontend, with all those race conditions and more.

By that time, Redux, as a partial solution to the problems described above, already existed, but wrappers to reduce boilerplate were still absent. Contexts, as you understand, were also nonexistent. And it pained me to see this.

New questions arose. Something like this: if the library already has a basic reactive mechanism built in, why not make it abstract so it could also address global state issues without unnecessary dependencies and adapters to those dependencies?

Svelte

At one time, Svelte had pretty aggressive marketing. We were told it was a "disappearing framework." In other words, we have created yet another, new file format that, when processed by a special compiler, turns into... pure JavaScript! Fantastic!

Couldn’t we just write in plain JavaScript right away? You know, to avoid dragging yet another compiler, a new (another) file type, and a new (another) syntax into the project? Is it completely impossible to live without "black boxes"?

Alright, let’s look at the compilation results. Ah, here we have an import of the base class... And here’s a long list of imports. And here’s the structure of elements... Well, you get the point. No special magic, and more questions arise.

Next.js

At some point, React developers realized that a fully dynamic SPA site isn’t always a good thing. Issues with indexing, asset loading speed, and initial UI rendering... Backend developers are laughing and pointing fingers. It’s frustrating. And the idea was born: let’s bring React to the backend! We’ll implement SSR! And for the dynamic part of the page, we’ll use hydration. We’ll insert special markers and placeholders in the markup and wake them up on the frontend at the right moment. Beautiful?

And what about me? Right, more questions.

Why do we need React on the server, actually?

To form the entire document and its parts (which are, for the server, simple strings), we only need simple... template literals. And to invoke certain behaviors and document sections on the client, nothing is better than the Custom Elements standard: you insert one of these anywhere in the markup, and it activates on its own, looks around through the DOM API, and implements any interactivity.

And yet another question: could we solve the issue at the level of the platform’s basic capabilities and the language itself? Why create yet another "black box" that creates unforeseen complexities at the most inconvenient moments? Why reinvent what's already available out of the box for free?

Yes, I understand there are still routing, permissions, caching, all sorts of other assets besides HTML... But how does React helps here? Not at all. The problem is that we don’t want to know anything outside of React.

Lit

Earlier, I mentioned Custom Elements. And where there are Custom Elements, there’s Lit: Google’s main library for working with web components. A good thing, which evolved from the Polymer project. Once, the folks at Google said, "Use the Platform!" and that was enlightening. They even patched the "Platform" a bit so that this "Use" wouldn’t cause too much "Pain." I’m sincerely grateful to them for that.

But then they started distancing themselves from the platform. Not so much distancing as shielding themselves with abstractions. For example, for working with templates, they use their magical function html, which transforms HTML-based syntax into a special object. And this function imposes a lot of restrictions on how the template literal works. For instance, you become very dependent on the execution context of this function and lose the ability to do regular string interpolation. We are told: if you want to implant something into the template - create a new instance of our special object, and then insert that into the parent template.

And I want to ask: couldn’t we do without that? To form and store templates in any way we want, including the ability to use and activate markup from the parent document?

The Art of Compromise

Engineering is the art of compromise. A well-thought-out engineering solution involves weighing a lot of pros and cons, both for the general case and for specific situations. We are all human and sometimes tend to overestimate or underestimate some "pros" and some "cons." Some factors might escape our notice for various reasons. Any technology can be criticized. Any technology and solution can be good in its context, which may not be obvious or fully understood by outsiders.

We always sacrifice something a little: convenience, performance, the number of extra kilobytes, or conceptual engineering beauty. Sometimes (often), we fall into an illusionary trap. Sometimes, for the sake of illusory goals, we do extra work and create unnecessary entities. How can we combat this? My recipe is to ask ourselves questions. Using the examples of those I’ve asked in this article.

My answer to these questions became Symbiote.js.

And yes, it was possible.

Author: Alex Matiasevich [RND-PRO.com] © 2024
7.10.2024

PhotoPizza

From the idea to the Open Source DIY Project
17.09.2024

Smart HTML-tags

Simple recipe with the Artificial Intelligence
12.05.2024

JAM-platform Whitepaper

Concept description.
25.01.2024

Symbiote VS Lit

David and Goliath: differences, pros and cons...
18.01.2024

Symbiote.js 2.x

The new major version is released. Let's see what's new...