skip to content
Podcast cover art for Marko with Dylan Piercey
Podcast

Marko with Dylan Piercey

Dylan Piercey explains how Marko, eBay's UI framework, pioneered partial hydration and MPA optimizations years before they became mainstream topics.

Open .md

Episode Description

Dylan Piercey explains how Marko, eBay's UI framework, pioneered partial hydration and MPA optimizations years before they became mainstream topics.

Episode Summary

Dylan Piercey, a developer at eBay and core contributor to the Marko framework, joins the show to discuss how Marko has approached web performance optimization since its creation around 2014. After sharing his programming origin story—from RuneScape bots to progressive enhancement experiments—Dylan explains how Marko differs fundamentally from mainstream frameworks like React, Vue, and Svelte. He traces the framework's origins to eBay's need for a declarative tool that could deliver fast first-load performance in a multi-page app setup without the overhead of full-page hydration. The conversation covers how Marko's compiler-first design and custom DSL enable partial hydration at the component level, and how the upcoming Marko 6 will push further with sub-template hydration, sending only the minimal JavaScript needed for dynamic interactions. Dylan contrasts MPA and SPA architectures, argues that the MPA approach has vast unexplored optimization potential, and discusses the tradeoffs of Marko's ecosystem—including limited tooling, editor support challenges, and its niche community. The episode closes with discussion of Marko's bundler integrations, deployment options including Cloudflare Workers, and hopes for a future where frameworks can seamlessly blend MPA and SPA behaviors.

Chapters

00:00:00 - Dylan's Background and the Road to Marko

Dylan Piercey introduces himself and recounts his programming journey, starting with copying websites as a kid and eventually writing bots in Java for RuneScape to automate its grind-heavy gameplay. That hobby led him into open source communities focused on sharing efficient code, which eventually shaped his interest in web development.

After college, Dylan worked at an agency building websites rapidly for diverse clients, which pushed him to explore progressive enhancement with React's early hydration capabilities. He built a framework-agnostic isomorphic router that let forms work server-side and then enhance with JavaScript in the browser—a pattern resembling what Remix does today. His attempt to write an adapter for Marko revealed its fundamentally different paradigm and ultimately drew him into the project and to eBay.

00:05:36 - Progressive Enhancement vs. Partial Hydration

Dylan defines progressive enhancement as building for the lowest common denominator—pages that function through basic HTML links and forms without JavaScript—and then layering on richer experiences like drag-and-drop after scripts load. He walks through practical examples of how a developer might create fallback form controls for interactive features.

The conversation then connects progressive enhancement to partial hydration, explaining that partial hydration becomes possible when a server or build step has already rendered HTML, meaning the browser doesn't need to rebuild everything from scratch. Dylan argues that the more a developer leans into progressive enhancement, the larger the surface area of content that can remain exclusively server-rendered, making the two concepts naturally complementary even if not directly equivalent.

00:09:19 - Marko's Syntax and Compiler-First Design

Dylan explains that Marko uses its own domain-specific language rather than JSX, giving the compiler full control to analyze templates and determine what needs to be sent to the browser versus what can stay server-side. He highlights how Marko's structured template format—with defined top-level exports, automatic component discovery, and built-in control flow tags like if and for—reduces boilerplate and simplifies static analysis compared to the open-ended nature of JavaScript.

He contrasts this with Solid's approach of optimizing within JSX, acknowledging Ryan Carniato's innovations while noting that a purpose-built DSL has fewer edge cases to handle during compilation. Dylan also points out developer ergonomic benefits like not needing to import components manually, a feature Marko has offered from the start that other frameworks have only recently adopted through plugins.

00:12:13 - Why eBay Built Marko and MPA Advantages

Dylan provides historical context on eBay's transition from a Java-based stack to Node.js around 2014. Because much of eBay's traffic arrives directly from search engines, first-load performance and SEO were critical requirements that existing SPA-oriented frameworks couldn't satisfy without sending massive JavaScript bundles. A/B testing showed that traditional frameworks added unnecessary overhead compared to the old Java setup's lightweight interactivity.

Marko was designed from the start to support partial hydration, streaming server-side rendering with promise-based async data, and a declarative developer experience—all optimized for the multi-page app model. Dylan explains how streaming lets the server flush static content immediately while async data resolves, moving the asset-loading waterfall forward. He argues these optimizations are the logical conclusion for any MPA and that the industry is only now recognizing benefits eBay has relied on for years.

00:17:51 - Marko's Tradeoffs and Ecosystem Challenges

The hosts ask what developers sacrifice by choosing Marko, and Dylan candidly discusses its limitations. The framework is heavily optimized for MPA use cases, which means SPA tooling like client-side routers simply doesn't exist in its ecosystem. eBay being Marko's primary consumer has focused development on eBay's specific needs, leaving gaps for broader community tooling.

Dylan also addresses the challenges of maintaining a DSL, including incomplete editor support and the absence of TypeScript autocompletion—areas where Vue and Svelte have recently made significant progress. He notes that Marko's need for deep bundler integration makes writing plugins more complex than for frameworks using traditional full-page hydration, and explains the difference between MPA and SPA architectures for listeners unfamiliar with the terms.

00:24:25 - The Future of MPA Optimization and Marko 6

Dylan argues that the MPA side of web development has vast untapped optimization potential and describes Marko 6's approach to sub-template hydration. Rather than hydrating entire components, Marko 6 tracks which specific expressions use state and compiles to a Solid-like reactive system, sending only the code needed to update dynamic text and attach event handlers—cutting bundle sizes by half even for simple components.

