Skip to content

Commit 868a944

Browse files
authored
Merge pull request #7516 from QwikDev/preloader
feat(preloader): more sane configuration
2 parents 031eeb4 + 53c8cdf commit 868a944

File tree

26 files changed

+467
-306
lines changed

26 files changed

+467
-306
lines changed

.changeset/fair-cars-fry.md

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,35 @@ FEAT: Major improvements to prefetching with automatic bundle preloading
1616

1717
⚠️ **ATTENTION:**
1818

19-
**Keep** your service worker code as is (either `<ServiceWorkerRegister/>` or `<PrefetchServiceWorker/>`).
19+
- **Keep** your service worker code as is (either `<ServiceWorkerRegister/>` or `<PrefetchServiceWorker/>`).
20+
- **Configure** your server to provide long caching headers.
21+
22+
Service Worker:
2023

2124
This new implementation will use it to uninstall the current service worker to reduce the unnecessary duplication.
2225

2326
The builtin service workers components are deprecated but still exist for backwards compatibility.
2427

28+
Caching Headers:
29+
30+
The bundles under build/ are named with their content hash and may therefore be cached indefinitely. Typically you should serve `build/**/*.js` with `Cache-Control: public, max-age=31536000, immutable`.
31+
2532
---
2633

27-
You can configure the prefetch behavior in your SSR configuration:
34+
You can configure the preload behavior in your SSR configuration:
2835

2936
```ts
3037
// entry.ssr.ts
3138
export default function (opts: RenderToStreamOptions) {
3239
return renderToStream(<Root />, {
33-
prefetchStrategy: {
34-
implementation: {
35-
// Enable debug logging for prefetch operations
36-
debug: true,
37-
// Maximum simultaneous preload links
38-
maxSimultaneousPreloads: 5,
39-
// Minimum probability threshold for preloading
40-
minPreloadProbability: 0.25
41-
},
40+
preload: {
41+
// Enable debug logging for preload operations
42+
debug: true,
43+
// Maximum simultaneous preload links
44+
maxBufferPreloads: 5,
45+
// Minimum probability threshold for preloading
46+
preloadProbability: 0.25
47+
// ...and more, see the type JSDoc on hover
4248
},
4349
...opts,
4450
});
@@ -52,3 +58,4 @@ npm run qwik add service-worker
5258
```
5359

5460
This will add a basic service worker setup that you can customize for specific caching strategies, offline support, or other PWA features beyond just prefetching.
61+

packages/docs/src/entry.ssr.tsx

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import { renderToStream, type RenderToStreamOptions } from '@builder.io/qwik/server';
1+
import type { PreloaderOptions, RenderToStreamOptions } from '@builder.io/qwik/server';
2+
import { renderToStream } from '@builder.io/qwik/server';
23
import Root from './root';
34

45
// You can pass these as query parameters, as well as `preloadDebug`
56
const preloaderSettings = [
6-
'maxPreloads',
7-
'minProbability',
8-
'maxSimultaneousPreloads',
9-
'minPreloadProbability',
7+
'ssrPreloads',
8+
'ssrPreloadProbability',
9+
'maxBufferPreloads',
10+
'preloadProbability',
1011
] as const;
1112

