Qwik, O(1) Scaling for Frontends and Frontends

10 Oct9:00 am – 9:25 amTalk

Checking session availability…

Hang tight while we load the latest updates.

Frontend frameworks, and SPA's in general, trade great DX against poor UX in terms of loading time and performance. But as frontends scaled, the DX benefits also suffered because, as a monolith, it became difficult to isolate sections of the code to enable teams to work in parallel without impacting each other.

The new generation of frontend frameworks solve this problem by using a fundamentally new paradigm called Resumability and leveraging HTML, blending the lines between SPA and MPA

1. Current frameworks scale linearly, future is constant.
2. Business can deliver massive amounts of interactivity without hurting performance
3. Developers can focus on authoring component without worrying about the performance
4. Microfrontends becomes trivial, allowing multiple apps to be deployed and build independently.
5. Partial hydration of React and other frameworks

This paradigm shift aims to build extremely complex applications that scale without performance degradation and negative trade offs of developer experience, this is part of our mission at Builder, where we want to allow businesses to ship fast, extremely complex and performant sites.

Qwik, O(1) Scaling for Frontends and Frontends

Manu Martínez-Almeida at UXDX EMEA. Video: https://youtu.be/DRexDGW6qWs

Readable transcript: edited from the recording's captions for readability (fillers and false starts removed, punctuation and section headings added). Wording is the speaker's own. Timestamps are positions in the video. Names marked [?] could not be verified against the audio.

Instant regardless of complexity

[00:00:00] Hi, everyone. Today I'm going to talk about Qwik, and Qwik has a really interesting property: Qwik can be instant regardless of the complexity of an application. It doesn't mean that the application is a hello world. It can be a massive application, and Qwik enables instant interactivity. We do this through a concept we call O(1), or resumability, which I'm going to talk about later. Part of my job today is to convince you that Qwik can do things in a fundamentally different way that other frameworks cannot do.

[00:00:35] My name is Manu, and I'm a software engineer at Builder. I work in the open source team, and before that I've been building the Stencil web compiler and making SDKs and APIs for the last 12 years. At Builder we want to look at performance in a different way. We don't want to look at the typical performance test where we render 1,000 rows and see how fast we can be, but really at how things scale for big customers. In this demo we built the same application with from one component up to 80 in different frameworks, and looked at the amount of JavaScript these frameworks had to deliver. On the right we see this graph, where all the current frameworks follow this trend: as the application gets more complex, the amount of JavaScript grows linearly. But Qwik is stable. I just want you to pay attention and try to get the feeling already that Qwik is doing something fundamentally different from what other frameworks do to achieve this kind of performance characteristic.

JavaScript is the bottleneck

[00:01:42] We look at the web, and sites need more and more JavaScript. This is a fact. This data is from the HTTP Archive [?], and we see that the amount of JavaScript has been steadily increasing for the last 10 years. But is this really a problem? Well, we built this tool called Performance Insights, where you can put in your website and it's going to tell you four things. The first thing is your current performance score, like a Lighthouse score. Then, if you optimize the images, what your score would be; if you optimize the CSS, what it would be; and for JavaScript, if you optimize the JavaScript, what the score would be.

[00:02:23] We actually ran this at scale for the 50 biggest e-commerce sites in the US. One thing I want to point out is this line over here: pretty much all of them are in the red area. This means that they are actually very slow. Then we see what can be done about it. If these websites optimize the images, the performance benefit is very, very small. If they optimize the CSS, very much the same thing. This means that they are already doing a good job at optimizing those particular parts. But when we look at JavaScript, the performance increase is massive. We start to see that the bottleneck is JavaScript. It's not any other thing.

[00:03:05] You might argue with me that this is not a problem for your business, and I get you, this might not be for you. But for a lot of companies, especially the customer-facing ones, it is: faster websites mean more sales and better conversion, especially when the application gets more and more complex. I'm going to argue that this is because there is a systemic correlation between sites becoming more interactive and the amount of JavaScript. You would be naive to think that we can go back 10 years and make pretty much static websites, because the business and the users are not asking for that.