He explains the two-part strategy: first, granular tree-shaking that goes below the component level to exclude static markup from bundles; second, a hydration process that skips re-rendering entirely, instead serializing only the scope needed for browser-side effects and event handlers. Dylan also touches on the possibility of frameworks that blend MPA and SPA behavior seamlessly, referencing Qwik's approach and expressing hope for convergence across the ecosystem.

00:33:09 - Using Marko With Other Tools, Hosting, and Community

The hosts explore whether Marko can coexist with React, and Dylan explains that while it's technically possible, combining frameworks defeats Marko's performance purpose. He clarifies that Marko is a full replacement for React, Vue, or Svelte—not a pre-compilation step. The discussion moves to deployment options, with Dylan noting that Marko runs anywhere Node does, and that Cloudflare Workers would be an ideal edge deployment target, though documentation for that setup is still forthcoming.

Dylan discusses Marko's bundler philosophy, explaining how the compiler itself acts as a mini-bundler that analyzes the full component tree, making integration with tools like Webpack, Rollup, and Vite possible but different from typical framework plugins. The episode wraps with Dylan sharing how to find Marko's Discord community and his own social accounts, expressing enthusiasm for continued conversations about the framework's future direction.

Transcript

00:00:00 - Anthony Campolo

Is it Piercey?

00:00:01 - Anthony Campolo

Yeah, Piercey is right. Great. Dylan Piercey, welcome to the show. Thanks for having me on. I'm excited to get talking about all this stuff.

You were recommended to us by Ryan, who we had on to talk about Solid, and he briefly talked about Marko a little bit, and I was curious to learn more about it. He said you were the guy to talk to.

So first, before we get into Marko et al., why don't you let our listeners know who you are and what you do? Right now I'm working at eBay.

00:00:40 - Dylan Piercey

I've been there for just over four years. I started programming way back when I was a kid, kind of as a hobby thing. I started copy-pasting some websites with slight tweaks to start a thing for some games that I was playing, and so on.

Then eventually it got more into non-HTML-based programming in Java because I was playing a game that was so grindy that I decided I didn't want to play it myself. I wanted to write a bot that could play it for me. That's kind of where I started programming.

00:01:07 - Anthony Campolo

What game was it?

00:01:08 - Dylan Piercey

It was RuneScape.

00:01:10 - Anthony Campolo

Ah, yeah.

00:01:12 - Dylan Piercey

Yeah. If any of you have played, you know it's a very grindy game. Anyway, I started writing bots for that, and then I started sharing these bots and all that stuff.

That kind of got me into a semi-open source community where people were sharing things, and we just wanted to make the most efficient methods for essentially botting the game.

After that, I did go to college, and that's when I really started to focus on web development. In my second job after college, I worked at a place called Tyler Digital. Essentially, we just pumped out website after website for various customers of various different sizes. Some were more application-like, and some were just kind of splash pages for various marketing agencies or whatever company you could imagine. We were pumping them out so fast.

I wanted to make sure that I could use all of the cool new tooling that was coming out at the time. React was pretty much brand new. Angular 1 was still very popular at that time, so I wanted to be able to use these tools.

[00:02:07] But I also realized that for a lot of these sites, SEO was going to be super important. And then the other thing is, I needed to make sure that all of this stuff worked back to, in some cases, IE7 or IE8. That was actually a big challenge.

One of the things I realized I could do right out of the gate is take advantage of progressive enhancement so that I could deliver the base functionality of the page using essentially links and forms and stuff like that, and then progressively enhance that with JavaScript. Because React supported a hydration mechanism, I could essentially render my page with React, hydrate it, and add some additional functionality after the fact. That was a really interesting pattern for me and felt like the best of both worlds.

But the first thing I always had in the back of my head was, I have this progressively enhanced experience. It would be nice if I could do more and more isomorphic code. The first thing I did was, how can I bring this server-side router that I have into the browser?

[00:03:04] At the time, React Router was still a baby. I think it had just kind of been released. A lot of routers that are out there, and even now, are all kind of SPA-oriented and didn't really have great support for the kind of server rendering that I was doing at the time.

So I built this little router that essentially allowed you to write an Express-like router that worked in the browser as well. You could write your routes that would work on the server, integrate it with Express, and then run that same subset of routes in the browser. It was framework-agnostic, and that was kind of interesting.

That allowed me to set things up a lot like Remix does today, where you have a form in the browser, and then once the JavaScript loads, the JavaScript code in the browser can handle the form submission and add some additional functionality, show something immediately to the user, do validation, those kinds of things, loading states, and so on.

[00:03:53] That's kind of what I was focused on at the time. Then the interesting thing after that was I started taking this framework and trying to write adapters for everything, as you do.

One of the frameworks I tried to write an adapter for was Marko, and that's kind of what started me into Marko. I realized that it was going to be a bit of a challenge. Part of the reason it's a bit of a challenge is because Marko is fundamentally different than a lot of the frameworks that exist today, and that's what drew me in.

To this day, there isn't an adapter for my little router framework for Marko because it's a different paradigm. I actually think the paradigm of Marko is better suited for a lot of the experiences that I was building at the time.

Anyway, tinkering with Marko and playing with that eventually, Patrick, the original creator of Marko, kind of reached out to me, and that's what brought me into eBay.

00:04:40 - Anthony Campolo

That's interesting how you say that Marko is a different paradigm. This is what got me interested in it because we've been talking a lot about partial hydration, both on the show and just within the general web dev conversation, with projects like Astro and Slinkity and now Îles and Qwik.

