Speeding Up Your React App With Less Javascript

Rate this content
Bookmark

Too much JavaScript is getting you down? New frameworks promising no JavaScript look interesting, but you have an existing React application to maintain. What if Qwik React is your answer for faster applications startup and better user experience? Qwik React allows you to easily turn your React application into a collection of islands, which can be SSRed and delayed hydrated, and in some instances, hydration skipped altogether. And all of this in an incremental way without a rewrite.

Miško Hevery
Miško Hevery
15 min
23 Oct, 2023

Video Summary and Transcription

Quick React is a tool that speeds up React applications with less JavaScript, and Builder.io is a visual CMS that empowers marketing teams. Web performance is a challenge, with most websites scoring poorly. Island architecture and reasonability are alternative approaches to hydration that improve performance. QUIC allows for resumable applications and Quick React enables island architecture for faster startup times. Hydration and inter-island communication are crucial for interactivity in React applications.

Available in Español

1. Introduction to Quick React

Short description:

Let's talk about Quick React and how it can speed up your React application with less JavaScript. Builder.io is a headless visual CMS that allows you to register existing React components and empower your marketing team with a visual editor. Builder.io also offers Partytown, which runs third-party code in web workers, and Mitosis, which generates idiomatic code for different frameworks.

Let's talk about Quick React, and specifically how to speed up your React application with less JavaScript.

Hi, my name is Misko Hevery, I'm a CTO at Builder.io and I've built these previous projects called Angular, and today I'm working on a project called Quick, and I want to specifically show you how Quick can be used to make React applications into smaller islands and load faster.

So I work for Builder.io, Builder.io is a headless visual CMS. What it means is that you can take your existing React application and do npm install builder into it, and once you install builder, you can register existing React components in your applications that you have, and that allows your marketing team to have a visual editor and they can drag and drop your components onto the page, and from the components they can change things, schedule when things go live, publish and send the data to the website. So you don't have to, as an engineer, be involved in every single small change.

We have an awesome team of open source contributors. First of all, Builder.io loves open source, so in addition to Quick, we have Partytown, which provides a way to run third party code, such as Google Analytics, inside of the web worker, which frees up the main thread to handle the application, makes the application more responsive. We also have Mitosis, which allows you to write your components in one style, and then those components get translated into all of the existing frameworks. So if you have a company where there are many teams using different frameworks and you want to have common design systems across everybody, Mitosis is a way to do it. The thing to do to understand about Mitosis is it's not a wrapper, over existing web components or anything like that. It actually generates idiomatic code for all different frameworks. And of course, we have these three awesome gentlemen who are working on the open source, Adam Bradley, who's creator of Ionic, Manu Martinez, Almeda, who also worked on Ionic and GEN, and finally, Sam Jaber, who's working on Mitosis.

2. Challenges with Web Performance

Short description:

Our web is awesome, but it's not as fast as it should be. Google scores websites based on user experience, and most websites score in the red. It's difficult to achieve good performance.

Now, the thing I want to talk to you about is that our web is awesome, but it's not as fast as it should be. And Google cares about this, and they see that the users leave sites that don't perform as well. And so Google scores websites, and they have something called Core web vitals. And this is actually recorded on what kind of a user experience people have when they use the Chrome browser. And as you can see, that most websites actually get scored in the red. Only the websites that spend the most amount of time and energy can get yellow, and almost no website, actually, that I've seen in production that have real traffic are managing to get green. So what is going on? Why is it so difficult to get good performance?

3. Enhancing Web Interactivity and Performance

Short description:

The applications of today are more interactive and rich than they were 10-20 years ago. Frameworks that perform the best in terms of Lighthouse core also ship the least amount of code. However, we still need to ship code to make the application interactive. Server-side prerendering may appear faster, but it still requires downloading, executing, and rendering the application. The interactivity is actually slower because of duplicate amounts of information being sent. Hydration starts at a root component and recursively executes components, learning about listeners, state, and component boundaries.

And the reason for this increase is because the applications of today are a lot more interactive, lot more rich than they were 10, 20 years ago, and so we would expect that this particular trend would continue.