[00:03:49] The other thing I want to argue is that this is a systemic problem. It's not like some websites are faster and some are slower. All applications that at some point get more complex become slow because of the amount of JavaScript. One of our core principles at Builder and Qwik is: don't blame developers for what the frameworks do. This is a very interesting concept, because the whole front-end ecosystem is full of best practices: your developers should do this in React, you should do this in a different way, that's why it's very slow. But it's not true. Frameworks are leading developers to these bad patterns, and sometimes the frameworks themselves are the bottleneck.

[00:04:32] That's literally what is happening. The current trend is linear and going up because the current frameworks are O(n). But we can do something about it. What if the frameworks were O(1)? We could immediately break this correlation, so business and users can keep building more and more amazing, interactive and complex websites without the performance getting worse and worse.

Hydration versus resumability

[00:04:59] At Qwik we solve this with two main things, which are resumability and progressiveness. To understand that, we need to get a feeling for what the problem is today. Current frameworks really started as SPAs. They started from the thought that the website and the framework are going to execute in the browser, do their thing, and then the user will interact. At some point later, as an afterthought, it turned out it's good to run it on the server. For SEO it's good because you send the HTML already made, so it's visually instant. But the HTML that the server sends is something you cannot interact with, because frameworks were not designed for that.

[00:05:47] The framework executes on the server and renders to HTML. That's what is happening here. It sends this HTML, and at that point the browser needs to hydrate, which means adding the listeners, adding life to the HTML to be interactive, and rebuilding the state. That means you have to replay everything. You have to download all the components on the page and replay all the logic, and at that point is when it's interactive. Resumability is taking this concept, which doesn't make any sense, and doing something logical. It's like you're watching a movie: you stop the movie and you can just continue, you don't have to go from the beginning. That's what is happening in Qwik. It's like a virtual machine. The application runs on the server, it's paused, it's sent to the client with all the serialized state, and the application resumes instantly and executes without having to do all this work.

[00:06:41] I love this analogy. It's from the CEO of Builder, and it's the server-side baking analogy for what's happening right now. The server is making a cake, preparing everything, but instead of sending the cake to the user, it's taking a photo and sending the photo with instructions. When the user gets it, they try to bite it, but come on, it's a picture, it's not an actual cake, right? The browser needs to first get the ingredients, bake the cake again, compare it with the picture and say, okay, now you can interact, now you can eat it. This really doesn't make sense, and in the future more and more frameworks will be solving this.

[00:07:26] We are in this state not because we don't know better. It's because of a learning process. In the past it was actually very performant, but it had problems, and we are not going back to that. At the beginning maybe you used PHP or Ruby on Rails, you rendered stuff, and then you would use jQuery to add interactivity. That was actually very performant, but it had slow development, it was error prone, it had duplicated logic. It was not good for developers. So then the next generation was like, no, let's make it amazing, let's make it easy to build websites at scale and complexity. That's what Angular, Vue and React do. We have a unified model. You don't have to build an application in different silos.

[00:08:09] The problem is that in all of them the server side is an afterthought. They need hydration. The application needs to run twice. The future, which includes Qwik and other frameworks like Marko, which is also giving a talk at this conference, follows the same idea. It's not going back to jQuery. It's following the same ideas of a unified model, but then solving the problem of the double rendering, which is solved with resumability.

Demo: a simple Qwik application

[00:08:37] I made a lot of claims here, so I'm going to show you. Let's start with some of the principles in a super simple Qwik application. I'm going to show it here. We see "hello world," and if we check the HTML, it's just HTML. There is no JavaScript. This, I guess, is not impressive, but let's start to put some JavaScript here. If I put a console log and say "render," we will see that the console log is here, but only in the SSR. That means this console log ran on the server. It happened there, it paused, and nothing is executed in the client. Again, not very impressive, but let's put in some events. I'm going to put an onClick, and I'm going to say I want to console log "click."

[00:09:28] What we see here now is that there is a special new attribute, and not only that, it injected this piece of JavaScript. But this JavaScript is fixed. It is always less than a kilobyte. It doesn't matter if we have a million components or just one, right? It will only render that. Let me just put it back, I don't know what happened there. If I do that and I interact with it, notice this is the important part: the click handler ran in the client, but not the SSR. This code never even ran in the client, never.