As I was reading about this, learning more about it, and learning more about the history, I kept getting pointed back to Marko. It would get mentioned, and I would be like, Marko? What is this Marko? I never really heard of it until I started learning about this stuff, and then it kept coming up. Not only did it keep coming up, it was the only thing that came up that was released before 2019 or 2020 that had done any of this, and it came out around 2014. So it seems like it was way ahead of the curve.

But I'd be curious. You used the term progressive enhancement in there. I want to tease apart the difference, similarities, or relation between progressive enhancement and partial hydration.

[00:05:36] We'd like to define both of those terms.

00:05:37 - Dylan Piercey

Progressive enhancement to me is building the lowest common denominator experience. As far as the web goes, in my mind, and obviously people have different definitions of this, I'm not the progressive enhancement police or anything like that, but in my mind you have a page, and the base functionality of that page is links and forms. That's how you can interact with a vanilla web page, assuming there's no JavaScript.

Then there's also CSS. So you can provide some functionality, like you can actually have it so that when you click a checkbox it animates or something like that, because you can do all that with CSS. There are some things that are just built into the browser that don't require any JavaScript.

I think optimizing your page for that base set of functionality, just the forms, links, CSS styling, and all that stuff, is a great way to get started. After that you can add progressive enhancements.

One example I can come up with off the top of my head is a drag-and-drop experience.

[00:06:25] A drag-and-drop experience is not something you can do without JavaScript. There's no HTML form that's like, this is a draggable form element, or something like that that's just shipped by the browser.

But even something like that, I think you can look at it from the perspective of progressive enhancement. You could look at it and think, okay, if I'm a user that's coming to this page, I have JavaScript disabled. Not a lot of users have JavaScript disabled, but there are lots of users who, for whatever reason, the network fails, the JavaScript has code that the syntax isn't supported in their browsers, or for whatever reason the JavaScript isn't there. What does the experience look like for that user?

The way that I would approach a problem like that is, okay, how can I build this experience in forms? Maybe I add controls to the draggable elements so that I can actually move them around the page using a form, and then after the fact, once JavaScript has been enabled, I can progressively enhance it to add the drag functionality that hopefully would be using the same underlying code to shift the elements.

[00:07:14] So essentially I click a button that is a form that says, move this element from here to here, or I can progressively enhance it and add a drag action that would do the same thing.

That's the way I look at progressive enhancement: how can we deliver an experience that works for the lowest common denominator? The simplest way to do that, especially if you're back in my younger years trying to support IE7 and IE8, where you don't know what the JavaScript is going to be like or the JavaScript support is really terrible, is to target the HTML form elements and links.

So then you were saying, how does that relate to partial hydration? Partial hydration is really only possible when you have a multi-page app in some sense. There's probably innovations that could be done there, but for now, the vast majority of partially hydrated setups are through multi-page apps. The reason for that is because essentially you've got a setup where the server, or through static site generation, has rendered some portion of the HTML, and you're sending that portion of the HTML to the browser.

[00:08:14] Some of the work has already been done. Because of that, it means that the browser doesn't necessarily need to rebuild the page from scratch. There's a lot of things that are just 100% unnecessary overhead to send to the browser.

So if you've got a progressively enhanced application, especially if you set it up from the get-go such that some experiences are completely defined through forms and link clicks and stuff like that, then you have a potentially higher surface area of content that can be exclusively rendered on the server side.

The more you opt into the progressive enhancement mental model, the easier it is for you to build experiences that could be pre-generated static HTML or even server-side rendered and so on. So I do think they're not totally related, but they kind of work well together.

00:08:54 - Christopher Burns

I'm not being awkward. I'm just out of my depth at this point, so I'm just listening.

00:08:58 - Anthony Campolo

This is a complicated topic, and this is why I've been digging into it and wanting to learn more about it. The conversation you had with Ryan there was just like so many things. You explain it and be like, okay, I think I get it.

What might help is we talk a little bit about what the syntax of Marko looks like. When you're actually writing Marko, what is it exactly?

00:09:19 - Dylan Piercey

Marko has its own language. Part of that is just because we want it to be able to optimize things in a slightly different way, which I think actually speaks to one of the things that is interesting about Marko, especially way back in 2014, is the fact that it has a compiler in front of it.

Marko, just like Svelte nowadays, compiles HTML string concatenation on the server and some kind of DOM mutation logic in the browser. Right now we use a DOM in the browser, but that's going to change for the future version of Marko.

As far as the syntax is concerned, it doesn't play a huge role, other than that we want to have full control over the experience. The main thing we want to be able to do with Marko is look at your template and be able to discern what needs to be sent to the browser and what parts are interactive. It's a lot easier to analyze that in a language that's a little bit more structured than just there's JavaScript and then you've got these little JSX sections in there.

[00:10:11] A Marko template has a defined top-level export. It's always there. You're not exporting multiple React components. You're not conditionally exporting things. There are a whole bunch of additional things you'd have to consider when you're trying to optimize JSX pages, which is essentially what Solid is doing. And he's doing his optimizations at the level of JSX.

Honestly, if you would have asked me if some of the things that they're doing in Solid right now would have been possible using JSX-like syntax a few years ago, I probably would have said no, but Ryan's come up with some pretty interesting approaches to that. I think there's definitely room for innovation in JSX as well.

It's just that when you have a language that's clearly defined, it makes it easier to, from a compiler perspective, go in and optimize that kind of stuff because there are fewer cases you have to worry about. The other thing is, since we're defining a language, we can make things kind of easier for the developer as well.

[00:11:05] So in a Marko file, basically from the beginning, you don't typically import other components. We use a Node.js module-style lookup where you have a components directory and it just finds the closest components directory, and then it ultimately propagates up to your node_modules.

