Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: make the distinction between module-prefetching and <Link prefetch> #5485

Merged
merged 1 commit into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/docs/public/_redirects
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
/qwikcity/static-site-generation/overview/ /docs/guides/static-site-generation/ 308
/qwikcity/static-site-generation/static-site-config/ /docs/guides/static-site-generation/ 308
/qwikcity/static-site-generation/dynamic-routes/ /docs/guides/static-site-generation/ 308
/qwikcity/advanced/prefetching/ /docs/advanced/speculative-module-fetching/
/qwikcity/advanced/prefetching/ /docs/advanced/modules-prefetching/
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the redirect to /modules-prefetching, since the first paragraph in /modules-prefetching already redirects to /speculative-module-fetching.

/qwikcity/prefetching/overview/ /docs/advanced/speculative-module-fetching/ 308
/qwikcity/prefetching/service-worker-prefetching/ /docs/advanced/speculative-module-fetching/ 308
/qwikcity/prefetching/request-response-cache/ /docs/advanced/speculative-module-fetching/ 308
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const QWIK_ADVANCED_GROUP = [
'eslint',
'library',
'optimizer',
'prefetching',
'modules-prefetching',
'qrl',
'qwikloader',
'vite',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ contributors:
- saikatdas0790
- the-r3aper7
- mhevery
- maiieul
---

# Prefetching
# Prefetching modules

Qwik provides various strategies to prefetch modules ahead of time, and building on top of that, Qwik City is able to take it further by using [Speculative Module Fetching](../../../(qwikcity)/advanced/speculative-module-fetching/index.mdx). This docs page describes the **low-level** features of Qwik's prefetching. However, it's recommended to refer to Qwik City's documentation on [Speculative Module Fetching](../../../(qwikcity)/advanced/speculative-module-fetching/index.mdx) for a more comprehensive understanding.

- [Pre-populate the Cache with service workers](../../../(qwikcity)/advanced/speculative-module-fetching/index.mdx)
- [Link rel](#link-rel)
- [Web Worker Fetch](#web-worker-fetch)

Prefetching is a way for applications to begin downloading modules in a background task, before the user may actually require these modules. The ideal solution is to only prefetch the smallest amount of code that is highly likely to be executed from a user's interaction, while also avoiding any JavaScript that _will not_ be used.
Prefetching modules is a way for applications to begin downloading modules in a background task, before the user may actually require these modules. The ideal solution is to only prefetch the smallest amount of code that is highly likely to be executed from a user's interaction, while also avoiding any JavaScript that _will not_ be used.

Only downloading and executing a minimal amount of JavaScript is an area where Qwik applications excel. And since Qwik is able to understand how individual components are used (and what's not used), it can also best decide which bundles should be prefetched.

Expand All @@ -34,7 +35,7 @@ For our "Add to cart" example, the optimizer would collect the symbols for only

Since Qwik understands what's possible, it's able to prefetch the code only for the event listener rather than all the JavaScript for the entire application or route. This is in contrast to the traditional approach where the entire application or route, and framework code, must be prefetched just to add the click event listener.

## Prefetching Strategy
## prefetchStrategy

The prefetching strategy is the logic that decides which JavaScript, if any, Qwik should prefetch in the background. By default, Qwik will prefetch any visible listeners on the page. To configure the prefetching strategy, use the options argument of the `renderToStream()` function, often found in the `src/entry.ssr.tsx` source file. Providing optimal prefetching strategies is an area Qwik will continue to research and experiment with.

Expand All @@ -52,9 +53,9 @@ export default function (opts: RenderToStreamOptions) {
}
```

## Prefetching Implementation
### Implementation

Browsers offer numerous ways to "implement", or apply, a [prefetching strategy](#prefetching-strategy), and Qwik can be configured to prefer one implementation over another, each with their pros and cons. Depending on the configuration, the generated HTML content will include the prefetch implementation.
Browsers offer numerous ways to "implement", or apply, a [prefetching strategy](#prefetchStrategy), and Qwik can be configured to prefer one implementation over another, each with their pros and cons. Depending on the configuration, the generated HTML content will include the prefetch implementation.

```ts
export default function (opts: RenderToStreamOptions) {
Expand All @@ -79,7 +80,7 @@ For Qwik City applications, we highly recommended using [Speculative Module Fetc
| `linkRel` | This option is used to define the [`rel` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types) of the `<link>` element. When the `linkInsert` option is used, the default is `prefetch`. Other options include `preload` and `modulepreload`. |
| `workerFetchInsert` | Prefetch urls by calling a `fetch()` for each module, with the goal of populating the network cache. |

### Dispatched Prefetch Event
#### Dispatched Prefetch Event

[Speculative Module Fetching](../../../(qwikcity)/advanced/speculative-module-fetching/index.mdx) is the preferred caching strategy used by Qwik City. This strategy listens for the `qprefetch` event, which is dispatched by the Qwik framework. The event contains a list of URLs that the background thread should use to pre-populate the browser's [Cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache).

Expand All @@ -95,7 +96,7 @@ dispatchEvent(new CustomEvent("qprefetch", { detail: {
}}));
```

### Link `rel`
#### Link `rel`

Using the `<link>` element with the `rel` attribute is a common approach by today's frameworks, and Qwik can use this method by configuring the `linkInsert` and `linkRel` options. The challenge with the link rel approach is lack of support on _all_ devices, at least at the time of writing. Additionally, during development, it can be misleading that it works everywhere; while on mobile devices it is not easily visible that link prefetching is working correctly.

Expand All @@ -107,12 +108,12 @@ For example, Safari (the browser powering iPhones and iPads) does not support `m

Additionally, it may be possible to fire off multiple requests for the same resource. For example, let's say we want to prefetch `module-a.js`, and while that's being downloaded (which may take a short time, or a very long time), the user interacts with the app, which then decides to actually request and execute `module-a.js`. At the time of writing, browsers will often fire off a second request, which makes matters worse.

#### link rel="modulepreload"
##### link rel="modulepreload"

- Even though it's in the HTML spec, that doesn't mean your end-users are preloading your app correctly. [Can I Use: modulepreload](https://caniuse.com/link-rel-modulepreload)
- Not supported by [Firefox](https://bugzilla.mozilla.org/show_bug.cgi?id=1425310).

### Web Worker Fetch
#### Web Worker Fetch

`workerFetchInsert` instructs Qwik to employ a web worker to `fetch()` a JavaScript file, with the goal of priming the browser cache with the module. By using a web worker, the fetch and caching logic lives on another thread. The fetch response will also have an `immutable` or long cache-control header, so the browser doesn't make a second network request.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ You can think of the page load as the first user interaction, which pre-populate

### Pre-populate Cache Event

The recommended strategy is to use a [service worker](#pre-populating-the-cache-with-a-service-worker) to populate the [browser's cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache). The Qwik framework itself should use the [prefetchEvent](../../../(qwik)/advanced/prefetching/index.mdx#prefetching-implementation) implementation, which is already the default.
The recommended strategy is to use a [service worker](#pre-populating-the-cache-with-a-service-worker) to populate the [browser's cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache). The Qwik framework itself should use the [prefetchEvent](../../../(qwik)/advanced/modules-prefetching/index.mdx#implementation) implementation, which is already the default.

## Pre-populating the Cache with a Service Worker

Expand All @@ -49,7 +49,7 @@ By pre-populating the cache from within a service worker (which is a worker), we

### Interactively Pre-populating the Cache

Qwik itself should be configured to use the [prefetchEvent](../../../(qwik)/advanced/prefetching/index.mdx#prefetching-implementation) implementation (which is also Qwik's default). When Qwik emits the event, the service worker registration actively forwards the event data to the installed and active service worker.
Qwik itself should be configured to use the [prefetchEvent](../../../(qwik)/advanced/modules-prefetching/index.mdx#implementation) implementation (which is also Qwik's default). When Qwik emits the event, the service worker registration actively forwards the event data to the installed and active service worker.

The service worker (which runs in a background thread) then fetches the modules and adds them to the browser’s [Cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache). The main thread only needs to emit data about the required bundles, while the service worker’s sole focus is to cache those bundles.

Expand All @@ -60,9 +60,9 @@ The service worker (which runs in a background thread) then fetches the modules

## Caching Request and Response Pairs

In many traditional frameworks, the preferred strategy is to use the html `<link>` tag with a `rel` attribute set to `prefetch`, `preload` or `modulepreload`. However, there are [enough known issues](../../../(qwik)/advanced/prefetching/index.mdx#link-rel) that Qwik has preferred to not make `link` the default prefetching strategy (though it still can be [configured](../../../(qwik)/advanced/prefetching/index.mdx)).
In many traditional frameworks, the preferred strategy is to use the html `<link>` tag with a `rel` attribute set to `prefetch`, `preload` or `modulepreload`. However, there are [enough known issues](../../../(qwik)/advanced/modules-prefetching/index.mdx#link-rel) that Qwik has preferred to not make `link` the default prefetching strategy (though it still can be [configured](../../../(qwik)/advanced/modules-prefetching/index.mdx)).

Instead, Qwik prefers to use a newer approach that takes full advantage of the browser's [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache), which is also better supported compared to [modulepreload](../../../(qwik)/advanced/prefetching/index.mdx#link-rel).
Instead, Qwik prefers to use a newer approach that takes full advantage of the browser's [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache), which is also better supported compared to [modulepreload](../../../(qwik)/advanced/modules-prefetching/index.mdx#link-rel).

### Cache API

Expand Down Expand Up @@ -102,7 +102,7 @@ For demo purposes, let's say the fetching for this bundle takes two seconds. How

However, with Qwik's caching, if the user clicked the button, and we already started a request one second ago, and it has one second left until it's fully received, then the end-user only has to wait for one second. Remember, they're on a slow 3G connection in this demo. Luckily the user already received the full rendered landing page, so they're already looking at a completed page. Next, they're only pre-populating the cache with the bits of the app they could interact with, and their slow connection is dedicated to just those bundle(s). This is in contrast to their slow connection downloading all of the app, just to execute one listener.

Qwik is able to intercept requests for known bundles, and if a fetch in a background thread is already in flight, and then a user requests the same bundle, it'll ensure that the second request is able to re-use the initial one, which may already be done downloading. Trying to perform any of this with the [link](../../../(qwik)/advanced/prefetching/index.mdx#link-rel) also shows why Qwik preferred to not make it the default, but instead uses the caching API and intercepts requests with a service worker.
Qwik is able to intercept requests for known bundles, and if a fetch in a background thread is already in flight, and then a user requests the same bundle, it'll ensure that the second request is able to re-use the initial one, which may already be done downloading. Trying to perform any of this with the [link](../../../(qwik)/advanced/modules-prefetching/index.mdx#link-rel) also shows why Qwik preferred to not make it the default, but instead uses the caching API and intercepts requests with a service worker.

### Reducing Network Waterfalls

Expand Down
4 changes: 2 additions & 2 deletions packages/docs/src/routes/docs/(qwikcity)/routing/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ export default component$(() => {

> The `Link` component uses the `useNavigate()` hook [internally](https://github.com/BuilderIO/qwik/blob/e452582f4728cbcb7bf85d03293e757302286683/packages/qwik-city/runtime/src/link-component.tsx#L33).

### Refreshing
### <Link reload>

The `Link` with the `reload` prop can be used to refresh the current page.
You can also call the `nav()` function from the `useNavigate()` hook, without arguments.
Expand Down Expand Up @@ -263,7 +263,7 @@ export default component$(() => {

> While refreshing the page, the `isNavigating` boolean from `useLocation()` will be `true` until the page is fully rendered.

### Prefetching
### <Link prefetch>

The Link component's `prefetch` prop can be used to improve the perceived performance of the application. Although Qwik pages excel at lazy loading javascript, this feature can come in handy for content-heavy pages or SSR pages that need to wait for database or API calls.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ It can be consumed in our `index.astro` page like so:

### Roadmap

There are some things missing from Astro that we would like to add in the future. That being better [prefetching](https://qwik.builder.io/docs/advanced/prefetching/#prefetching) and [Insights](https://qwik.builder.io/docs/labs/insights/).
There are some things missing from Astro that we would like to add in the future. That being better [prefetching](https://qwik.builder.io/docs/advanced/modules-prefetching/#prefetching-modules) and [Insights](https://qwik.builder.io/docs/labs/insights/).

If there's anything else you think would be awesome with Astro & Qwik, feel free to take a crack at it.

Expand Down
2 changes: 1 addition & 1 deletion packages/docs/src/routes/docs/menu.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
- [Library mode](</docs/(qwik)/advanced/library/index.mdx>)
- [Qwikloader](</docs/(qwik)/advanced/qwikloader/index.mdx>)
- [Optimizer](</docs/(qwik)/advanced/optimizer/index.mdx>)
- [Prefetching](</docs/(qwik)/advanced/prefetching/index.mdx>)
- [Modules Prefetching](</docs/(qwik)/advanced/modules-prefetching/index.mdx>)
- [Build Directory](</docs/(qwik)/advanced/custom-build-dir/index.mdx>)
- [Vite](</docs/(qwik)/advanced/vite/index.mdx>)
- [Advanced Routing](</docs/(qwikcity)/advanced/routing/index.mdx>)
Expand Down