Skip to content

Commit f90e6a1

Browse files
authored
Merge pull request #7604 from QwikDev/eager-preloader
- adds the preloader, core, and the bundlegraph as preloads at the top of the page - adds SSR modulepreload links immediately after body completes, so that those preloads don't interfere with page loading, but still before document ready (what it was before) These changes don't seem to interfere with LCP, and they decrease delays.
2 parents 8c10268 + c50fda8 commit f90e6a1

File tree

10 files changed

+50
-13
lines changed

10 files changed

+50
-13
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@
434434
}
435435
],
436436
"kind": "Interface",
437-
"content": "The metadata of the build. One of its uses is storing where QRL symbols are located.\n\n\n```typescript\nexport interface QwikManifest \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[bundleGraph?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[QwikBundleGraph](#qwikbundlegraph)\n\n\n</td><td>\n\n_(Optional)_ All bundles in a compact graph format with probabilities\n\n\n</td></tr>\n<tr><td>\n\n[bundles](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[fileName: string\\]: [QwikBundle](#qwikbundle)<!-- -->; }\n\n\n</td><td>\n\nAll code bundles, used to know the import graph\n\n\n</td></tr>\n<tr><td>\n\n[injections?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[GlobalInjections](#globalinjections)<!-- -->\\[\\]\n\n\n</td><td>\n\n_(Optional)_ CSS etc to inject in the document head\n\n\n</td></tr>\n<tr><td>\n\n[manifestHash](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\nContent hash of the manifest, if this changes, the code changed\n\n\n</td></tr>\n<tr><td>\n\n[mapping](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[symbolName: string\\]: string; }\n\n\n</td><td>\n\nWhere QRLs are located\n\n\n</td></tr>\n<tr><td>\n\n[options?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ target?: string; buildMode?: string; entryStrategy?: { type: [EntryStrategy](#entrystrategy)<!-- -->\\['type'\\]; }; }\n\n\n</td><td>\n\n_(Optional)_ The options used to build the manifest\n\n\n</td></tr>\n<tr><td>\n\n[platform?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[name: string\\]: string; }\n\n\n</td><td>\n\n_(Optional)_ The platform used to build the manifest\n\n\n</td></tr>\n<tr><td>\n\n[preloader?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n_(Optional)_ The preloader bundle fileName\n\n\n</td></tr>\n<tr><td>\n\n[symbols](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[symbolName: string\\]: [QwikSymbol](#qwiksymbol)<!-- -->; }\n\n\n</td><td>\n\nQRL symbols\n\n\n</td></tr>\n<tr><td>\n\n[version](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\nThe version of the manifest\n\n\n</td></tr>\n</tbody></table>",
437+
"content": "The metadata of the build. One of its uses is storing where QRL symbols are located.\n\n\n```typescript\nexport interface QwikManifest \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[bundleGraph?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[QwikBundleGraph](#qwikbundlegraph)\n\n\n</td><td>\n\n_(Optional)_ All bundles in a compact graph format with probabilities\n\n\n</td></tr>\n<tr><td>\n\n[bundles](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[fileName: string\\]: [QwikBundle](#qwikbundle)<!-- -->; }\n\n\n</td><td>\n\nAll code bundles, used to know the import graph\n\n\n</td></tr>\n<tr><td>\n\n[core?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n_(Optional)_ The Qwik core bundle fileName\n\n\n</td></tr>\n<tr><td>\n\n[injections?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n[GlobalInjections](#globalinjections)<!-- -->\\[\\]\n\n\n</td><td>\n\n_(Optional)_ CSS etc to inject in the document head\n\n\n</td></tr>\n<tr><td>\n\n[manifestHash](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\nContent hash of the manifest, if this changes, the code changed\n\n\n</td></tr>\n<tr><td>\n\n[mapping](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[symbolName: string\\]: string; }\n\n\n</td><td>\n\nWhere QRLs are located\n\n\n</td></tr>\n<tr><td>\n\n[options?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ target?: string; buildMode?: string; entryStrategy?: { type: [EntryStrategy](#entrystrategy)<!-- -->\\['type'\\]; }; }\n\n\n</td><td>\n\n_(Optional)_ The options used to build the manifest\n\n\n</td></tr>\n<tr><td>\n\n[platform?](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[name: string\\]: string; }\n\n\n</td><td>\n\n_(Optional)_ The platform used to build the manifest\n\n\n</td></tr>\n<tr><td>\n\n[preloader?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\n_(Optional)_ The preloader bundle fileName\n\n\n</td></tr>\n<tr><td>\n\n[symbols](#)\n\n\n</td><td>\n\n\n</td><td>\n\n{ \\[symbolName: string\\]: [QwikSymbol](#qwiksymbol)<!-- -->; }\n\n\n</td><td>\n\nQRL symbols\n\n\n</td></tr>\n<tr><td>\n\n[version](#)\n\n\n</td><td>\n\n\n</td><td>\n\nstring\n\n\n</td><td>\n\nThe version of the manifest\n\n\n</td></tr>\n</tbody></table>",
438438
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/optimizer/src/types.ts",
439439
"mdFile": "qwik.qwikmanifest.md"
440440
},

packages/docs/src/routes/api/qwik-optimizer/index.mdx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,6 +1433,21 @@ All code bundles, used to know the import graph
14331433
</td></tr>
14341434
<tr><td>
14351435