It's a lot like, I think there's a plugin for Vite to work with Vue that automatically discovers components. It works a lot like that, but we've had that from the beginning. So there's a lot less boilerplate. You don't have to import the components.

Another thing is JSX. Initially, when it came out, people were like, the fact that I have to use a JavaScript map here is kind of awkward, especially at the time where maps were not supported in all browsers. You've got the ternaries and the logical operators that people use to conditionally render stuff. At the beginning people were like, this looks pretty weird. Obviously it's pretty commonplace now, but if you have a DSL like Marko that is designed for rendering HTML, you can make things a lot more clear.

[00:11:58] We have an if tag from the beginning. We have a for tag from the beginning, just like Solid has a show tag and a for tag as well. There are advantages to being a DSL, but I wouldn't say Marko is what it is because it's a DSL, although it's definitely made things easier for us to do.

00:12:13 - Christopher Burns

What's the use case of Marko that you see in the industry, where it started in 2014 and its use case there, and how has that use case evolved to today and today's needs in the industry as a language?

00:12:32 - Dylan Piercey

I think it could make sense for me to talk about why Marko was built for eBay in general and what that transition looked like back in 2014. So a little bit of backstory.

eBay was primarily a Java shop before 2014. It became clear at some point that writing your front-end logic and using Node to have isomorphic code and code sharing and all the benefits and the concurrent model of Node and all that stuff, there were a lot of advantages piling up there. So obviously eBay started looking into Node.

eBay is a site that is, I mean, we try to be very optimized for that first load experience. A lot of traffic to eBay is coming directly from a search engine. We can't necessarily rely on that a user has been to eBay in the past week or so since we've done a deployment or whatever, and we don't want them to download all of our giant JavaScript bundles before they can even experience the website. From the beginning, we've really been focused on that first-load performance.

[00:13:25] With the Java-based setup, it was really set up with a sprinkling of interactivity. It's a multi-page app. Then we had some vanilla JavaScript and some helpers and stuff like that to go in and add interactivity to the page. Obviously that doesn't scale super well. It's kind of nightmare code to look at. It's not declarative, and so on.

So there are huge benefits to having a declarative model on top of that. But with most of the front-end frameworks that exist today, they're set up such that you render the whole application, or a big part of the application, and then you have to hydrate and rerender the entire application again in the browser to set up the event handlers, run the effects, and so on. That means you're bundling all of the code for your entire application.

When we were doing A/B testing, going from the Java-based stack to a Node-based stack, we were using one of these other frameworks. We'd quickly see, okay, here they added a couple kilobytes of JavaScript to add the sprinkling of interactivity. Over here we brought in the whole application to render it when we don't actually need it.

[00:14:20] So Marko from the get-go was designed with the idea of how do we have a declarative experience for building applications with a sprinkling of interactivity. That's why from the beginning it had partial hydration support. And partial hydration still isn't perfect, right? Effectively, "islands" is the term that people are using nowadays. Under the island of interactivity, there's still a whole bunch of stuff that really the server already did and the browser doesn't need to do, but it's a whole lot better than just sending the whole application down.

That was one of the first things out of the gate. The other thing is SEO is important to a company like eBay. So we needed to make sure that the server-side rendering was there from the get-go and that it was performant.

Another piece of that is if you want to optimize for first-load performance, one of the things you're going to reach for is streaming, especially when you have, and this is the case at eBay, services that are giving the data to the front-end view that take any amount of time.

[00:15:19] Streaming is hugely beneficial because however long it takes, you can move the waterfall of asset loading for images, scripts, and so on forward if you're able to do streaming.

So essentially from the beginning, the way it works with Marko is you do all of your async requests for data at the beginning before you start rendering, but you pass all these promises through your templates. Then the templates are like, okay, here's all the static stuff that I can send to the browser, and it's done. The browser is starting to download those assets. Things are going well. As those async sections finish, we flush out more and more content.

Really, these two optimizations, if you're looking at a multi-page app, are the logical conclusion, especially if you're coming from a multi-page app where it's like, yeah, this was an experience that was relatively small, relatively fast, and why is bringing in these new tools making it a million times bigger?

I think that was really the forcing function for why eBay needed a framework that was optimized to be able to build experiences quickly using declarative tools and so on, which is what Marko was trying to do, but also for that first-load performance and MPA setup.

[00:16:19] I think right now there's a lot of focus around MPA setups, and people are kind of acknowledging the benefits of MPAs. Part of it is that there's a little bit of baggage of people being like, well, the MPA setup, you can't do X, Y, or Z with an MPA, but it's like, you can do a lot of stuff. Especially if you're saying, this section is interactive and this section is not, and so on.

So there's a lot of benefits there, and it's really more of a spectrum of where your app fits on the SPA versus MPA spectrum. I think with people realizing that, that's why these, in my mind, very obvious places to optimize are becoming more and more to the forefront.

The thing is, since Marko was, how do we optimize for the MPA setup from the beginning, it's like, yeah, we've tackled those obvious ways to optimize a multi-page app. It's also a little bit of an Achilles heel of Marko because we haven't super optimized on the SPA side of things.

[00:17:14] We don't have an official client-side router because we're kind of expecting you to do server-side routing. Not to say that you couldn't do client-side routing with Marko. We just don't support that because that's not the way that we're using it currently.

Most people coming to Marko know its advantages are in the multi-page app setup and first load and all that stuff. So they're not necessarily going to be like, yeah, I'm joining Marko for these reasons. I'm going to go build a SPA-like router. That kind of negates most of its advantages.

