You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: packages/docs/src/routes/(blog)/blog/(articles)/qwik-1-14-preloader/index.mdx
+12-14Lines changed: 12 additions & 14 deletions
Original file line number
Diff line number
Diff line change
@@ -45,7 +45,7 @@ In comparison, the other frameworks need to execute at least all of the visible
45
45
46
46
In effect, this means that TTI on Qwik apps can often be as fast as ~5s on a slow 3G network connection, even for very complex applications. With hydration on the other hand, TTI often reaches ~20s on slow 3G on simple websites and 60s or more on more complex applications as it increases proportionally to the amount of components that need to hydrate.
47
47
48
-
### A long standing “Buffering” issue
48
+
### A long standing “buffering” issue
49
49
50
50
In Qwik 1.11.0 and 1.13.0, we fixed some long lasting bugs that were leading to “under-prefetching” and “over-prefetching under certain conditions. With those fixes, we made sure that all and only the bundles required for the user interactions available on a page are prefetched, therefore preventing any sort of network delays.
51
51
@@ -60,7 +60,7 @@ Thankfully, using a service worker isn’t the only way we can prefetch and cach
60
60
61
61
In Qwik 1.14, we've transitioned away from using a service worker in favor of a solution leveraging [`<link rel="modulepreload">`](<https://devdocs.io/html/attributes/rel/modulepreload>) as the new default.
62
62
63
-
The solution consists of a small script called the “Qwik Preloader”. Once it is downloaded on the client, it adds the `<link rel="modulepreload" href=”my-bundle.js#segment123456”>` to the html `<head>`, which tells the browser to preload and buffer the corresponding JavaScript bundles.
63
+
The solution consists of a small script called the “Qwik Preloader”. Once it is downloaded on the client, it adds the `<link rel="modulepreload" href=”my-bundle.js#segment123456”>` to the html `<head>`, which tells the browser to preload and buffer the corresponding JavaScript bundles.
64
64
65
65
By doing so, we not only get rid of any startup penalty, but also make any interaction on Qwik components absolutely instant once the bundles for it have been preloaded, even on devices with poor CPUs 🚀
66
66
@@ -80,11 +80,11 @@ On our tests on a pretty used up Xiaomi note 7 pro, the delays only reached ~100
80
80
</figure>
81
81
</div>
82
82
83
-
If you look closely at the two screen recordings above, you will notice that the text is first marked with an underline when focused, and then the Accordion opens the selected item. But the difference is that with the service worker, the first interaction on the Accordion component is a little delayed. With modulepreload, all interactions are instant. (You might want to set the video to 0.5x speed to better see the difference.)
83
+
It is hard to feel on a screen recording, but if you look closely at the two recordings above, you will notice that with the service worker, the first interaction on the Accordion component is a little slower. With modulepreload, all interactions are instant. (You might want to set the video to 0.5x speed to better see the difference.)
84
84
85
-
The reason why there is such a delay with the service worker on devices where the CPU is slow is because retrieving a chunk from the CacheControl with the Service Worker doesn't always take 1ms, but sometimes 10ms or more. So for example to retrieve 15 bundles on click, an old device can in total take 150ms or more instead of 15ms.
85
+
The reason why there is such a delay with the service worker on devices where the CPU is slow is because retrieving a chunk from the CacheControl with the Service Worker doesn't always take 1ms, but sometimes 10ms or more. So for example to retrieve 15 bundles on a first click, an old device can in total take 150ms or more instead of 15ms. Once the bundles have been executed and live in the browser memory or disk cache, the interactions are instant.
86
86
87
-
In contrast, modulepreloaded bundles are downloaded and compiled by the browser. They live in memory and are ready to be served instantly on request. So if all the bundles required for an interaction have been preloaded, the interaction will be instant. There is no network request, no service worker interception, no retrieving of bundles from the CacheStorage.
87
+
In contrast, modulepreloaded bundles are downloaded and compiled by the browser. They live in memory and are ready to be executed instantly on request. So if all the bundles required for an interaction have been preloaded, the interaction will be instant. There is no network request, no service worker interception, no retrieving of bundles from the CacheStorage.
88
88
89
89
Here’s a small Excalidraw to illustrate the difference:
90
90
@@ -95,28 +95,26 @@ Here’s a small Excalidraw to illustrate the difference:
95
95
The Service Worker had to be registered before any prefetching could happen. Not only did this negatively affect TTI and [TBT (Total Blocking Time)](https://developer.chrome.com/docs/lighthouse/performance/lighthouse-total-blocking-time#:~:text=Blocking%20Time%20audit-,What%20TBT%20measures,Paint%20and%20Time%20to%20Interactive.) a little, but it also prevented Qwik from reprioritizing bundles if the user interacted before the registration.
With modulepreload, we can now start preloading bundles **as soon as the browser is idle**. This means [FCP (First Contentful Paint)](https://web.dev/articles/fcp) and [LCP (Largest Contentful Paint)](https://web.dev/articles/optimize-lcp#:~:text=Largest%20Contentful%20Paint%20(LCP)%20is,is%20rendered%20within%20the%20viewport.) remain as fast as possible, and slightly better TTI and TBT scores because we can prioritize buffering the bundles needed for a user interaction as soon as the page is visible to the user.
99
-
### Even better prioritization based on heuristics
98
+
With modulepreload, we can now start preloading bundles as soon as the html is rendered. The default makes sure that [FCP (First Contentful Paint)](https://web.dev/articles/fcp) and [LCP (Largest Contentful Paint)](https://web.dev/articles/optimize-lcp#:~:text=Largest%20Contentful%20Paint%20(LCP)%20is,is%20rendered%20within%20the%20viewport.) remain as fast as possible, and slightly improves TTI and TBT scores over the service worker.
100
99
101
-
Reprioritization is a powerful feature - allowing Qwik to change the “buffering” order based on the user’s actions.
100
+
### Even better prioritization based on heuristics
102
101
103
-
But it’s even better if the framework can already know ahead of time what to “buffer” in which order.
102
+
A powerful feature that already existed in the Qwik service worker that is also implemented in the Qwik Preloader is the ability to “**reprioritize**” bundles on user interaction. If some bundles are at the bottom of the preload queue, we can tell the browser to start preloading them right away. This means that no matter what, TTI remains constant as it doesn't increase proportionally to the number and size of bundles that need to be loaded.
104
103
105
-
Qwik can now out of the box have better guesses about bundles that are more likely to be needed with other bundles, as they are “related”.
104
+
But it’s even better if the framework can already know ahead of time what to “buffer” in which order. Qwik can now out of the box guess which bundles are more likely to be requested by the user based on what is most likely to be interacted with first.
106
105
107
-
It is not perfect (for that we have [Qwik Insights]( which requires a database), but it’s quite a bit better than before! Qwik now gives “better scores” to more important things like “user events” or “above the fold” components over things it assumes are less important.
106
+
It is not perfect (for that we have [Qwik Insights]( which requires a database)), but it’s quite a bit better than before! Qwik now gives “better scores” to more important things like “user events” or “above the fold” components over things it assumes are less important.
108
107
109
108
For example, Qwik assumes that the search input on the navbar above the fold is more likely to be used sooner than a Button on a footer far down below the fold, but if the user scrolls and clicks the button on the footer, Qwik will re-prioritize its bundles before the search input.
109
+
110
110
### Faster CI times
111
111
112
112
Thanks to the performance improvements above, our full CI tests on [qwik.dev](<http://qwik.dev>) now run in about ~10 minutes instead of ~15, and most of it can be attributed to the E2E tests which do many renders in a browser and were therefore bootstrapping a lot of service workers.
113
113
## **How do I get all of this Goodness?** (**Migration steps)**
114
114
115
115
Migrating to Qwik 1.14.0 with the Qwik Preloader as the new default should not require much effort on your end, but there are a few changes you should know about.
116
116
117
-
Currently 93% of browsers support “modulepreload”, which wasn't the case when we started using the service worker for “buffering”.
118
-
119
-
For non-supported devices, the preloader will fallback to `<link rel=preload>`, which doesn't compile the code in advance but still works and brings the support to 100%. In effect, you can rest assured all your users will experience lightning speed regardless of their device.
117
+
Currently 93% of browsers support “modulepreload”, which wasn't the case when we started using the service worker for “buffering”. For non-supported devices, the preloader will fallback to `<link rel=preload>`, which doesn't compile the code in advance but still works and brings the support to 100%. In effect, you can rest assured all your users will experience lightning speed regardless of their device.
0 commit comments