Now, unsurprisingly, I've picked a couple of frameworks on the left and show you what is their average performance that Google sees on the website. And on the right hand side, I'm showing you how much code these frameworks are shipping to the client. And notice that the frameworks that perform the best in terms of Lighthouse core also shipped the least amount of code. Again, this shouldn't be surprising because it basically tells you that, hey, the less code you ship, the easier it is for the browser to interpret it, execute it, and make the website interactive.

Now, the problem is that we need to ship code. We need to ship code in order to make the application interactive, and so we do this through this process called hydration. And the way hydration works is it starts with HTML, which essentially is a blank page first. And we'll talk about server-side rendering in a second. The JavaScript loads, the JavaScript then executes, then causes a rendering, and at this point, you actually have an actual interactive website. And it is at this point where you can go and click on it and perform operations.

Now, the problem is that we have this blank page at the very, very beginning, and so people started to do server-side prerendering. And so with server-side perendering, or SSR, or SSG, you end up with HTML, and the HTML now has a image that you can go and look at, but you can't really interact with it, right? And so there is an appearance of it being faster because the page actually appears faster for the user, and so that provides a better user experience. But it still has to download all of the JavaScript, it still has to execute all of the application, and it still has to render the application, except now we don't call that rendering. Instead we call it reconciliation, because we're trying to reuse as many DOM elements as possible inside of the UI. And so it is only at this point that the application becomes interactive. And notice what's actually happening, is that the interactivity is actually slower, have you said no content at the beginning at all. And so it's a bit of a dichotomy that we appear faster, but we're actually slower. And the reason for that is because we're actually sending more information, we're sending duplicate amounts of information. If you think about it, if you take a string, like visually built on your tech stack that you see in the image, that string actually appears twice. Once in HTML and once in JavaScript. And so this duplication actually means that you have to send more stuff to the client, the client has to process more stuff. And the end result is that there is a... that it takes longer for the application to wake up. Now, hydration, if you think about it, what it is, is that you start at a root component. And as this new root component gets processed and executed, hydration learned, the framework learns about other components, in this case, these three. And so it recursively goes and executes these components and learns about more components. And as it does so, it learns about the listeners. And it's the listeners that we actually care about. Listeners, state, and the boundaries of the components is the information that we need in order to make the application interactive.

4. Island Architecture and Reasonability

Short description:

Listeners, state, and the boundaries of the components are crucial for making the application interactive. Alternative approaches to hydration, such as Partial Hydration and React Server Components, break the application into islands, allowing for better performance and user experience. Reasonability, popularized by frameworks like QUIC, provides a middle ground by combining hydration and reasonability. Island architecture, exemplified by frameworks like Astro and Fresh, offers a way to achieve reasonability without changing the framework. Quick enables island architecture for React applications, providing faster startup times. Reasonability starts with HTML, containing the necessary information for the framework, making the page immediately interactive.

Listeners, state, and the boundaries of the components is the information that we need in order to make the application interactive. And so, because this takes a lot of time and all the application has to be present, people are looking for alternatives to hydration.

And so there are different variations on it. The one is called a Partial Hydration, in which case you turn everything into islands. And so the idea is that you recognize that this particular island is not interactive and therefore there's no need to download and execute it on the client. Whereas this island is super small and can be woken up so quickly that maybe you can do it just on click interaction, maybe this island is a little bigger. And so you have to do it on idle or on visible to get the best possible performance. But by breaking the application into islands, it allows you to not overwhelm the browser or at the beginning and what gives a better user experience.