It's a little bit tricky for people coming in, but I think that's really the key, that Marko is optimized from the beginning for that use case. And we're seeing more and more tools coming out optimized for that use case as well, which is really awesome.

00:17:51 - Christopher Burns

What do you sacrifice by using Marko? Because right now we've talked about all the benefits. It sounds like if I replace the word Marko with Remix, I'm getting a bit of deja vu to a certain extent without using either of them.

00:18:06 - Dylan Piercey

I would say Remix really does a great job on the progressive enhancement side of things, and they've got server-side rendering as well. But Remix doesn't have islands of interactivity or partial hydration. It also doesn't support streaming, at least until they upgrade to React 18. Maybe they do support it out of the box, I'm not sure. Either way, it's coming soon.

That's where they are similar. But the drawbacks of Marko, really, I would say, are that it is kind of set up for an MPA. So the ecosystem is very MPA-centric. There just aren't tools. People aren't interested in building the tools for SPA-like applications for Marko, which is something that I think actually has a ton of room for innovation and which I would love to talk about some more as well.

It's sort of an ecosystem problem. For the most part, eBay is Marko's biggest customer, so we've very much optimized Marko for eBay's use cases, which means we're kind of optimizing it for the tools that we're using.

[00:18:59] We've been trying to do better as far as integrating with tools that eBay isn't necessarily using, like Vite. We've got Marko integration for Vite, but one of the things that is tricky is because Marko likes to look at the whole experience from start to finish, including the bundling and how we deliver assets. Because it's had partial hydration from the beginning, we need a lot of control over how we integrate with tools, especially bundlers.

So it's actually a little bit more involved for us to go and write a bundler plugin than a framework that does the traditional-style rebuild-everything-in-the-browser hydration. So ecosystem is a big one.

Another one is, and this is something we're going to be improving upon, since Marko is a DSL, the editor tools for that DSL don't necessarily work properly. You can embed Less or Stylus or whatever in a Marko file, but maybe the completions don't work as well. I think they do actually at this point. But TypeScript support is something that doesn't currently work, and autocomplete in that regard.

[00:19:53] I think Svelte and Vue have been doing a way better job in that their language servers have improved a ton, and now I think you get pretty decent completions. A month or two ago, Vue got TypeScript completions in their actual expressions. We're going to be doing similar stuff like that in Marko.

But just by the nature of it being set up for a niche type of app and also having a DSL, the ecosystem is a little bit more sparse.

00:20:15 - Christopher Burns

We've used a lot of acronyms there. I'm just going to reaffirm them because some people may not know what they are. So what was MPA compared to SPA? SPA is a single-page application.

00:20:29 - Dylan Piercey

MPA is a multi-page application. The reason I think the term MPA has come up is just because most apps these days are being built as a SPA, but really an MPA is the traditional way that you would build an application.

I'm not 100% sure why we needed to return it, but I do think it's good to differentiate these two things. Another thing about MPAs is you can have a SPA in one of the pages of an MPA, or you can have islands of interactivity. You can do that approach. So I really think MPAs are a good starting point because, like I said, you can sort of progressively enhance an MPA setup all the way to a SPA. I'm not quite clear how you would do it the other way around, but there could be innovation there.

00:21:14 - Christopher Burns

So in terms of the difference, and this is what I understand, a SPA is when you load the page, it basically loads your whole application and then it basically lies to the browser navigation and says, they're on this new page, they're on this new page, they're on this new page, when really the bundle hasn't changed. Everything on the page has just changed.

MPA is more: every time a page changes, the whole bundle gets reloaded. Everything is completely different. But that means the bundle is a lot smaller because it's specific for that page.

00:21:47 - Dylan Piercey

Exactly. If you're doing a SPA, essentially you're saying, I've got an app where we're going to be doing the vast majority of the rendering. Maybe you do the initial server render, but everything can be rendered in the browser. So you're basically saying, hey, browser, here's everything you need for my application.

With a multi-page app, you actually have the ability to either pre-render to static HTML or by server rendering, have it so that the server or static HTML contains some initial render information. You can pre-render stuff. The browser never has to do that work, and you can potentially cache it better. You kind of offload work to the server.

The downside of that is you're going to have to communicate with the server unless you have a service worker cache in front of those pages. But the upside of that is, well, the server did a whole bunch of the work that the application might have otherwise had to do, and your server is likely running in a known set of performance characteristics and so on.

[00:22:39] You know that your server is going to be relatively fast. You don't know what the end user's device is going to necessarily be. Maybe their device is super slow at running or hydrating an entire React page. So it is pros and cons, but I think the simplest way to think about it is deferring some work to the server.

The main problem I see is that a lot of people are like, React can render on the server and we've got this box checked, right? But it's like, no, we've done the server-side rendering kind of to improve the initial perceived load performance. We haven't taken full advantage of leveraging what the server did for us. We're still redoing a whole bunch of stuff in the browser.

I think the best is kind of in the middle. Like I said, having a setup where the server or your build step can do some of the work, like a precompiler for your app, and then the browser can pick up where it left off.

[00:23:29] I think that's our goal anyway.

00:23:30 - Christopher Burns

It's kind of a really interesting ground where what you're saying is, when we look at it just through the e-commerce lens, you could say you've got Marko on the left saying compile everything on MPA to make the page load as fast as possible. And then you've got all of these, like Next.js and Gatsby, saying, well, what we're doing is good enough and we'll never fail a Lighthouse test, and it's all good.

Is there a problem with either? E-commerce, I find, is one of these really polarizing categories in JavaScript because everybody chooses to do it a different way, but there's no true way, and that's a good thing.