[00:10:13] You may think that this is easy, and this is actually what is happening here: the optimizer is taking this code and splitting it into small chunks. We have this one, which is the click, and the rendering. But what if I do something like a const with some variable, "Manu," my name, and I put it here? Then I'm going to click, and it works. It says "click Manu," but again, it didn't execute this code. That's weird, how is it possible? Well, the innovation in the optimizer here is that Qwik serializes closures, which is what allows us to write code like in React but with the scalability and resumability of Qwik. We're going to keep focus, because we have a lot more to talk about.

Micro front ends as containers

[00:11:02] The next thing is micro front ends. Qwik has a very interesting property: Qwik is HTML-centric. It doesn't depend on execution of JavaScript, and it doesn't depend on state that lives in the JavaScript. That allows Qwik applications to be composable at the document level. You can have several servers generating different parts of HTML, combined into a single document, and everything works, because every Qwik application is a container. They can be built by different teams, with different versions of Qwik. Let's explore this.

[00:11:35] You have this app, and this demo called Containers. Containers is a demo that we built in collaboration with Cloudflare [?]. All these links are actually independent applications. There's an application that comes from this worker, an edge worker, which is just the footer. This one is the body, and I believe this is the header. All these applications are interactive by themselves. But at the same time, if we look at the code, we can put them all together in a single application, and it looks like this. All these applications are being combined at the document level.

[00:12:19] The reason this works is that all these containers live here, and they can be nested. You have the body container, and inside the body container there's this one over here, which is another container that was compiled by this version of Qwik, while this one was compiled with a different version of Qwik. Not only that, I can interact with this container, and notice that it becomes resumed while the previous container, even the parent one, is still paused. It didn't download any JavaScript. I'm going to show you this. If we open the network tab and refresh, there is no JavaScript. I'm just going to point out that this even works with JavaScript disabled. If I disable JavaScript and refresh, all of these still work, and they are coming from different workers that can be deployed by independent teams.

Data-driven bundling

[00:13:28] Let's go back. Another thing we have is data-driven bundling in Qwik. You will notice here that I don't specify how this is bundled. I don't have to write dynamic imports manually. Developers don't have to change anything, because it's impossible for a developer at scale to know how an application is going to be used and how it should be bundled. Instead, Qwik by default splits everything as much as it can. It makes as many entry points as possible. I'm going to show you how we can use real traffic information from the website to rebundle and reoptimize things. We have the docs site, so I'm going to show you the docs. I'm going to open this application in incognito so it doesn't cache. I want you to see several things.

[00:14:32] The first thing that happened here is that it's downloading... Not secure? Why is it doing that? Maybe I can put it here. Let's cut all this demo and do it again, because as usual, the freaking demos are a pain. So confusing. Docs, wait, not now, I will tell you when. Okay, something is up, let me try to fix it.

[00:16:00] Another very interesting thing that we can do in Qwik is data-driven bundling. You will notice from the code here that developers don't specify how applications are bundled. They don't have to manually write dynamic imports and make the bundles, because this is really a very hard problem to solve, especially when applications get very, very complex. Instead, what we think is that this bundling and this prefetching should be driven by traffic data. Data-driven bundling means using real traffic information to rebundle the application, doing this optimization at a different layer.

[00:16:37] I'm going to show you this demo. We have the docs site. I'm going to open it in incognito and put it here. I'm going to open the dev tools first, and pay attention to something that happens here. In the dev tools you will see that there is some JavaScript downloading, but mind, this is prefetching. Notice that the code is being downloaded by the service worker. Why are we doing this? We are doing this because we want to have instant interactivity. We can detect when this code is needed, so when we interact with it, the code was already cached by the service worker.

[00:17:19] But let's find a case where the performance was not very good. I'm going to clean this, and I'm going to interact with the search. Notice that it had to download a lot of code. This interaction requires so many little chunks, and after running testing we found out that we don't have to do that. In Qwik you will see all the little symbols with this hash. We collect this information and we generated this. It's going to be automated, but for now, for the demo purposes, it's manual. What we are doing here, and I'm going to stop it and rebundle it, is saying: look, these symbols actually belong to Algolia, they need to be all together.