1436+
[core?](#)
1437+
1438+
</td><td>
1439+
1440+
</td><td>
1441+
1442+
string
1443+
1444+
</td><td>
1445+
1446+
_(Optional)_ The Qwik core bundle fileName
1447+
1448+
</td></tr>
1449+
<tr><td>
1450+
14361451
[injections?](#)
14371452

14381453
</td><td>

packages/qwik/src/optimizer/src/manifest.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,8 @@ export function generateManifestFromBundles(
473473
bundle.origins = modulePaths;
474474
if (modulePaths.some((m) => m.endsWith(QWIK_PRELOADER_REAL_ID))) {
475475
manifest.preloader = bundleFileName;
476+
} else if (modulePaths.some((m) => /[/\\]qwik[/\\]dist[/\\]core\.[^/]*js$/.test(m))) {
477+
manifest.core = bundleFileName;
476478
}
477479
}
478480

packages/qwik/src/optimizer/src/plugins/plugin.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,7 @@ export const isDev = ${JSON.stringify(isDev)};
868868
bundleGraph: manifest.bundleGraph,
869869
mapping: manifest.mapping,
870870
preloader: manifest.preloader,
871+
core: manifest.core,
871872
};
872873
}
873874
return `// @qwik-client-manifest

packages/qwik/src/optimizer/src/qwik.optimizer.api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ export interface QwikManifest {
185185
bundles: {
186186
[fileName: string]: QwikBundle;
187187
};
188+
core?: string;
188189
injections?: GlobalInjections[];
189190
manifestHash: string;
190191
mapping: {

packages/qwik/src/optimizer/src/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ export interface QwikManifest {
227227
bundleGraph?: QwikBundleGraph;
228228
/** The preloader bundle fileName */
229229
preloader?: string;
230+
/** The Qwik core bundle fileName */
231+
core?: string;
230232
/** CSS etc to inject in the document head */
231233
injections?: GlobalInjections[];
232234
/** The version of the manifest */
@@ -247,7 +249,7 @@ export interface QwikManifest {
247249
*/
248250
export type ServerQwikManifest = Pick<
249251
QwikManifest,
250-
'manifestHash' | 'injections' | 'bundleGraph' | 'mapping' | 'preloader'
252+
'manifestHash' | 'injections' | 'bundleGraph' | 'mapping' | 'preloader' | 'core'
251253
>;
252254

253255
/**

packages/qwik/src/server/prefetch-strategy.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,5 +72,8 @@ export const expandBundles = (names: string[], resolvedManifest?: ResolvedManife
7272
probability *= 0.95;
7373
}
7474

75-
return getQueue();
75+
return getQueue().filter(
76+
(name) =>
77+
name !== resolvedManifest?.manifest.preloader && name !== resolvedManifest?.manifest.core
78+
);
7679
};

packages/qwik/src/server/preload-impl.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export function includePreloader(
6363
`e=document.createElement('link');` +
6464
`e.rel='modulepreload';` +
6565
`e.href=${JSON.stringify(base)}+l;` +
66-
`document.body.appendChild(e)` +
66+
`document.head.appendChild(e)` +
6767
`});`
6868
: '';
6969
const opts: string[] = [];
@@ -80,9 +80,10 @@ export function includePreloader(
8080
// We are super careful not to interfere with the page loading.
8181
const script =
8282
// First we wait for the onload event
83+
`let b=fetch("${base}q-bundle-graph-${manifestHash}.json");` +
84+
insertLinks +
8385
`window.addEventListener('load',f=>{` +
84-
`f=b=>{${insertLinks}` +
85-
`b=fetch("${base}q-bundle-graph-${manifestHash}.json");` +
86+
`f=_=>{` +
8687
`import("${base}${preloadChunk}").then(({l,p})=>{` +
8788
`l(${JSON.stringify(base)},b${optsStr});` +
8889
`p(${JSON.stringify(referencedBundles)});` +

packages/qwik/src/server/render.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,22 @@ export async function renderToStream(
165165
})
166166
);
167167
}
168+
const preloadChunk = resolvedManifest?.manifest?.preloader;
169+
if (preloadChunk && opts.preloader !== false) {
170+
const core = resolvedManifest?.manifest.core;
171+
beforeContent.push(
172+
jsx('link', { rel: 'modulepreload', href: `${buildBase}${preloadChunk}` }),
173+
jsx('link', {
174+
rel: 'preload',
175+
href: `${buildBase}q-bundle-graph-${resolvedManifest?.manifest.manifestHash}.json`,
176+
as: 'fetch',
177+
crossorigin: 'anonymous',
178+
})
179+
);
180+
if (core) {
181+
beforeContent.push(jsx('link', { rel: 'modulepreload', href: `${buildBase}${core}` }));
182+
}
183+
}
168184

169185
const renderTimer = createTimer();
170186
const renderSymbols: string[] = [];

starters/apps/preloader-test/src/entry.ssr.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,9 @@ import Root from "./root";
1818

1919
export default function (opts: RenderToStreamOptions) {
2020
return renderToStream(<Root />, {
21-
prefetchStrategy: {
22-
implementation: {
23-
debug: true,
24-
minProbability: 0.5,
25-
maxSimultaneousPreloads: 10,
26-
minPreloadProbability: 0.25,
27-
},
21+
preloader: {
22+
debug: true,
23+
ssrPreloads: 10,
2824
},
2925
...opts,
3026
// Use container attributes to set attributes on the html tag.

0 commit comments

Comments
 (0)