But we always have the quote of whoever said it: every millisecond Amazon cut down on their load times made money. That's why it should be fast. But what is fast? How fast can you get, right?

00:24:25 - Dylan Piercey

I think that's actually the most important thing to figure out: how fast can we get, and why are we leaving all of this performance on the table?

I think looking at the MPA setup and thinking of it, like I said, as a free compiler for your app, rather than just this old technology or something like that, has a lot of unexplored potential. Marko has obviously done some of it with partial hydration, and more things are coming out that way, but there's actually a lot more we could do on that side of things.

The real question is, why don't we have a framework that can deliver an ideal experience depending on what type of application you've written? People want one framework to rule them all. That is tricky because optimizing for all cases is quite hard.

I don't even think we've figured out what the potential is as far as a declarative framework that could be optimized for an MPA, and I don't think we're going to get anywhere close to that if we continue down the path of just focusing on frameworks like Next.js and Gatsby.

[00:25:18] This is the floor of performance, right? They've changed where the floor of performance is. We're doing full-page hydration, so the bare minimum JavaScript present is X.

Digging into MPA-style optimizations is good just because there's so much unexplored potential there. Some of these things have come into modern frameworks. React is finally getting server-side streaming with Suspense and so on, and that's something we've had forever because we needed it for our use cases.

I think as we figure out the best ways to do all of this stuff on the MPA side, hopefully we can converge more and more. I really want to live in a world where I don't have to think about, I'm building an MPA experience or an experience that would be best suited for an MPA or a SPA experience. I just want to have a framework or a set of tools that's like, this one can do both. And actually, for these pages, I want it to be a SPA, and for these pages, I want it to be MPA.

[00:26:07] Right? That's where I would like to be.

00:26:08 - Anthony Campolo

Yeah. I saw a tweet from Ryan talking about Qwik, and he was saying that it operates as islands but can morph into a SPA as needed, and that this type of functionality was going to be coming to Marko. So how is that possible?

00:26:23 - Dylan Piercey

Technically, Marko can morph into a SPA as needed as well, right? You can essentially have a router at the top of your Marko file. The problem is, as soon as you have a router, at least in every framework setup excluding Qwik right now, you're essentially saying this section is routed client-side, which means it needs to be able to be rebuilt by the browser.

That's kind of the status quo of it. You hit a new route, you need the client to be able to rerender that section if you've got a client-side router. What Qwik is doing that's really interesting is they've set things up such that no matter what's rendered on the page, it will download the assets just for what's rendered.

I'm not 100% sure what a router would look like that could actually do a seamless transition. What I have in my mind is more like you would denote, some pages are MPA setup or server-side rendered, and then you'd have a subset of pages that are a SPA.

[00:27:16] Ultimately, there needs to be a router that allows you to say, hey, this is this, and this is that. I don't think there's any clear-cut way right now to determine which would be best suited for your application.

If you look at SvelteKit right now, they have a way to opt in and say this is a static page, right? So they kind of have that already. I just think there's more improvements on actually optimizing the pages that are MPAs, and that's where Marko is going.

So right now, I said Marko has partial hydration or an islands-based approach. Essentially the way it works in Marko today is we look at all of the components in a page, and we try to find the top-level components that have stateful logic, that is, they can rerender in the browser. If you have a component that doesn't have anything that would indicate that it could rerender, we just leave it on the server side. That's how we're able to tree shake stuff out.

[00:28:07] But the thing is, when you look at things from a component level, that's not granular enough because you could imagine a component that has some state that could rerender, but maybe it has this giant SVG in it or something like that. That SVG could be totally static and could be exclusively rendered by the server, so you don't necessarily need to bundle that in your application to be able to rerender it in the browser.

So what we want to do, and what we're doing in Marko 6, is what we call sub-template hydration, which comes in two parts. First, we moved more of the language for defining state and lifecycle into the Marko template directly inline, kind of like React hooks, except you can put them sort of anywhere. There's no hook rules or anything like that. With that, we're able to track, okay, this state is used by these two expressions, this state is used by these two expressions. As a side note, we're taking that and compiling it to a reactive system kind of like Solid.

[00:29:00] So you have the benefit of the components only rendering once and so on. There's going to be good client-side performance.

With that, we're able to see, okay, this text right here, that's the dynamic piece, but the rest of this button and the rest of this prefix text, that's all static. We don't need to send that to the browser at all. That's kind of what we've set things up to do.

With that setup, I think the simplest example is if you've got a counter component and you're imagining it's displaying the current count, and you've got a button that increments it. That's the simple example. You've seen it on lots of frameworks.

If you really think about what it would mean to build an optimized counter page that is in a multi-page app setup, all that page would have in terms of JavaScript is code to go and find that count text and code to go and add an event handler to the button.

[00:29:47] Then every time the button is clicked, update the text content. Ultimately, there would be maybe five lines of JavaScript that you would send down.

Now the interesting thing is, let's say we're doing partial hydration or component-level hydration. We're sending down the code for the fact that there's a button, but the button was rendered server-side, so we don't actually need that. We've got some content in the button, like maybe Increment or something like that, but that was rendered server-side. We don't actually need that.

So there's a whole bunch of stuff, even in a fairly dynamic single component, that could be exclusively rendered on the server side. We recently compiled that example, and even something as simple as that, with what looks like a fully reactive component, our output component size was half of what it would be if we did partial hydration.

We think there's huge potential there. It's one of those types of optimizations where it's like, oh, you could see infinite gains from this potentially.

[00:30:43] Because you're able to exclude more and more code from the browser, and by excluding this chunk of code, now you've excluded this, and maybe now you're not sending Lodash to the browser and all this stuff.