Another form of this is React Server Components, which if you think about it, are kind of like islands except that instead of being treated as independent applications, they're actually treated as a one unified application, because some of the VDOM is computed on a server and just sent to the client and therefore the client doesn't have to re execute that portion of the component. And the only thing that the client has to execute are the components that are actually interactive. So we have kind of extremes, right. On one extreme, we have just basic hydration, which Angular and React and other frameworks do. And on the other extreme, we have this idea of reasonability. We'll talk about it a little more and frameworks like QUIC have popularized it, but QUIC by no means is the first one. Google has a framework called Wiz that has been doing reasonability for about the past 10 years. And Marco has a framework. Sorry, eBay has a framework called Marco which in the latest version 6, they also provide reasonability for your applications as well. And all that means that the applications essentially get to start up faster. But there is this middle ground which is basically islands and islands says, Hey, I can basically still do reasonability, which means I don't have to change my framework. I have to do still hydration, which means I don't have to do my change my framework and still do what I have done before. But instead of doing a hydration on the whole thing, as I said, we can do a smaller chunks. Now this has been popularized by frameworks such as Astro and currently a framework called Fresh. But what I want to show you is that you can also get island architecture for your React application with Quick. And so that's what we're going to talk about in a second.

Now, reasonability is a bit different than hydration in that it reasonably starts with HTML. You get a page, but the page already has all the information needed for the framework. Now, doesn't mean that it has all of the code of the application. It would be too large to serialize into the page, but it has information about where the listeners are and what code needs to be downloaded when you go and interact with one of these listeners. And so as a result, the page is immediately interactive. Now, not only does it appear faster, it actually is faster and you immediately start downloading the JavaScript that if the user goes and interacts, there will be no delay on interaction.

5. QUIC Installation and Component Building

Short description:

QUIC allows you to resume the application where it left off, eliminating the need for re-execution or reconciliation. Install QUIC City and Quick React, then build a Hello World component and a counter in React. QUICify function turns the component into an island, allowing resumability with zero cost.

And notice that the amount of JavaScript you download is much much smaller. And that because you resume, you don't have to re-execute all the components. Most of these components can be removed because they're actually duplicate information. And so with resumability, you don't have the double-download problem that exists in Hydration. And as a result, there is no need to re-execute the application or do any sort of reconciliation. The application simply just continues where it left off.

So let me give you a demo. So let's start off by installing QUIC. So you do npm create QUIC at latest. This contains a meta-framework, which we called QUIC City. So let's install QUIC City in there as well, install the dependencies, git, and so on, and you're ready to go. The second step is to install Quick React. So this is a wrapper that allows QUIC to use React components. As you can see, we can install QUIC and add a React integration, go through all the steps, and set everything up. And now we're ready to go and build something in QUIC.

So let's build a Hello World to see what a Hello World looks like. On the right hand side, I have a React component that you can see. Notice at the top, there is a pragmat that says JSX import source react. This tells the compiler that hey, this is a React code, make sure you deal with JSX in a way that React likes it. And we create a basic component using the function greetings. Now the thing that QUIC adds is that it allows you to take the greetings component and run through a QUICify function to get a QUICify QUIC version of this particular component. Now this is a runtime wrapper, this is not a translation, so you have, you'll get the same exact behavior as before. You don't have to worry about compatibility or anything of that sort. But in practice, what it means, is that it turns the component into an island. So because QUIC is resumable, it essentially can start up with zero cost, but now your greetings component has cost that under some conditions, we, you will have to execute and hydrate. In this particular case, the greetings actually never hydrates because there's no signal to the, to QUIC, to tell it, hey, it has to be hydrated. And if you think about it, this makes perfect sense because in this case, greetings is indeed and therefore there's no need to do anything with it. Now let's do something more complicated. Let's build a counter. So let's build a counter in React and you can see, you have a button and you can click on it, which changes the state and updates the count.

6. Hydration and Inter-Island Communication

Short description:

We create an island of React inside an existing application by quickifying the counter. Hydration is necessary to make the code interactive, and it can be triggered by specific conditions like hovering over a button. Inter-island communication is crucial, and we demonstrate it with two islands: a button and a display. The state transitions between the islands, and Quick owns this state. Lazy hydration allows components to hydrate based on changes in inputs or props. Different methods like hover, load, idle, visible, click, signals, and property changes can wake up the system.