1213
export default function (opts: RenderToStreamOptions) {
@@ -15,21 +16,21 @@ export default function (opts: RenderToStreamOptions) {
1516
if (urlStr) {
1617
const { searchParams } = new URL(urlStr);
1718
if (searchParams.size) {
18-
opts = {
19+
const newOpts = {
1920
...opts,
20-
prefetchStrategy: {
21-
...opts.prefetchStrategy,
22-
implementation: { ...opts.prefetchStrategy?.implementation },
21+
preloader: {
22+
...(typeof opts.preloader === 'object' ? opts.preloader : undefined),
2323
},
24-
};
25-
if (searchParams.has('preloadDebug')) {
26-
opts.prefetchStrategy!.implementation!.debug = true;
24+
} as Omit<RenderToStreamOptions, 'preloader'> & { preloader: PreloaderOptions };
25+
if (searchParams.has('preloaderDebug')) {
26+
newOpts.preloader!.debug = true;
2727
}
2828
for (const type of preloaderSettings) {
2929
if (searchParams.has(type)) {
30-
opts.prefetchStrategy!.implementation![type] = Number(searchParams.get(type));
30+
newOpts.preloader[type] = Number(searchParams.get(type));
3131
}
3232
}
33+
opts = newOpts;
3334
}
3435
}
3536
return renderToStream(<Root />, {

packages/docs/src/routes/api/qwik-server/api.json

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
}
8383
],
8484
"kind": "Interface",
85-
"content": "```typescript\nexport interface PrefetchImplementation \n```\n\n\n<table><thead><tr><th>\n\nProperty\n\n\n</th><th>\n\nModifiers\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\n[debug?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nboolean\n\n\n</td><td>\n\n_(Optional)_ If true, the preloader will log debug information to the console.\n\nDefaults to `false`\n\n\n</td></tr>\n<tr><td>\n\n[linkFetchPriority?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'auto' \\| 'low' \\| 'high' \\| null\n\n\n</td><td>\n\n_(Optional)_ Value of the `<link fetchpriority=\"...\">` attribute when links are added. Defaults to `null`<!-- -->.\n\n\n</td></tr>\n<tr><td>\n\n[linkInsert?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'js-append' \\| 'html-append' \\| null\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[linkRel?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'prefetch' \\| 'preload' \\| 'modulepreload' \\| null\n\n\n</td><td>\n\n_(Optional)_ Value of the `<link rel=\"...\">` attribute when links are added. The preloader itself will autodetect which attribute to use based on the browser capabilities.\n\nDefaults to `modulepreload`<!-- -->.\n\n\n</td></tr>\n<tr><td>\n\n[maxPreloads?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nnumber\n\n\n</td><td>\n\n_(Optional)_ Maximum number of preload links to add during SSR. These instruct the browser to preload likely bundles before the preloader script is active. This includes the 2 preloads used for the preloader script itself and the bundle information. Setting this to 0 will disable all preload links.\n\nDefaults to `5`\n\n\n</td></tr>\n<tr><td>\n\n[maxSimultaneousPreloads?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nnumber\n\n\n</td><td>\n\n_(Optional)_ Maximum number of simultaneous preload links that the preloader will maintain.\n\nDefaults to `5`\n\n\n</td></tr>\n<tr><td>\n\n[minPreloadProbability?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nnumber\n\n\n</td><td>\n\n_(Optional)_ The minimum probability for a bundle to be added to the preload queue.\n\nDefaults to `0.25` (25% probability)\n\n\n</td></tr>\n<tr><td>\n\n[minProbability?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nnumber\n\n\n</td><td>\n\n_(Optional)_ The minimum probability of a bundle to be added as a preload link during SSR.\n\nDefaults to `0.6` (60% probability)\n\n\n</td></tr>\n<tr><td>\n\n[prefetchEvent?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'always' \\| null\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[workerFetchInsert?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'always' \\| 'no-link-support' \\| null\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n</tbody></table>",
85+
"content": "> Warning: This API is now obsolete.\n> \n> Use `preloader` instead\n> \n\n\n```typescript\nexport interface PrefetchImplementation \n```\n\n\n<table><thead><tr><th>\n\nProperty\n\n\n</th><th>\n\nModifiers\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\n[linkFetchPriority?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'auto' \\| 'low' \\| 'high' \\| null\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[linkInsert?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'js-append' \\| 'html-append' \\| null\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[linkRel?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'prefetch' \\| 'preload' \\| 'modulepreload' \\| null\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[prefetchEvent?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'always' \\| null\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[workerFetchInsert?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n'always' \\| 'no-link-support' \\| null\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n</tbody></table>",
8686
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/server/types.ts",
8787
"mdFile": "qwik.prefetchimplementation.md"
8888
},
@@ -114,6 +114,20 @@
114114
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/server/types.ts",
115115
"mdFile": "qwik.prefetchstrategy.md"
116116
},
117+
{
118+
"name": "PreloaderOptions",
119+
"id": "preloaderoptions",
120+
"hierarchy": [
121+
{
122+
"name": "PreloaderOptions",
123+
"id": "preloaderoptions"
124+
}
125+
],
126+
"kind": "Interface",
127+
"content": "```typescript\nexport interface PreloaderOptions \n```\n\n\n<table><thead><tr><th>\n\nProperty\n\n\n</th><th>\n\nModifiers\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\n[debug?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nboolean\n\n\n</td><td>\n\n_(Optional)_ Log preloader debug information to the console.\n\nDefaults to `false`\n\n\n</td></tr>\n<tr><td>\n\n[maxBufferPreloads?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nnumber\n\n\n</td><td>\n\n_(Optional)_ Maximum number of simultaneous preload links that the preloader will maintain. If you set this higher, the browser will have all JS files in memory sooner, but it will contend with other resource downloads. Furthermore, if a bundle suddenly becomes more likely, it will have to wait longer to be preloaded.\n\nBundles that reach 100% probability (static imports of other bundles) will always be preloaded immediately, no limit.\n\nDefaults to `25`\n\n\n</td></tr>\n<tr><td>\n\n[preloadProbability?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nnumber\n\n\n</td><td>\n\n_(Optional)_ The minimum probability for a bundle to be added to the preload queue.\n\nDefaults to `0.35` (35% probability)\n\n\n</td></tr>\n<tr><td>\n\n[ssrPreloadProbability?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nnumber\n\n\n</td><td>\n\n_(Optional)_ The minimum probability for a bundle to be added as a preload link during SSR.\n\nDefaults to `0.7` (70% probability)\n\n\n</td></tr>\n<tr><td>\n\n[ssrPreloads?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nnumber\n\n\n</td><td>\n\n_(Optional)_ Maximum number of preload links to add during SSR. These instruct the browser to preload likely bundles before the preloader script is active. This most likely includes the core and the preloader script itself. Setting this to 0 will disable all preload links.\n\nPreload links can delay LCP, which is a Core Web Vital, but it can increase TTI, which is not a Core Web Vital but more noticeable to the user.\n\nDefaults to `5`\n\n\n</td></tr>\n</tbody></table>",
128+
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/server/types.ts",
129+
"mdFile": "qwik.preloaderoptions.md"
130+
},
117131
{
118132
"name": "QwikLoaderOptions",
119133
"id": "qwikloaderoptions",
@@ -152,7 +166,7 @@
152166
}
153167
],
154168
"kind": "Interface",
155-
"content": "```typescript\nexport interface RenderOptions extends SerializeDocumentOptions \n```\n**Extends:** [SerializeDocumentOptions](#serializedocumentoptions)\n\n\n<table><thead><tr><th>\n\nProperty\n\n\n</th><th>\n\nModifiers\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\n[base?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring \\| ((options: [RenderOptions](#renderoptions)<!-- -->) =&gt; string)\n\n\n</td><td>\n\n_(Optional)_ Specifies the root of the JS files of the client build. Setting a base, will cause the render of the `q:base` attribute in the `q:container` element.\n\n\n</td></tr>\n<tr><td>\n\n[containerAttributes?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nRecord&lt;string, string&gt;\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[containerTagName?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n_(Optional)_ When set, the app is serialized into a fragment. And the returned html is not a complete document. Defaults to `html`\n\n\n</td></tr>\n<tr><td>\n\n[locale?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring \\| ((options: [RenderOptions](#renderoptions)<!-- -->) =&gt; string)\n\n\n</td><td>\n\n_(Optional)_ Language to use when rendering the document.\n\n\n</td></tr>\n<tr><td>\n\n[prefetchStrategy?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[PrefetchStrategy](#prefetchstrategy) \\| null\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[qwikLoader?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[QwikLoaderOptions](#qwikloaderoptions)\n\n\n</td><td>\n\n_(Optional)_ Specifies if the Qwik Loader script is added to the document or not.\n\nDefaults to `{ include: true }`<!-- -->.\n\n\n</td></tr>\n<tr><td>\n\n[qwikPrefetchServiceWorker?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nQwikPrefetchServiceWorkerOptions\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[serverData?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nRecord&lt;string, any&gt;\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[snapshot?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nboolean\n\n\n</td><td>\n\n_(Optional)_ Defaults to `true`\n\n\n</td></tr>\n</tbody></table>",
169+
"content": "```typescript\nexport interface RenderOptions extends SerializeDocumentOptions \n```\n**Extends:** [SerializeDocumentOptions](#serializedocumentoptions)\n\n\n<table><thead><tr><th>\n\nProperty\n\n\n</th><th>\n\nModifiers\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\n[base?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring \\| ((options: [RenderOptions](#renderoptions)<!-- -->) =&gt; string)\n\n\n</td><td>\n\n_(Optional)_ Specifies the root of the JS files of the client build. Setting a base, will cause the render of the `q:base` attribute in the `q:container` element.\n\n\n</td></tr>\n<tr><td>\n\n[containerAttributes?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nRecord&lt;string, string&gt;\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[containerTagName?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n_(Optional)_ When set, the app is serialized into a fragment. And the returned html is not a complete document. Defaults to `html`\n\n\n</td></tr>\n<tr><td>\n\n[locale?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring \\| ((options: [RenderOptions](#renderoptions)<!-- -->) =&gt; string)\n\n\n</td><td>\n\n_(Optional)_ Language to use when rendering the document.\n\n\n</td></tr>\n<tr><td>\n\n[prefetchStrategy?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[PrefetchStrategy](#prefetchstrategy) \\| null\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[preloader?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[PreloaderOptions](#preloaderoptions) \\| boolean\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[qwikLoader?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[QwikLoaderOptions](#qwikloaderoptions)\n\n\n</td><td>\n\n_(Optional)_ Specifies if the Qwik Loader script is added to the document or not.\n\nDefaults to `{ include: true }`<!-- -->.\n\n\n</td></tr>\n<tr><td>\n\n[qwikPrefetchServiceWorker?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nQwikPrefetchServiceWorkerOptions\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[serverData?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nRecord&lt;string, any&gt;\n\n\n</td><td>\n\n_(Optional)_\n\n\n</td></tr>\n<tr><td>\n\n[snapshot?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nboolean\n\n\n</td><td>\n\n_(Optional)_ Defaults to `true`\n\n\n</td></tr>\n</tbody></table>",
156170
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/server/types.ts",
157171
"mdFile": "qwik.renderoptions.md"
158172
},

0 commit comments

Comments
 (0)