Instead of it being like islands, it's like moving to, maybe you only need a house or something like that, or an apartment. That's kind of the way we're thinking about it. How can we get it to the level where we are just sending down the stuff that is actually dynamic? That's part one. Does that part make sense to you all?

00:31:09 - Christopher Burns

Yes.

00:31:10 - Anthony Campolo

Yeah.

00:31:11 - Dylan Piercey

Okay. If I can get into part two.

Essentially the other thing that happens during hydration is pretty much every setup right now renders everything again. Even if it's islands, you're rendering that island again so that you can attach the event handlers and stuff.

But if you really think about what needs to happen, like I said, it's just go and find a text node, go and add an event handler. Those are the things that the server couldn't do or that couldn't be easily defined in the HTML. That's what you really want the browser to do. You don't want to be like, okay, rerender this component just so that I can get these things.

One of the things we're doing in Marko 6 is essentially we keep track of code that only needs to run in the browser, which is your effects and attaching the event handlers. We serialize everything that is in the scope of those functions to the browser, and then in the browser we just say, hey, okay, here's some effects that you need to run, and here's some event handlers that you need to attach. The way that we have things compiled, if the server does any work, even if it's a computation to map something to new data, it would actually serialize that depending on what was used in the effects and event handlers in the browser.

[00:32:19] So essentially the hydration process looks a lot more like what I described, where you're just finding the elements in the page. That's one step of what we do during hydration.

The other thing is attaching the event handlers and running effects in that way. It's optimized for bundle size, but it's also optimized for doing as little work as we can do so far. Obviously there's room for improvement, but it's impossible right now to create an app that's just like, build me the most optimized experience for this thing and compile it to craziness.

We have a pretty good runtime that we're targeting, and it's quite small. I think the overarching mechanism and how we're doing the tree shake and all that stuff is coming out quite well, so hopefully that kind of makes sense.

00:32:59 - Christopher Burns

It really does. One of the biggest questions that I have, and I already know the answer to it, and it's kind of a stupid question: can I put Marko plus React together?

00:33:09 - Dylan Piercey

Technically you can. The tricky thing when merging frameworks or using multiple frameworks on the page is now you've taken the cost of multiple frameworks. And being that Marko is kind of designed for that first-load performance, it's like you're defeating the purpose of using Marko, but there's nothing that would really stop you besides that.

It is a little bit tricky to figure out transclusion, where you have content, like body content that you're passing to React and making the APIs seamless. That is a little bit tricky, but nothing would fundamentally stop you from doing that besides you're just adding a bunch of JavaScript to your page.

Now, from our perspective...

00:33:45 - Christopher Burns

Marko is not necessarily a replacement or an alternative for your Vue, your Svelte, and your React.

00:33:51 - Dylan Piercey

It is.

00:33:52 - Christopher Burns

Yeah, great, because that's a really simple question that I'm not sure we answered because it's got its own style. My first thought was, is this like a really cool pre-compiling step, then you just use another framework like Svelte to do something later on? And there's like, no, they do everything.

But then it's that question of like, we're so used to either seeing tools as a React competitor or a React integrator. It's that thing of like, where do you sit? Well, this sits by itself.

My next question. Okay. So this is obviously not something we're used to with SPAs. How do you host a Marko application? Where do you host it? If someone wants to pick it up and quickly build an app in it, where would they go and host that?

00:34:34 - Dylan Piercey

eBay has its own servers, so we're kind of deploying it internally, obviously, but you can deploy it really anywhere. You can run Node, or you can also deploy it to the edge using Cloudflare Workers. We don't have support for Deno Deploy yet, but I would say probably the best-suited place for Marko would be the edge and Cloudflare Workers. But really, anywhere you can run Node, anywhere you can get a Node instance like Heroku, and so on.

00:34:57 - Christopher Burns

Is there a tutorial about putting it on Cloudflare Workers? This is something that I hear everybody talking about. Cloudflare Workers are the next best thing and we should all go and start using that. You've just said you work great on that. Is there already a tutorial about deploying Marko on that?

00:35:14 - Dylan Piercey

We don't have one right now. It's definitely something we want to do.

00:35:18 - Anthony Campolo

We have an open issue asking for one.

00:35:20 - Dylan Piercey

Yes, so we need to do that. It's a little bit tricky because, like I said, it's not something that we're actively using at eBay. We don't use Cloudflare Workers at eBay. We are trying to push for a more edge-based setup, but we do already have a solution for that that's internal.

I do think in the future we'll have more documentation for integrating with Cloudflare Workers because it seems like it is probably the best place to deploy Marko at this point. But like I said, anywhere that's running a Node process would also be a good fit for Marko.

Another thing is you can use Marko for building static sites as well. All you have to do to turn a Marko application into a static site is crawl it and download all the HTML, and then just dump that to disk somewhere. The nice thing about using Marko for static site generation is it still has the automated partial hydration, so it's still going to build you a static site that hopefully has bundles that only include the interactive parts for those pages. You can use it for that setup as well.

00:36:09 - Christopher Burns

You've got a lot of open opinions in that you don't necessarily pick one. For example, on your bundlers you have Webpack, Rollup, Lasso, and you've spoken about Vite in this episode. We've seen a lot of React players just go, here's the one we've picked.

Do you think that having a more open opinion to just use what you want is something that is far more enterprise, where you're like, because we make enterprise software, we have to do this, instead of just picking one?

00:36:40 - Dylan Piercey