And again, we're going to go and quickify the counter to get a component and then, you know, embed it inside of a larger application. So we create an island of React inside of an existing application. Now if you go and click on it, notice nothing happens. And that is because the code isn't hydrated. So you need to tell the system like, hey, under which conditions does this particular island have to be hydrated? And the way you do that is through this eagerness property. So in this particular case, we have the same piece of code. And now we're saying, hey, you know, when you hover over this particular button, which means you're very likely to about to click on it. By the way, there's other ways of doing it. Go ahead and hydrate the component. So if you look at what's happening is there is now React going on. When you hover, you can see that the React DevTools have been downloaded and they have initialized and we have downloaded the necessary code. And because it has initialized, you can see that the React counter has been rendered. And now that it's rendered and hydrated, you can go and interact with it and everything works exactly as you would expect.

Now, one of the important things about islands is that you need to solve the inter-island communication problems. These islands are effectively independent React applications and they need to be able to talk to each other. So what I'm going to show you here is that you have two islands, one is a button and another one is a display. In a button case, we are going to, again, quickify it by running it through a quickify function. And we're going to specify eagerness hover, which means that as soon as I hover over the particular button, I want the button to hydrate. In a case of a display, we're not specifying any sort of hydration at all. What happens on the client side is that we need to have a state that transitions from both the button and the display. In this state, because it is owned on a way that it's two separate islands, it really has to be owned by Quick. So Quick now has a state, and this state is passed both to a button, which is hydrated on hover, but also to the display. Notice what happens in here. When I go and hover over the button, you can see the DevTools come up and the React button is being rendered. But now when I go and I click on it, the actual act of clicking... First, there is just a button, and then if you go back and you click on it now, now you can see that, hey, the React display has hydrated and executed as well, and so now we have this lazy hydration situation where the button hydrates eagerly, but the display only hydrates when the inputs or the props of it change. And if you think about it, this is exactly how React works underneath it, but we're emulating the same exact thing with signals and islands as well.

Now, just to point out, you know, a hover is not the only way to wake up the system. You can do it on load, idle, visible, click our parameters, and when you wake up things, you can also wake things up using signals or property changes, as we have shown.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

A Guide to React Rendering Behavior
React Advanced Conference 2022React Advanced Conference 2022
25 min
A Guide to React Rendering Behavior
Top Content
React is a library for "rendering" UI from components, but many users find themselves confused about how React rendering actually works. What do terms like "rendering", "reconciliation", "Fibers", and "committing" actually mean? When do renders happen? How does Context affect rendering, and how do libraries like Redux cause updates? In this talk, we'll clear up the confusion and provide a solid foundation for understanding when, why, and how React renders. We'll look at: - What "rendering" actually is - How React queues renders and the standard rendering behavior - How keys and component types are used in rendering - Techniques for optimizing render performance - How context usage affects rendering behavior| - How external libraries tie into React rendering
Speeding Up Your React App With Less JavaScript
React Summit 2023React Summit 2023
32 min
Speeding Up Your React App With Less JavaScript
Top Content
Too much JavaScript is getting you down? New frameworks promising no JavaScript look interesting, but you have an existing React application to maintain. What if Qwik React is your answer for faster applications startup and better user experience? Qwik React allows you to easily turn your React application into a collection of islands, which can be SSRed and delayed hydrated, and in some instances, hydration skipped altogether. And all of this in an incremental way without a rewrite.
React Concurrency, Explained
React Summit 2023React Summit 2023
23 min
React Concurrency, Explained
Top Content
React 18! Concurrent features! You might’ve already tried the new APIs like useTransition, or you might’ve just heard of them. But do you know how React 18 achieves the performance wins it brings with itself? In this talk, let’s peek under the hood of React 18’s performance features: - How React 18 lowers the time your page stays frozen (aka TBT) - What exactly happens in the main thread when you run useTransition() - What’s the catch with the improvements (there’s no free cake!), and why Vue.js and Preact straight refused to ship anything similar
The Future of Performance Tooling
JSNation 2022JSNation 2022
21 min
The Future of Performance Tooling
Top Content
Our understanding of performance & user-experience has heavily evolved over the years. Web Developer Tooling needs to similarly evolve to make sure it is user-centric, actionable and contextual where modern experiences are concerned. In this talk, Addy will walk you through Chrome and others have been thinking about this problem and what updates they've been making to performance tools to lower the friction for building great experiences on the web.
Optimizing HTML5 Games: 10 Years of Learnings
JS GameDev Summit 2022JS GameDev Summit 2022
33 min
Optimizing HTML5 Games: 10 Years of Learnings
Top Content
The open source PlayCanvas game engine is built specifically for the browser, incorporating 10 years of learnings about optimization. In this talk, you will discover the secret sauce that enables PlayCanvas to generate games with lightning fast load times and rock solid frame rates.
When Optimizations Backfire
JSNation 2023JSNation 2023
26 min
When Optimizations Backfire
Top Content
Ever loaded a font from the Google Fonts CDN? Or added the loading=lazy attribute onto an image? These optimizations are recommended all over the web – but, sometimes, they make your app not faster but slower.
In this talk, Ivan will show when some common performance optimizations backfire – and what we need to do to avoid that.

