Welcome to the Qwik Academy!
In this post, you are going to get a birds-eye view of the Qwik framework, focusing on it's most unique design characteristics.
Let's focus specifically on the main questions that you probably have:
- Why Qwik?
- Why another framework?
- In what way is Qwik different than other frameworks?
Here are the 5 key distinctive features of Qwik:
- Server-side rendering by default: Qwik server-side rendering works out of the box, without special configuration or extra libraries. Server-side rendering is the default, you don't have to turn it on.
- Resumability: Qwik applications are resumable, meaning that they continue on the client where the server left off, so the client does not have to re-render the component tree again after page load (no flickering effects, etc.). There is no need to do manual state transfer between the server and the client, Qwik takes care of that transparently.
- Fine-grained, automatic lazy-loading: Lazy loading is completely automated, and done transparently by the framework. Qwik decides the lazy loading boundaries of the application at build time transparently, and splits up the application into fine-grained chunks. For example, the code for a click handler can be lazy-loaded only when the button is clicked for the first time.
There is a lot to unpack here.
So in the rest of this post, let's cover the first 4 items on this list, because they are all closely related and I don't think it's possible to explain them well separately (reactivity will be in a separate post).
As you will see, although Qwik is superficially similar to React (as it also uses JSX), but under the hood it works in a completely different way.
So without further ado, let's dive right in. 😊
What is Qwik?
Qwik is a web framework that allows developers to build instant-loading websites and apps.
I think the main and most defining characteristic of Qwik is its blazing speed, combined with its very familiar, React-style developer experience.
It's a next generation framework in terms of performance, but it comes with an API that is very familiar to a lot of developers, so the learning curve to transition to it is going to be small for many of us.
Qwik was created by Miško Hevery, that also created the Angular framework at Google, as well as the original AngularJs.
Qwik is the only web framework currently capable of getting you a 100% score on Lighthouse, a popular Google tool used to measure the speed and usability of a web page.
And that happens to be extremely hard to pull off!
How important is the perceived speed of an application?
Application speed is crucial for commercial products, it's not just a nice to have.
For example, in e-commerce pages, with a 0.1 seconds improvement in site speed, it was noticed in this study that retail consumers spent almost 10% more.
As you can see, the commercial incentive is there to create way faster applications than what we have today.
We just needed the technology to do it, which we didn't have... until now. 😉
So let's go through the list of key innovations of Qwik, starting with the way it handles server-side rendering.
Improved Server-side Rendering By Default
Server-side rendering in Qwik has several unique advantages and solves several problems that most current server-side rendering solutions have.
But what is server-side rendering exactly?
As you know, the best way to make an application feel faster, is to serve some HTML from the server on the initial request, when the application is initially loaded.
This way, some HTML and CSS can be immediately shown to the user as fast as possible, while we wait for the rest of the application to be ready.
With Qwik, not only do we have server-side rendering available, but it's actually on by default.
In Qwik, server-side rendering works out of the box immediately for a new application, without you needing to do any special configuration or install an extra set of libraries.
But more important than having server-side rendering by default, is that the server-side rendering of Qwik generally works better when compared to previously available solutions.
Here are the 2 main ways in which Qwik server-side rendering is different:
- Automatic state transfer: There is no need for the developer to manually transfer state between the server and the client, that is done by Qwik automatically.
- applications are resumable: the frontend picks up where the server left off, and there is no duplication of work between the server and the client.
Both of these features (which are connected) have to do with a very important property of Qwik applications: they are resumable.
Understanding Qwik Resumability
The resumability feature is unique to Qwik, and it gives to Qwik applications some truly unique performance characteristics.
Resumable server-side rendered applications have several important user experience and performance advantages over non-resumable applications.
But what does it mean for a Qwik application to be resumable?
An application is resumable if get's initially rendered on the server, and then it resumes itself again on the browser, picking up right where the server left off.
In a resumable application, there is no repeated work that the client application has to do at page load time, that the server already did on the initial render.
I think the best way to understand what a resumable application is, is to give you first an example of what a non-resumable application looks like, and talk about the potential problems that it usually has.
After that, I'm going to compare that to a Qwik application, and show how those problems are solved by Qwik.
An example of a non-resumable application
So here is an example of a non-resumable application. Imagine a simple application that renders a page with a list of course objects.
Here is the HTML for that list of courses:
This HTML is initially server-side rendered, added to the page and then served to the browser.
Notice that this course data came from the database, and was fetched during server-side rendering via a GET /api/courses HTTP request.
The browser then receives this HTML payload and displays it to the user.
The rendered output also includes the client application
That bundle usually contains:
- a good amount of framework code
This script essentially contains the client-side version of the application plus the framework code needed to run it.
All of that code is getting sent over the wire together with the initial HTML payload.
The client application needs to take over the page on the client side
The framework will then re-render the whole component tree.
And for that it might try to fetch again from the server the same data via a second HTTP GET request to /api/courses.
Once the whole component tree gets re-rendered on the client, that newly generated DOM will then replace all the content already on the page.
But the new content produced by the client application, and the initial content rendered on the the server that it now replaces are exactly the same.
Depending on how you code the application and how you style it, you might notice a strange "flickering" effect, where you see for a second that some of the existing content already visible "blinks", as it gets replaced with the new content generated by the client application.
There are really two applications working separately: the client and the server applications
As you can see, the client application that gets bootstrapped onto the browser will have to repeat all the rendering work already done on the server.
It will have to -render the component tree all over again from scratch and replace it on the page.
This ends up being a waste of time and resources, because the client application will generate the exact same HTML as the server already rendered, and then replace it.
Meanwhile, the user is waiting for all that process to finish before being able to interact with the page.
As we can see, what we have here is not a single application at work.
What we really have are two separate applications that work independently:
- one application on the server, taking care of the initial HTML render, and adding the client application as a script to the page
- another application on the client, that takes over the page and renders everything all over again (the bundle.js script)
This type of server-side rendering is non-resumable, because the client application has to redo all the work and render everything all over again, while the user waits.
The client application doesn't just take the rendered HTML by the server, and picks up where the server has left off.
No, for the client-side application it's like the initial server-side rendering never happened in the first place!
The client application behaves just like it's a standard single page application, with no server-side rendering involved at all.
It just takes over the page, and re-renders everything from scratch.
Let's talk about a couple of problems that this type of non-resumable server-side rendering has:
- high time to interactive
- need for manual state transfer between server and client
After understanding these two problems, let's talk about how Qwik solves them.
Why do non-resumable applications have low Time To Interactive?
The Time To Interactive is the first possible moment when the user can interact with the application.
So this usually happens way after the DOMContentLoaded event.
This is a very different measurement that the Time To First Paint, which is a measurement of how fast the user can see something on the screen (other than a completely blank page).
Both resumable and non-resumable server-side rendered applications do something about the Time To First Paint, because both solutions can deliver a full page of HTML to display to the user.
Also, the component tree of the application also needs to be re-rendered, and the HTML created on the server needs to be replaced.
And that re-rendering process takes time.
So it's clear that a non-resumable application simply can't do much about lowering the Time To Interactive, because it still needs to do all that bootstrapping and rendering work before taking over the page.
The Time To Interactive of a non-resumable server-side rendered application is essentially the same as a regular single page application, with no server-side rendering involved.
This issue of a high Time To Interactive is addressed by Qwik, via its resumability feature.
But before explaining how that works, let's cover another important problem that non-resumable applications also have, which relates to state transfer.
Understanding the need for manual state transfer
To understand this common problem that current server-side rendering solutions have, let's take that same sample application that renders a list of course objects.
This list of courses was taken from the database, via a call to GET /api/courses, and the list was rendered into HTML on the server.
Now the application is bootstrapped on the client, and this list of courses component gets re-rendered again.
We know that we can't do much about preventing the re-rendering, because that is just how a non-resumable application works.
But it would be ideal to at least not have to do that same HTTP request one more time, to fetch the same data from the server again, just to be able to finish the bootstrapping process of the client application.
This is where the need for state transfer comes in.
We need a way for the server to store the data somewhere on the HTML page (as serialized JSON), so that the data can be easily retrieved by the client application.
This way, we would at least avoid having to call the backend again to re-fetch the exact same data.
Ideally, this state transfer should happen automatically without the developer intervention.
If possible, the developer should not have to write code that takes care of this transfer of application data between the server and the client.
But that is not the case in many existing server-side rendering solutions: the developer usually does need to take care of this state transfer manually on a case-by-case basis.
Summary of the problems of current server-side rendering solutions
We have talked so far about two well-known problems that are present today in many existing server-side rendering solutions.
Let's summarize them:
- the client application needs to repeat all the rendering work done by the server, wasting resources and delaying the client application startup
- the developer has to manually transfer the data between the server and the client, on a case-by-case basis.
So these are the two main problems.
And as you can imagine, Qwik solves all of these problems in one go. 😉
How Qwik Resumability solves all these problems
With Qwik, both the problems of low time to interactive and the need for manual state transfer are solved.
To understand how resumability works, we will first need to understand what is the Qwik Loader.
Lowest Possible Time To Interactive, and The Qwik Loader
So here is how resumability works in Qwik, and this is maybe the most unique aspect of framework.
Instead, Qwik only includes on the page a tiny bit of framework code, called the Qwik Loader.
This is a tiny script of around more or less 10 Kb, that gets included inline in the body of the HTML page. Including it inline avoids an extra HTTP request.
Here is what the Qwik loader looks like, in the body of a rendered Qwik page:
The good news is that not only the Qwik Loader script is tiny, but also it remains constant in size as your application grows.
Which is quite mind-blowing! 😉
Usually, the more features we add to an application, the more the initial bundle size grows over time, as we add more features over time, right?
This means that a non-resumable application typically gets slower over time.
But with Qwik, only the Qwik Loader needs to be served in the initial HTML payload, no matter the size of the application or how many features you add to it.
So Qwik applications start fast initially, and they remain fast as you add more features to them over time.
This explains how Qwik solves many of the problems highlighted before, which we usually see in previous server-side rendering solutions.
Understanding why Qwik has such a low Time To Interactive
I think it's now becoming now clear how Qwik achieves its baseline performance in terms of application startup time.
This is how Qwik gets a 100% lighthouse score every time, just like if it were a plain static page with just HTML and CSS.
The reason for that, is that a Qwik application, when it starts up, it actually is almost just a plain static page.
So no wonder that it scores just like a static page! 😉
This means that a Qwik application starts up almost instantly, and is ready to interact almost immediately.
Understanding Qwik state transfer between server and client
Another reason why Qwik applications are resumable, is that any state that you need to re-render a component is transferred between the server and the client automatically by the framework.
So the client application does not need to fetch the same data that the server just fetched a moment before during the initial server-side render.
For example, here is a simple Qwik component, that stores some data using a Qwik store (an article on stores will be coming out soon).
A store is just a state container where you can store your data, and track its changes.
Qwik components will know when to re-render themselves as the data inside a store changes over time:
The component just keeps a list of messages in a store, and prints out to the screen the currently selected message, according to an index.
Imagine that these messages are coming from a backend, instead of being hardcoded.
When the component gets initially rendered on the server, these messages are turned into plain HTML and served to the browser, as you would expect:
But not only that, but the content of the store itself is serialized and added to the page, under the form of JSON:
As you can see, during the server-side rendering process, the server has appended the state of the component store to the page, under the form of JSON.
This way, when the application resumes its execution on the browser, it will find all the state that it needs already in the store, without having to call again the backend.
So as you can see, Qwik takes care of transferring any application state between the server and the client automatically,
There is no need for you to manually transfer the state between the client and the server using some special API.
You just write a component, and Qwik does the state transfer for you automatically. 😉
Automatic state transfer is just one of the aspects that make Qwik applications resumable.
I bet that at this point you are probably thinking:
- What does the Qwik loader do exactly, what is it for?
- And where is all the application component code, if it's not part of the Qwik loader?
- and how will the component code get to the browser, once the user starts interacting with the application?
All of this will be explained next, as we introduce the last piece of the puzzle: Qwik lazy loading.
Qwik Fine-Grained, Automatic Lazy-Loading
So here is what the Qwik Loader does, when the application first starts.
The Qwik Loader is a very small framework script, and all it does it detect browser events on the page, such as for example click events.
Let's say that for example, you have that same component that has a click handler:
You would be surprised to find out that the code for handling this event is not loaded to the browser when the page first loads.
This code is only pulled from the server by the Qwik Loader when the code is really needed, only after the button gets clicked for the first time!
Only when we click that button for the first time will the Qwik loader pull the click handling code from the server in its own separate lazy-loaded file:
The Qwik Loader will know when to lazy load each and every part of your application, and it will only pull that code at the last possible moment, and only if it's really needed.
If you check the content of that highlighted file that Qwik just loaded, here is what you will find inside:
As you can see, this lazy-loaded file contains just the click handling code, and not much more.
But this code was only fetched from the server in response to the first click of the user on that particular button.
If in that particular user session the user never clicks that button, its click handling code will never be loaded, and the user will not pay for the performance penalty that comes with having to load and parse that code.
How the Qwik Loader handles lazy loading
So as you can see, the Qwik Loader is one of the main design elements of the framework that enables Qwik applications to be resumable.
It's the Qwik loader that knows exactly what parts of the application to pull from the server, in order to allow the application to resume it's execution from the state where the server left off.
The Qwik loader will not load the whole tree of components at startup time, like it usually happens in many other frameworks, and there is no need to re-render the tree of components, after the Qwik Loader is active on the page.
The Qwik Loader is a small script of constant size, and it contains no application code at all. This is the only script that a Qwik application loads at startup time.
This is why a Qwik application doesn't get slower over time, as you add more features to it.
No matter how many features you add, the Qwik lazy loading mechanism is going to automatically and transparently split everything up into small chunks, without the developer's intervention.
And the Qwik Loader will then fetch from the server on demand only the parts of the application that are needed, depending on how the user interacts with the application.
But the question now is, how does the Qwik Loader know what to load from the backend?
Understanding QRLs, or Qwik URLs
The Qwik Loader can determine what scripts to load from the server in response to an event like a button click, by checking information that was serialized into the HTML when the application was rendered on the server.
For example, in the case of our click handler, the button has this strange-looking attribute associated with it:
<button on:click="/src/stores_component__fragment_button_onclick_xgedka8tbxg.js#stores_component__Fragment_button_onClick_xgedKA8TbXg"> Next Message
This attribute contains a QRL, which is short for Qwik URL.
This is a specially formatted URL that tells the Qwik Loader what lazy-loadable script to load in response to a click event on that button, and what code to grab from inside that file.
As you can see, the QRL works a bit like a dynamic import, as it tells Qwik what code to import dynamically at runtime.
You can think of a QRL as a serializable representation of a dynamic import, that the Qwik Loader reads and parses in order to know what code to lazy-load from the server and run it.
As you can see, the design of the Qwik framework is very innovative.
It all fits together quite nicely:
- server-side rendering out of the box
- the fine-grained lazy-loading mechanism
- and the new reactive DOM update system
This all combines together to give Qwik applications the maximum possible perceived speed and performance, both at page load time and at runtime.
The main characteristic of Qwik is really its blazing speed!
The perceived performance as seen by the user is just on another level, close to a static page.
The developer experience feels super familiar to React developers, and the development environment is super easy to use.
I think Qwik is going to make a large impact on the frontend development world in the next years to come, due to it's unique design and performance characteristics.
The familiarity that it brings to React developers is also a huge benefit of Qwik.
If you know React, you almost already know Qwik, as the whole JSX developer experience will ring very familiar to you.
To conclude, let's summarize the key innovations of Qwik:
- server-side rendering by default
- automatic server to client state transfer
- resumable applications with low Time To Interactive
- fine-grained automatic lazy loading
- fine-grained reactive rendering system
I hope this post helped, and that you enjoyed it. If you are interested in learning more about Qwik, do make sure to subscribe to my Qwik newsletter:
Let me know in the comments section below if this post covered what you were looking for, if you have any other questions, and what else would you like to learn about Qwik?
Let me know and I might just write a post about it. 😉
I'm looking forward to hearing from you.
Founder of OnlineCourseHost.com