Meta-frameworks such as Next.js, SvelteKit and Astro are currently the talk of the town. These handle certain tasks relating to hydration, which speeds up start-up time and allows users to interact with websites more quickly. Qwik takes this approach a step further and introduces ‘Resumable’. But what exactly is ‘Resumable’, and what other concepts underpin this framework?
Contents
With Single Page Applications (SPAs), rendering takes place on the client side. This means that the HTML page, including the JavaScript used, must be downloaded before a user can interact with a web page. Experts refer to this point in time as the First Meaningful Paint (FMP). To improve the FMP, other frameworks utilise hydration. Hydration is the process whereby event listeners are added to the DOM, the component treeis constructed and the application state is restored. Qwik simplifies this process by ensuring that all the necessary information is already present in the HTML, meaning no client-side adjustments are required. This concept is known as ‘resumable ’.
Figure 1: Hydration vs. Resumable [1]
To understand Qwik and the concepts behind this framework, we need to look at the history of web development. This can be broken down as follows:
Qwik is a JavaScript framework that loads only the absolute minimum amount of JavaScript. Just 1 kilobyte of JavaScript is required for a web page to be interactive or for the First Meaningful Paint (FMP) to be achieved. JavaScript itself is only loaded when it is required for a user action. This concept is known as ‘progressive loading ’. In the example below, the required JavaScript is only loaded when the ‘increment’ button is clicked, and the counter is subsequently incremented. The $ symbol tells Qwik that JavaScript should only be loaded on demand.
Figure 2: Example of a Qwik component
As a result, the bundle size does not subsequently increase linearly with the size of the project, but remains constant, as shown in the diagram below.
Figure 3: Bundle size versus project size [2]
The conceptsof ‘resumable’and‘progressive’are Qwik’s greatest assets. But how does Qwik manage to build the component tree quickly and effectively, and how does reactivity work in Qwik? Qwik uses signals, which enable finely granular reactivity, ensuring that only those parts of the component tree that have changed are re-rendered. Unlike other frameworks, this does not involve using a compiler or registering listeners; instead, proxies are utilised. These proxies generate serialisable subscriptions, which are used for re-rendering. In the example below, `useStore` is used to create such a proxy. As soon as the user clicks the button, the relevant JavaScript is downloaded and the affected part of the component is re-rendered. It is important to note that only those parts of the code affected by the action are reloaded. Suppose there were a second counter in the component shown; this would not be reloaded.
Figure 4: Counter component in Qwik
As can already be seen from the examples given, the syntax in Qwik is very closely modelled on React. The component templates are also similar to React’s, and JSX is used. However, only the syntax is the same; the underlying concepts differ from those in React. Qwik does not use a virtual DOM.
Qwik differs from other JSX frameworks as follows [3]:
But how does binding work using signals, and how can a condition for rendering be specified? As shown in Figure 5, binding is carried out via `bind:value`, and a condition can be specified using `isVisible.value`.
Figure 5: Qwik component with binding and condition
The concepts described are intuitive and improve not only start-up time but also runtime performance. But how can existing applications be migrated to Qwik? Qwik React was introduced for React applications. This enables React to be used within Qwik. The `qwikify$` function can be used for this purpose. Figure 6 shows how this works.
Figure 6: Using a React component in Qwik
For all other SPA applications, such as Angular, the entire application would need to be migrated to Qwik.
As the person behind Qwik, Miško Hevery, is regarded as the father of Angular, it is interesting to compare Qwik with Angular. Generally speaking, every Angular application is represented as a component tree, as shown in Figure 7. Furthermore, reactivity works differently to how it does in Qwik. In Angular, when a user action occurs, the component tree is traversed from the bottom up, and all components affected by the action are marked as ‘dirty’.
|
Figure 7: Change Detection in Angular |
In Figure 7, these are all the parent components of the component highlighted in yellow. Next, Change Detection (CD) triggers a tick, causing all components marked as ‘dirty’ to be re-rendered.
|
Signals were first introduced in Angular 16 – a new reactivity concept that has been progressively expanded in subsequent versions. This includes adjustments to the control flow as well as the integration of inputs, outputs and other elements into this new paradigm. As a result of this development, the use of zone.js is no longer strictly necessary (see https://medium.com/stackademic/angular-without-zone-js-embracing-zoneless-change-detection-82f2f1ceeb77)
A key advantage of Signals lies in their fine-grained reactivity: only those parts of the template where something has actually changed are re-rendered (see Figure 8). This leads to improved performance and a more efficient update strategy. However, this requires the use of the new control flow in combination with Signals.
Figure 8: Control Flow
Furthermore, Angular now offers a flexible, declarative way to dynamically reload parts of the template. What was previously only possible via routing with separate components can now be controlled directly within the template using defer blocks. Developers can specify when a particular block should be loaded – for example, when it enters the viewport, on a click, or after a defined timer has elapsed. Further details can be found in the official documentation at: https://angular.dev/guide/templates/defer.
To gain a practical insight into the new concepts and understand how modern Angular applications can be developed today, we recommend taking a look at the following reference repository:
👉 https://github.com/rmaiersilldorff/performance-example.git
The repository demonstrates:
New control flow
Use of the new @if, @for and @switch directives – clearer and more efficient than traditional ng-templates.
Signal-based inputs and outputs
Instead of the traditional @Input() and @Output(), the application uses input<T>() and output<T>().
Here, T is the data type (e.g. string, number, boolean, Todo, etc.).
This ensures reactive, type-safe and high-performance component communication.
Signals in the template
Direct use of signals in the view – for precise and efficient rendering.
Zoneless architecture
Implemented entirely without zone.js – lower overhead, clearer change detection.
In addition, Angular relies on hydration and is continually expanding this approach. Angular 16 introduced non-destructive hydration. This makes it possible to further enrich the HTML page rendered by the server, add event listeners and build up the application state, thereby avoiding the need for the client to reload the entire HTML page. Research is currently being carried out into progressive and partial hydration. These are intended to enable the loading of many small bundles, as opposed to a single large bundle.
Figure 9: Destructive vs. Non-Destructive Hydration
With the latest versions of Angular – particularly since version 17 – there have also been fundamental changes in the area of hydration. Angular now supports incremental hydration.
Incremental hydration is an advanced form of hydration in which certain parts of an application initially remain ‘dehydrated’ and are only gradually ‘hydrated’ as and when required – for example, when scrolling into the viewport, through user interactions or on a timer (see https://angular.dev/guide/incremental-hydration).
Qwik takes a new, innovative approach and is rightly regarded as a new generation of JavaScript frameworks. Not only is the absolute minimum amount of JavaScript loaded, but only 1 kByte of JavaScript is required to interact with a web page. Thanks to the simple integration of React components, a number of component libraries can already be used in Qwik. However, other SPA framework components are not supported. It remains to be seen whether Qwik will replace all existing frameworks and herald a new generation of JavaScript frameworks. The concepts behind Qwik would suggest so. Applications that are used predominantly on mobile devices, in particular, would benefit greatly from this.
At the same time, there have been significant developments in Angular’s recent versions, particularly in the areas of hydration and reactivity. Angular has borrowed and further developed some concepts from other SPA frameworks in this area to remain competitive. As a result, Angular is currently holding its own very well against new frameworks such as Qwik and continues to offer a powerful and tried-and-tested framework for modern web applications.
Sources
[1] https://qwik.builder.io/docs/concepts/resumable/
[2] https://twitter.com/QwikDev/status/1521202882124521472
[3] https://qwik.builder.io/docs/components/rendering/#jsx
This article first appeared in Red Stack magazine: https://www.doag.org/de/home/news/red-stack-magazin-inkl-business-news-nr-1-2024-ist-online/
You can find out more about the possibilities offered by bespoke software and systems for your business on our website.
Feel free to get in touch with us.