Workshops on related topic

React Performance Debugging Masterclass
React Summit 2023React Summit 2023
170 min
React Performance Debugging Masterclass
Top Content
Featured WorkshopFree
Ivan Akulov
Ivan Akulov
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
Building WebApps That Light Up the Internet with QwikCity
JSNation 2023JSNation 2023
170 min
Building WebApps That Light Up the Internet with QwikCity
Featured WorkshopFree
Miško Hevery
Miško Hevery
Building instant-on web applications at scale have been elusive. Real-world sites need tracking, analytics, and complex user interfaces and interactions. We always start with the best intentions but end up with a less-than-ideal site.
QwikCity is a new meta-framework that allows you to build large-scale applications with constant startup-up performance. We will look at how to build a QwikCity application and what makes it unique. The workshop will show you how to set up a QwikCitp project. How routing works with layout. The demo application will fetch data and present it to the user in an editable form. And finally, how one can use authentication. All of the basic parts for any large-scale applications.
Along the way, we will also look at what makes Qwik unique, and how resumability enables constant startup performance no matter the application complexity.
Next.js 13: Data Fetching Strategies
React Day Berlin 2022React Day Berlin 2022
53 min
Next.js 13: Data Fetching Strategies
Top Content
WorkshopFree
Alice De Mauro
Alice De Mauro
- Introduction- Prerequisites for the workshop- Fetching strategies: fundamentals- Fetching strategies – hands-on: fetch API, cache (static VS dynamic), revalidate, suspense (parallel data fetching)- Test your build and serve it on Vercel- Future: Server components VS Client components- Workshop easter egg (unrelated to the topic, calling out accessibility)- Wrapping up
React Performance Debugging
React Advanced Conference 2023React Advanced Conference 2023
148 min
React Performance Debugging
Workshop
Ivan Akulov
Ivan Akulov
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
Maximize App Performance by Optimizing Web Fonts
Vue.js London 2023Vue.js London 2023
49 min
Maximize App Performance by Optimizing Web Fonts
WorkshopFree
Lazar Nikolov
Lazar Nikolov
You've just landed on a web page and you try to click a certain element, but just before you do, an ad loads on top of it and you end up clicking that thing instead.
That…that’s a layout shift. Everyone, developers and users alike, know that layout shifts are bad. And the later they happen, the more disruptive they are to users. In this workshop we're going to look into how web fonts cause layout shifts and explore a few strategies of loading web fonts without causing big layout shifts.
Table of Contents:What’s CLS and how it’s calculated?How fonts can cause CLS?Font loading strategies for minimizing CLSRecap and conclusion
High-performance Next.js
React Summit 2022React Summit 2022
50 min
High-performance Next.js
Workshop
Michele Riva
Michele Riva
Next.js is a compelling framework that makes many tasks effortless by providing many out-of-the-box solutions. But as soon as our app needs to scale, it is essential to maintain high performance without compromising maintenance and server costs. In this workshop, we will see how to analyze Next.js performances, resources usage, how to scale it, and how to make the right decisions while writing the application architecture.