Skip to content

Commit

Permalink
docs: speculative module fetching (QwikDev#3239)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamdbradley authored Mar 3, 2023
1 parent 014ad5b commit dbe1813
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 334 deletions.
9 changes: 5 additions & 4 deletions packages/docs/public/_redirects
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
/qwikcity/static-site-generation/overview/ /qwikcity/guides/static-site-generation/ 308
/qwikcity/static-site-generation/static-site-config/ /qwikcity/guides/static-site-generation/ 308
/qwikcity/static-site-generation/dynamic-routes/ /qwikcity/guides/static-site-generation/ 308
/qwikcity/prefetching/overview/ /qwikcity/advanced/prefetching/ 308
/qwikcity/prefetching/service-worker-prefetching/ /qwikcity/advanced/prefetching/ 308
/qwikcity/prefetching/request-response-cache/ /qwikcity/advanced/prefetching/ 308
/qwikcity/prefetching/parallelizing-network-requests/ /qwikcity/advanced/prefetching/ 308
/qwikcity/advanced/prefetching/ /qwikcity/advanced/speculative-module-fetching/
/qwikcity/prefetching/overview/ /qwikcity/advanced/speculative-module-fetching/ 308
/qwikcity/prefetching/service-worker-prefetching/ /qwikcity/advanced/speculative-module-fetching/ 308
/qwikcity/prefetching/request-response-cache/ /qwikcity/advanced/speculative-module-fetching/ 308
/qwikcity/prefetching/parallelizing-network-requests/ /qwikcity/advanced/speculative-module-fetching/ 308
35 changes: 30 additions & 5 deletions packages/docs/src/routes/docs/advanced/prefetching/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ contributors:

# Prefetching

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, but to avoid any JavaScript that _cannot_ be used.
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, but recommended to instead review Qwik City's [Speculative Module Fetching](../../../qwikcity/advanced/speculative-module-fetching/index.mdx) docs.

- [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.

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 @@ -29,6 +35,8 @@ Since Qwik understands what's possible, it's able to prefetch the code only for

The prefetching strategy is the logic which 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.

For Qwik City applications, we highly recommended using [Speculative Module Fetching](../../../qwikcity/advanced/speculative-module-fetching/index.mdx).

```ts
export default function (opts: RenderToStreamOptions) {
return renderToStream(<Root />, {
Expand Down Expand Up @@ -59,18 +67,30 @@ export default function (opts: RenderToStreamOptions) {
}
```

For Qwik City applications, we highly recommended using [Speculative Module Fetching](../../../qwikcity/advanced/speculative-module-fetching/index.mdx), which uses the `prefetchEvent` implementation.

| Option | Description |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `prefetchEvent` | Dispatch a `qprefetch` event with detailed data containing the urls that should be prefetched. The event dispatch script will be inlined into the document's HTML. |
| `prefetchEvent` | Dispatch a `qprefetch` event with `detail` data containing the urls that should be prefetched. The event dispatch script will be inlined into the document's HTML. By default, the `prefetchEvent` implementation will be set to `always`. |
| `linkInsert` | Insert the `<link>` element into the document. When using `html-append`, it will render each `<link>` directly within the html, appended at the end of the body. Using the `js-append` option, it will instead insert some JavaScript, which creates the elements at runtime and appends them at the end of the body. |
| `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. |

### Request/Response Cache and Service Workers
### 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).

Qwik itself should be configured to use the `prefetchEvent` implementation, which will dispatch a `qprefetch` event. By default, the `prefetchEvent` implementation will be set to `always`. Next, [Qwik City](../../../qwikcity/advanced/speculative-module-fetching/index.mdx) will listen for this event and communicate with its service worker to persist the Request / Response object pairs so they are cached in long-lived memory.

The preferred caching strategy used by [Qwik City](/qwikcity/advanced/prefetching/index.mdx), is to use a Service Worker to populate the browser's [Cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache). Qwik itself should be configured to use the `prefetchEvent` implementation, which will dispatch a `qprefetch` event. Next, Qwik City will listen for this event and communicate with its service worker to persist the Request / Response object pairs so they are cached in long-lived memory.
By using a service worker to intercept `fetch` requests from the browser, this approach allows fine-grain caching control, along with preventing duplicate requests for the same resource.

By using a service worker to intercept fetch requests from the browser, this approach allows fine-grain caching control, along with preventing duplicate requests for the same resource.
Below is an example of manually dispatching the event. These events are dispatched from Qwik itself and do not require developers to dispatch these events manually. Additionally, the [service worker](../../../qwikcity/advanced/speculative-module-fetching/index.mdx) will automatically add listeners for these events.

```ts
dispatchEvent(new CustomEvent("qprefetch", { detail: {
bundles: [...]
}}));
```

### Link `rel`

Expand All @@ -84,6 +104,11 @@ For example, Safari (the browser powering iPhones and iPads) does not support `m
Additionally, it may be possible to fire off a 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"

- 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

`workerFetchInsert` can be used to have Qwik use 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
12 changes: 6 additions & 6 deletions packages/docs/src/routes/docs/faq/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,21 @@ export const App_component_p_onClick_01pEgC10cpw = () => console.log('hello');

## Does Qwik download JS when the user interacts?

Nope. In production, Qwik uses a lot of information generated during SSR (Server-Side Rendering) to start [prefetching](/qwikcity/advanced/prefetching/index.mdx) only the bits of interactivity available on the current page as soon as possible (ASAP). This way, when the user clicks or interacts, the JS is already downloaded.
Nope. In production, Qwik uses a lot of information generated during SSR (Server-Side Rendering) to start [pre-populating the cache](../../qwikcity/advanced/speculative-module-fetching/index.mdx) with only the bits of interactivity available on the current page as soon as possible (ASAP). This way, when the user clicks or interacts, the JS is already in the cache.

## If Qwik prefetches JS, then what's the difference?
## If Qwik still requests the JS, then what's the difference?

Prefetching is not the same as parsing and executing JS, and Qwik does not execute JS until the user interacts.
Pre-populating the cache is not the same as parsing and executing JS, and Qwik does not execute JS until the user interacts.

In addition, [prefetching](/qwikcity/advanced/prefetching/index.mdx) enables Qwik to prioritize the important parts of interactivity before the less important parts.
In addition, [Speculative Module Fetching](../../qwikcity/advanced/speculative-module-fetching/index.mdx) enables Qwik to prioritize the important parts of interactivity before the less important parts.

For example, the "buy now" button is more important than the "add to cart" button, so Qwik will prefetch the "buy now" button first, and then the "add to cart" button.
For example, the "buy now" button is more important than the "Add to Cart" button, so Qwik will prefetch the "Buy Now" button first, and then the "add to cart" button.

Qwik does not need to prefetch everything to start running, while other frameworks do need to download the whole critical path before they can start running because of [hydration](https://www.builder.io/blog/hydration-is-pure-overhead).

## Are Qwik apps slow on slow networks?

Not at all! Thanks to [prefetching](/qwikcity/advanced/prefetching/index.mdx) Qwik apps are not more affected by slow networks than other frameworks. In fact because of the fine grained bundling and resumability, Qwik apps can become interactive with much less JS, effectively making them faster on slow networks.
Not at all! Thanks to [Speculative Module Fetching](../../qwikcity/advanced/speculative-module-fetching/index.mdx) Qwik apps are not more affected by slow networks than other frameworks. In fact because of the fine grained bundling and resumability, Qwik apps can become interactive with much less JS, effectively making them faster on slow networks.

## Does Qwik generate too many small files?

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 @@ -37,10 +37,10 @@

- [The $ dollar sign](advanced/dollar/index.mdx)
- [Containers](advanced/containers/index.mdx)
- [Prefetching](advanced/prefetching/index.mdx)
- [QRL](advanced/qrl/index.mdx)
- [Qwikloader](advanced/qwikloader/index.mdx)
- [Optimizer](advanced/optimizer/index.mdx)
- [Prefetching](advanced/prefetching/index.mdx)
- [Custom Build Directory](advanced/custom-build-dir/index.mdx)
- [Internationalization](advanced/i18n/index.mdx)
- [Vite](advanced/vite/index.mdx)
Expand Down
Loading

0 comments on commit dbe1813

Please sign in to comment.