[00:18:08] Let's see how this looks. I'm going to close this and see when it's ready. I think it's ready already. Okay, so now when I interact with it, it only downloaded three files, and all these three files were already precached, so you have instant interactivity. Notice here that you didn't have to change a single line of JavaScript. The source is still the same, something even a different team can do. So it's very, very cool at scale.

Loading React inside Qwik

[00:18:53] Something else I want to show is that Qwik can load React. It's not a goal, but some of the principles and primitives of Qwik allow Qwik to partially hydrate React. In this demo we have React code in Qwik City and Qwik React. We have Three.js, which is a 3D library, using React, and we have a canvas with some boxes. We also have MUI, which is the most popular component library for React, at the bottom here. Pay attention to this: we have this qwikify util that converts this React component to a Qwik component. The thing is that by converting it to a Qwik component, this code will never run in the browser.

[00:19:52] I'm going to show you this, it's very interesting. We just refresh, and there is no JavaScript being downloaded. Let's scroll and see what happens. We have Three.js, and nothing really happens here. Why? Because Three.js actually needs to run. You have a Three.js library using WebGL, so you actually need to hydrate. We also need to enable JavaScript, because we disabled it before; that's why it was not working. Let's go here and open the network tab. Still no JavaScript, but as we scroll, React works and you can interact with it. Again, you can decide: if you don't put client visible, then this component will always be static, and there will be a canvas here that never works.

O(1) frameworks are not new

[00:21:06] O(1) frameworks are not new. This is actually an idea that's been around for years. At Google there has been, for eight years, an internal framework called Wiz, and it powers the most complex projects at Google that are required to be extremely fast. We are talking about Google Search, Gmail, Google Photos. The problem is that building with it is a pain. You have a deeply coupled backend in Java, and business logic needs to be duplicated. It's not nice, so not even Google uses it for all its projects, because O(1) frameworks are still really hard to build with. Qwik solves that. Amazon is the same: they have claimed many times that they cannot use existing frameworks to make the front page. That's what we are trying to solve with Qwik. We're trying to bring these innovations that extremely big companies use for extremely demanding projects to everyone.

Capabilities, performance and developer experience

[00:22:05] This is an analogy from the backend, the CAP theorem, and I don't need to explain it. Basically, the idea is that when you make a website, you want three things. You want capabilities: a lot of functionality, tons of interactivity, user customization, A/B testing, a lot of things that a business or application needs. You also want it to be fast, because that leads to sales and better UX. And you want your developers happy. You want to be able to build quickly and iterate. I'm insisting on this a lot because we build software for real businesses, and in real businesses websites are not only owned by developers. They are also owned by marketing and by designers that need to make changes, so this is part of it.

[00:22:51] Right now you cannot have all of them. If you choose performance and capabilities, you will be neglecting the nice-to-build API, so you will have something like Wiz [?], places that have very custom stacks. That's what Amazon does. If you want API plus performance, then you will lose the capabilities. You will have something like MPAs, Astro, Eleventy. And if you want API, meaning nice and easy to build, plus capabilities, you will have Next.js, Vue, Angular, but you will destroy the performance at scale.

[00:23:24] What we solve at Builder is how we can have all these things, because real businesses cannot only care about performance. Our current stack: Builder is a tool that companies can use to integrate with their existing stack, meaning React applications and React components, and allow all-hands development. Not only that, it integrates extremely efficient A/B testing [?] and user personalization, meaning they can serve different content to people in different regions, or depending on whether they are male or female. Then Qwik is our solution for first-party code: how you put all this complexity in an application and still keep it fast.

[00:24:04] In third place you have Partytown, which is also for real businesses. They need third parties. They need Google Analytics, they need metrics, FullStory, all these things that slow down your website. Partytown is our solution to put them in a web worker while still being able to run them transparently. For us, that's the whole vision: how these three projects work together to solve a problem that was previously unsolved. Thank you very much. I'm available at manucorporat [?] on Twitter, so please follow me and ask me questions, whatever you want. Have a beer, have a good time. Cheers.