DEV Community

loading...
Cover image for FLUURT: Re-inventing Marko

FLUURT: Re-inventing Marko

ryansolid profile image Ryan Carniato Updated on ・4 min read

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(() => {
  document.title = `You clicked ${count} times`;
}, [count]);
Enter fullscreen mode Exit fullscreen mode

useEffect hook depending on 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.

Alt Text

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.

Alt Text

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.

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.

Discussion

pic
Editor guide
Collapse
xyn profile image
Mydrax

Haha, that's a very interesting name! Saying "FLUURT engine" during discussions is definitely going to make a few people laugh.

Regardless, it's exciting to see progress and most of all the fact that Marko is solving problems in a different way. The syntax looks pretty intimidating though. It looks like a hybrid of JS and XML, like markup that is actually capable of expressing logic. Don't you think that'll make documentation efforts tougher?

I believe sub-component hydration will be a game-changer for depth-heavy components like pages. Do you think that because of this, progressive loading can be further improved? Like currently, you'd go from page -> general layout of the UI -> rest of the UI. Maybe with sub-component hydration, I can load less critical components like text for example the last while prioritizing interactive components like buttons?

Edit: Also, don't you think that the use of let/const as tags will introduce any confusion? From what I understand, they serve different purposes right?

Collapse
ryansolid profile image
Ryan Carniato Author

We do share some of these concerns. In the next article I'm going to focus squarely on syntax. I think that the XML syntax for Marko has always been a bit of a barrier and at certain point to reach our goals it just made sense to embrace it. The hope is now that people have seen primitives like Hooks or the Composition API this will be an easy translation. These systems always have framework specificity no matter how we try to hide them. Svelte's $ sign has both assignment and function call semantics. This isn't really any different.

let and const is an interesting choice too. But I think you will find as we show more examples and you get a chance to try writing the code they actually make more sense than you'd expect. In our reactive world there are mutable bindings and constant bindings. This might be a bit too cerebral to translate but our hope is that you won't be thinking much about this as you get going.

What we hope that will help documentation is reining in all the current syntax Marko has into a consolidated set, that is both used internally by Marko and externally in end-user code. As always part of the reason to showcase this stuff early is to get feedback so we can make improvements.

Subcomponent Hydration is case that definitely is for more complicated sites and applications. Marko already aggressively partially hydrates, but we still see so many places due to component boundaries we need to ship more JS than we'd like. The only place you absolutely need to share the full JS is where the client is responsible for rendering, like under a conditional or dynamic loop. There are many places where the parent components are stateful, or have events etc, but 3 quarters of their template is still static. Maybe there are nested components on the static side as well. This way we choose to not include any of that code. It isn't enough to identify this is the beginning of the dynamic Island.

This can inform hydration strategy definitely. However, we do see value in separating the mechanics here from the UX. Sometimes arbitrary cascading loading/hydration is not desirable so expect to see more control over async boundaries and placeholders in this next version. There are few different ways to attack progressive hydration and we will be looking at them. But the first big win is to just combine our streaming with this new ability to ship less JS hydration code.

Collapse
peerreynders profile image
peerreynders

It looks like a hybrid of JS and XML, like markup that is actually capable of expressing logic.

One of the problems with JSX is that people treat it as markup even when it's only an "XML-like syntax extension to ECMAScript". Similarly here - it's not markup.

Other than that templating systems like Nunjucks (based on Jinja) can accomodate a lot of logic (for better or worse) - so the proposed syntax just seems to cut down on the braces and percent characters and is in line with Marko's philosophy: Marko is HTML re-imagined as a language.

Also, don't you think that the use of let/const as tags will introduce any confusion? From what I understand, they serve different purposes right?

Perhaps initially. But eventually:

  • let - define new observable
  • const - define computed (i.e. has one or more dependencies)
Collapse
peerreynders profile image
peerreynders

Thanks for the update.

This seems to pick up where Michael Rawlings: Maybe you don’t need that SPA (2020-May) left off.

Readers interested in some more background:

Collapse
ryansolid profile image
Ryan Carniato Author

That's a really good point. This is the culmination of years of various research between myself and the rest of Marko team. We're getting to a point now where we can start sharing these ideas and get feedback.

Another good one that is hidden in the article is:

Collapse
madza profile image
Madza

wait marko was developed by ebay, right?

Collapse
ryansolid profile image
Ryan Carniato Author

Yes, and still is the primary library ebay.com is built on. In 2017 it was given to the JS Foundation to "ensure that it remains a healthy open source project", shortly before Patrick the original author moved on from eBay and the project.
The Future of Marko

eBay employs a small team to continue to maintain and develop the project, which I recently joined this past summer.