I've been sitting on writing this article for 2 years. In my heart this was the article I was going to write even before I read @swyx's quintessential Svelte for Sites, React for Apps. When I signed on to join the Marko team back in March 2020 (I know, perfect timing to relocate for work) something was very clear to me. I would have the opportunity to work on two of the most exemplary approaches to what the future of JavaScript frameworks could look like.
Some wondered why I would take on working on a second framework but I never saw a conflict. In many ways, they couldn't be more different. Every design decision made with different set of tradeoffs, where the "right" answer for each is allowed to be different. But the reason this excited me so much was that Solid and Marko represented the most powerful approaches on the axes that matter. A pincer movement of sorts for the JavaScript framework world.
Evan You, creator of Vue gave a great talk on tradeoffs of frameworks where he positioned Vue as that middle ground between React and Angular. It's easiest to explain this as a bunch of independent ranges but the reality is we live in a multi-dimensional world and one solution isn't always fully on one side for all decisions. But we as developers keep on changing our perspective to pull out these 2D comparisons.
So the task was simple: Don't change the world, change the perspective. And instead of being focused on the middle and being everything to everyone focus on the more achievable task at being the best version in the places that are divisive. Nothing wrong with backing multiple horses.
So Sites Vs Apps?
Well, this has been the dichotomy of the web for a long time. It even predates Single Page Apps, although that is why it has come into focus so much the past decade. We have seemingly two very different use cases trying to leverage the same technology. So it does make sense that maybe there is a way to make this unified even when it hasn't been feasible. And the frameworks/libraries I'm talking about today represent both sides to a tee.
Marko for Sites
Marko was created at eBay sometime in the early 2010s and was open sourced in 2014. It was built for eCommerce and the demanding nature of support global customers where not every device and network is made equal. A huge emphasis placed on page load, being the first JavaScript framework to introduce both Out of Order Streaming and Partial Hydration right from its inception.
Marko also was one of the earliest compiler-based frameworks as its origins were from server side templating languages. It was very clear from its beginning it was ultimately a language rather than a framework; a line of thinking that wasn't really popularized until Svelte did similar half a decade later.
Marko is a Superset of HTML where the whole world lives in Single File Components and a new user can enter this world simply by changing the extension of the HTML files they got from a designer to .marko
or using the HTML they copied and pasted from StackOverflow. Components are auto discovered and the impact of adding JavaScript feels minimal. It has all the characteristics people using server templating languages are used to but it is fully isomorphic to become interactive in the browser automatically.
And it sends the least JavaScript without thinking. Its "Islands" are automatic, and its streaming as easy as adding an <await>
tag with a promise. Its Multi-Page forward approach isn't worried about persistent client state or client routing and just works like a website the way you'd expect. It has the tersest syntax that lets you write the least code of all JavaScript Frameworks. It's an effortless way to get unmatched page load performance without getting away from the simplicity, that in the end we are just making pages in a website.
Solid for Apps
Solid came from a very different home. First created as a side project in 2016 when I was at a startup creating private Social Media. It was a long lived project that needed to keep on changing and pivoting to find its customer. While we could never rewrite what we had we would quickly rip out and replace parts. Solid was modular from the start, built to work with Web Components as a component-agnostic solution. It evolved to shedding that weight as it came into its own.
Solid's power is that everything is a primitive, right down to the JSX. Components are just functions, <div>
are just HTMLElements, and state is just reactivity. It scales down to a jQuery replacement and up to concurrent time-slicing, with the portability to run on non-web platforms using the same techniques. There is no VDOM or required abstractions. It is a chameleon that is exactly what it needs to be when it needs to be.
While it leverages compilation, only the JSX is compiled. It is very much a "Just JavaScript" library. Everything is built upon composing simple primitives and every corner has an escape hatch for complete control over how your application runs. The icing on the cake is this way of modelling things is also extremely performant making Solid a benchmark king in all environments it runs on.
This adaptability has made it easy to port libraries, and for people to opt into compiling down to Solid from their preferred DSLs. And it has been championing this composable primitive approach well before modern trends like Hooks. It gives "Just JavaScript" a new life in a world looking like it is heading deep into custom DSLs and compiled languages and returns to developers all the control they need to execute on the most demanding of applications.
False Dichotomy?
I admit I lured you here under a false pretense. If anything we've seen JavaScript centric web technologies collapsing on themselves. At first there was a clear difference between Static(SSG) and Dynamic(SSR) experiences but that has disappeared, and soon the difference between Sites(MPA) and Apps(SPA) will as well.
When we are seeing Solid acing page load metrics in impossibly expensive pages when used with Astro, something historically only Marko could pull off:
Or Marko bringing incredible client side rendering performance and composability with its new compiled reactivity that rivals even Solid, you start realizing we are just seeing a path to finally unify the opposite sides of the spectrum.
And this makes me hopeful, because these frameworks philosophically couldn't be more different. Language vs Library, HTML vs JavaScript first, Mutability vs Immutability, Implicit vs Explicit state updates, 2-way data-binding vs Unidirectional flow. And despite these differences we are here.
It would even not be unfair to claim that Marko is more svelte than Svelte, or Solid is more reactive than React. These frameworks sit at the the opposite edges with different values and philosophy but they both have unmatched performance, the smallest bundle sizes, and can serve use cases that span the whole spectrum. If these frameworks can do this any framework in between could as well.
Conclusion
Isn't it great that soon we could live in a world where Site vs App won't impact your choice of tool on technical merit? Nor JSX vs Custom DSL, or a HTML-first vs JS-first mentality? Sure, there will always be preferences and solutions that cater on developer experience. But you can choose the framework that speaks to you, and I wouldn't be able to convince you that there's a "winner". There is a path here regardless of what philosophy you hold close to your heart.
It took me giving Marko a chance to see this. To challenge my preferences and view of the world. As with Solid I looked at an approach that seemed to do all the right things years ahead of its time and leveraged that experience to explore what the best version of that looks like. Now, I see that potential to varying degrees in other frameworks. There really is an answer here for everyone. And that is exciting. The web is truly an amazing place.
Notes:
Acing scores refers to getting mid 90s lighthouse scores for this brutal page. This doesn't count the idle time. For the loading image I decided it was better to show the full time even if it was non-blocking, because otherwise it would look like Astro + Solid hydrated immediately.
Svelte + Astro can do the same trick. And SvelteKit performs no worse than SolidStart, Remix, Next, Nuxt, etc. This is just showing Partial Hydration coming to other frameworks. Marko and Qwik still are more optimal here.
JS Framework Benchmark results are run locally against the currently unreleased version of Marko. While this is not the final version it is close enough that I feel comfortable sharing these numbers. I've seen them be higher and lower than those but this should be close to where things should land.
Top comments (13)
@ryansolid Thank you for another great article Ryan. The only thing that worries me is whether Marko, Solid, Svelte etc. are going to be able to challenge React, as the predominant solution for anything web related.
It's true. But I can't really afford to be pessimistic about it. Otherwise nothing changes or evolves. When I created Solid I wasn't being concerned with that, I just made something that made sense for me with no expectations. And if you go back to the early 2010s there wasn't a single predominate declarative library. It's only been in the past 7 or so years that things consolidated the way they have. Part of it to avoid "JavaScript Fatigue" etc.. And also to provide stability and maturity to the job market. But there was a time not too long ago when you were like, I'm going to build our application in Ember, or Knockout and no one would blink an eye.
Now if you try to suggest not React, your team might accuse you of trying to sabotage their career and be severely jeopardizing their future FAANG hire-ability. Anyone with industry experience it seems almost comical to think that experience wouldn't translate, but then you recognize the real tragedy is they aren't wrong. React supersedes web fundamentals especially in junior to intermediate levels.
So I don't know. This has been my message because it's not that I dislike React. I just think the current state of "ecosystem maturity" is stifling to innovation. It isn't enough that a single other solution checks all the boxes. No we need to surround this ecosystem with many solutions otherwise should it ever be dethroned we just repeat ourselves.
Don't get me wrong I completely agree and I was that person using Knockout and Backbone before all this craziness.
I've met younger developers in their 20s and 30s completely enthralled in React and everything hippie this time around. Same people who are unfortunately completely oblivious how to use HTML or CSS. Moreover, even when it comes to JS they are also completely unready to implement the simplest of algorithms, but instead try to use some obscure library.
But it is also unfortunately true that the market insists on asking for React even if not the fastest or with the best DX. Personally, I have been asked questions about how React operates internally, plus why its the fastest.
I worry if the trend will change and I am all in having all the other options as well e.g. solid, svelte, marko, in case most developers realize where we are heading to, which is a React-ified world, which still lacks commonality, since no two React projects are the same.
@ryansolid by the way, when is Marko hitting v6 :-)???
Things have been coming together. We have basically a big bingo card as we are filling in features right now. We just got end to end hydration tentatively working the last day or so (made our Hackernews Demo). There are still quite a few missing features on the more complex side, including automatic async handling (ie.. what enables streaming) so there is still quite a bit of work. I think when you consider documentation, migration plans, integrations there are lot more moving parts that need to be tackled beyond just implementing this. But since the new year we've been able to focus on this more and have been making good progress.
To bring a somewhat different perspective to this, my concern isn't sabotaging anyone's career progression, but sabotaging my tiny, bootstrapped company's ability to hire within our budget. (Well, in a sense, I'm concerned about my own career, in that I want to be able to get some tasks off my plate.) So, as much as a focus on web fundamentals resonates with me, and I've been watching Solid and (especially) Marko with interest, I may still use React for future projects.
I think this may actually be a cultural/industry issue rather than a technical one.
My jaw dropped when I first ran across this on the Thoughtworks Technology Radar SPA by default Hold:
"We generally avoid putting blips in Hold when we consider that advice too obvious, including blindly following an architectural style without paying attention to trade-offs … Too often, though, we don't see teams making that trade-off analysis, blindly accepting the complexity of SPAs by default even when the business needs don't justify it. Indeed, we've started to notice that many newer developers aren't even aware of an alternative approach, as they've spent their entire career in a framework like React."
i.e. at least even the perception is now bad enough for TW to call it out to their clients (2021 was the first year where React surpassed jQuery in the Stack Overflow Developer Survey as the most used web framework).
Despite of the associated complexity somehow the available tooling has created a "developer comfort zone" (which is ironic because of the continued complaints of how complex everything has become) that potential detrimental effects downstream on the end product are usually ignored (or even denied).
On the surface the SPA-preference can be explained by trying to compete with native applications (in the long run competing on native application's terms is a losing proposition).
The problem: web performance is other people:
"I believe this is why Kroger.com used a SPA in the first place — if disparate teams’ APIs can’t be trusted, at least they won’t affect other teams’ code."
This suggests that SPAs may be (ab)used to keep organizational issues at bay. And perhaps the complexity leads to teams that are larger—possibly large enough that individuals can specialize fairly narrowly where they don't think about any trade-offs that don't affect them directly. Objective analyses of the drawbacks of SPAs aren't nearly as common as the declarations of perceived DX and productivity benefits that SPA frameworks can bring.
The fact that some people seem to treat React as (the future of) the web is more than a bit disconcerting. React's design goal is to enable reuse over the React Web/React Native divide—so React is about React, not the web.
There is no inherent incentive to align with the realities of the web unless it directly benefits React and doesn't interfere with the "Native" end. React's "re-implementing the browser" could be explained by the "Native" end needing whatever is being re-implemented.
To some degree even the Thoughtworks commentary isn't helpful:
"SPAs incur complexity that simply doesn't exist with traditional server-based websites … We believe that many websites will benefit from the simplicity of server-side logic, and we're encouraged"
While Marko, Astro, and Qwik are server-first solutions they are by no means traditional, trying to "go back to the old days". They do not eliminate the need for SPAs where they are appropriate but instead offer an "optimized for the web" alternative for a wide range of applications where SPAs can be an ill fit (or difficult/high effort to get right).
So it's not really about "Marko, Solid, Svelte etc. challenging React" but getting the industry and individual developers to realize that SPAs aren't the one-size-fits-all tool they clearly want them to be and that using them as a golden hammer isn't going to be helpful in the long run.
The educational discussion has been slowly gaining momentum over the past few years but the fact that there is a significant "developer comfort zone" attached to the SPA/React ecosystem means that it is going to take more time and effort.
What we need is a lib or framework that does SPA or MPA all in one. There are cases when we need client-side routing, and cases when we don't, etc, but the average dev would rather not have to switch frameworks just to change those semantics.
Which system gets us closest to having the choice in all four sectors of that graph, with resumable hydration in every case? I think that's where we're going.
Qwik (City) is the one. As you prefaced by mentioning resumability ;-)
Sounds interesting. I don't see the docs mention this though. Can you explain? How do we choose when a route is client side or full-page refresh?
The FAQ explains a bit, just search for SPA and MPA there: qwik.builder.io/docs/faq/
Qwik City apps basically do a full page refresh for every link (MPA style), unless you use their Link component (in which case it does a client side SPA style navigation).
I think there is a more interesting tension. Should be trying to mix SPA and MPA in the same app. This is essentially SvelteKit or Qwik's approach is. What Rich Harris called Transitional Apps. Or should be working on something that has the best aspects of both like I talk about here:
Client-side Routing without the JavaScript
Ryan Carniato for This is Learning ・ Nov 7 '22 ・ 6 min read
So many frameworks to choose is not positive/exciting for developers in JS world, in fact it's a mess. Life is too short to learn all of them or figure out which one fits me the best each month. It's a never ending chase that slows down get-the-job-done, it's a shame.