FLUURT: Re-Inventing Marko

Ryan Carniato
The Startup
Published in
4 min readNov 19, 2020

The Marko Team has been working on a new rendering engine which is slated to become the core engine for Marko in a similar way Fiber(React), Glimmer(Ember), and Ivy(Angular) have been for their respective libraries. Today I want to give you a first peek into what this is going to look like.

A lot has changed since the release of Marko 4 in 2017. Most of the effort has been managing migrations, and updating tooling (ie.. the move to Babel, Webpack, Rollup). Marko 5 is in alpha and represents the modernization of the toolchain. But what about the architectural considerations?

The FLUURT(Fast Lean Unified Update and Render Target) engine is being developed with a few key goals in mind:

  1. Reduce shipped JavaScript size
  2. Improve client-side performance
  3. Improve development experience

These are an acknowledgement of the increasing need for a dynamic and interactive experience on the client. Marko has long had one of the best server-side implementations but as frameworks like Next show up, and even newer compiled approaches like Svelte it is clear it is time to take the next steps.

Approach

Marko is an interactive templating language first and foremost so we should play to our strengths. We have the ability to compile our templates as desired. So to best accomplish our goals we’ve decided to attack the problem by building a new foundation on the client.

1. Reactivity

Being a declarative language with control over templating syntax and semantics reactivity is a clear way we can achieve both our goals. Relying on a small set of reactive primitives with code generation drastically reduces runtime size and complexity.

The approach the FLUURT is using is what I’m calling granular compile-time reactivity. This is basically a hybrid between what Svelte does with its compiler and granular reactivity found in libraries like Vue, Solid, or MobX.

The way this works, similar to other granular libraries, is through explicit dependency tracking and ensuring only relevant parts of code are run as your application state changes. However, instead of tracking dependencies at runtime, it generates the dependency arrays at compile time.

// useEffect hook depending on count
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);

You can think of this like React Hooks if React automatically put the items in the array. This does lend to some edge cases re-evaluating more than desired but also reduces the runtime cost of tracking. Runtime granular reactivity, like MobX, actually unsubscribes and re-subscribes on every execution. This approach avoids it altogether.

Like Svelte there is no VDOM, but unlike Svelte we still manage a subscription list. This means the baseline for a single component Svelte will be smaller, but it also means that FLUURT can have better performance.

2. First Class Composition

Language design can be challenging but we know that it is of utmost importance to make things consistent. To accomplish this we want to bring reactivity into the language of Marko in an extensible way.

The proposal is that our primitives are just Marko tags. This means that they can be co-located, nested, and composable. Co-located means that they can live in the template where they are used; nested means that they can be mounted/unmounted independent of the component; composable in that they can be constructed and extracted independently of the component file.

One would define a reactive value (ref/observable/signal) with a <let> tag. And a derivation (computed/memo/$) with a <const> tag. And writing your own can be used and consumed in the same way.

The ability to put these primitives nested in the template creates a cut and paste development experience, where the cost of refactoring is greatly reduced as code can mostly be moved around at will without change.

3. Sub-Component Hydration

From these parts you might be able to see that most of the library works independently of components. One benefit is this approach reduces the overall overhead of having components.

But more interesting, is that this allows for a new type of hydration. We can hydrate along reactive boundaries rather than component ones. We can split the stateful and static parts of the template and ship only parts of components and their descendants to the browser.

Classically with partially hydrated apps, as you might find in Marko or ElderJS, once you hit a stateful component you need to have all the JS code below that point. But FLUURT introduces the ability to break up our islands even smaller. It’s more like Hawaii than Taiwan.

The amount of end-user code shipped to the client can be drastically reduced.

Summary

There is a lot to be excited about in the upcoming FLUURT engine. It unlocks performance techniques yet to be seen in any major framework. It provides a development experience where writing less code isn’t just about the number of characters you commit. And it finally gives Marko the tools it needs to be as much of a force in the client as it has been on the server.

This is just the introduction. Look forward to follow-up articles where I will dig into each area in more depth.

  1. Marko: Designing a UI Language

Check out Marko on Github, Follow us on Twitter, or Join us on Discord to keep apprised of the latest updates.

--

--

Ryan Carniato
The Startup

FrontEnd JS Performance Enthusiast and Long Time Super Fan of Fine Grained Reactive Programming. Member of Marko Core Team. Author of SolidJS UI Library.