It's a bit tricky because actually, for the vast majority of Marko's life, it pretty much only properly supported one bundler, which was Lasso, the bundler that we've built. Lasso is kind of in maintenance mode right now, but it actually has a lot of features that are similar to Vite. It basically allows you to say with our plugin, hey, here's a Marko template, give me the assets and put them here and here, which is kind of what you want versus a normal: here's the JavaScript entry point, which is like your whole application. Give me the output JavaScript and I'll inline that in my page.

Somehow maintaining both a framework and a bundler and everything is quite difficult. We wanted to explore supporting other tools. Marko is kind of set up such that we do need to have at least some control over the whole experience to be able to know what assets to load and all that stuff.

So one of the things we did with Marko 5 is basically move a lot of the logic for figuring out what needs to be bundled into the Marko compiler itself.

[00:37:31] So Marko, instead of a normal templating language like Svelte, when you compile it, it's looking at a single component. The Marko compiler right now actually looks at your whole tree and can make decisions and give you an optimized bundle based off of that. So it's kind of like a mini bundler just for Marko applications, which has made it easier for us to integrate with other tools.

If it's possible and easy for us to integrate with other tools, we want to do that. But obviously we want to promote tools that actually work for the use cases that we have. One of the tools that I see some hype for is Parcel, but Parcel is not really set up for server-side rendering. To my knowledge, I have never seen a good server-side rendering setup with Parcel, so we're not necessarily going to support that if we would have to use Marko in a way that wouldn't be optimized.

Every solution that we have out there, like the Rollup one, the Vite one, if you go and look at any of these plugins, you'll probably quickly realize that it's very different than how you would use React in Rollup or React in Vite because we expose APIs in all of these tools to say, hey, here's where you put your assets, here's how this is defined.

[00:38:29] You actually don't specify the entry points for your application because we determine what they are. So there are some differences there.

The main thing for us is we want people to be able to use the tools that are most interesting to them. We don't want to put all of our eggs in one basket or anything like that, but we want to make sure whatever tools we do integrate with actually work well with Marko.

00:38:47 - Christopher Burns

As you said, as we were going along, this area has a lot of room to expand. We're seeing the SPA market being flooded with options and now server integrations being added into them like Redwood and Blitz.

So you can do dashboarding. Do you think all of that innovation is yet to be had on the MPA side? And a second part of that is, is Marko the right tool to integrate on top of, or will we see other tools in the MPA area emerge with these further capabilities like databases, Prisma, ORMs?

00:39:25 - Dylan Piercey

I hope other tools start thinking seriously about these types of optimizations, even the ones that we've done for a while, like partial hydration and stuff like that. Astro picking that up, we're super happy about that and that there's been more focus on it, and so on.

We've been looking at Marko from the get-go in terms of how can we get to these types of optimizations and how can we design the language so that it's easier for us to compile to these optimizations and so on. I do think we have a bit of a leg up.

We've also set up our compiler, like I said, so that it can look across multiple templates, which I think is kind of necessary when you want to do the kind of aggressive tree shaking that we're going to be doing. So I think there are some ways that Marko is set up to be able to achieve these optimizations, but it's not necessarily something that only Marko could ever do. Maybe Svelte could look into this.

[00:40:07] I do think any language that has a compiler in front of it is going to be way better set up to do it, but at the same time, with Solid, it's got a compiler in front of it, but it's still JSX. There are certain limitations that you have to work within.

So you could potentially come up with a subset of functionality in JSX or in a JSX-like template that could maybe provide the same functionality. But you're just having to think about so many different ways that people could write JavaScript that it becomes hard to reason about and optimize.

So the gist is, I kind of think we have a leg up both in that we're looking into these types of optimizations and that we've set things up with the compiler such that we can actually do them.

00:40:46 - Christopher Burns

So Anthony, it's now the right time for you to go and make a Prisma plus Marko dev.to article.

00:40:55 - Dylan Piercey

Yeah, that would be great.

00:40:56 - Anthony Campolo

That would be the thing to do. On that note, I'll be curious. Is there a community for Marko if people are creating things with it, writing about it, or should they share it? Is there Discord or anything like that?

00:41:06 - Dylan Piercey

Yeah, we have a Discord. I think it's just the Marko Discord. You can get to it if you just go to the Marko website. In the bottom right, you can get to our Discord. It's a great place to chat with us there.

00:41:18 - Anthony Campolo

And you said before, when we were talking, that you had never done a podcast before and you were a podcasting natural. So thank you so much for coming on and explaining all of this stuff. I want to get you on some other shows. We had told the pod people to get in touch with you.

00:41:33 - Dylan Piercey

That'd be great. I have so much more to talk about. There are some things I wish I could have snuck in here, but yeah, it was great talking with you guys. Definitely appreciate you bringing me on.

00:41:41 - Anthony Campolo

Yeah. Thank you so much. Could you also let our listeners know where they can get in touch with you and follow your stuff?

00:41:45 - Dylan Piercey

I'm on Twitter. I think it's just @dylan_piercey or something like that. On GitHub, I'm just DylanPiercey there as well. Probably the simplest, quickest way to actually get in contact with me is just on the Marko Discord or several other Discords. I'm on there all the time.

00:42:01 - Anthony Campolo

Well, thank you so much.

00:42:02 - Christopher Burns

Thank you.

00:42:03 - Dylan Piercey

Yeah, thanks for having me.

00:42:34 - Anthony Campolo

Awesome. How do you feel about that?

00:42:36 - Dylan Piercey

I thought it went pretty well. Like I said, I feel like I missed some things that I wanted to jump into, but that's fine.

00:42:42 - Anthony Campolo

Yeah, there's only so much time for this one. It's such a dense topic. Like, there's so many...

On this pageJump to section