Skip to content

Commit 82a40d4

Browse files
committed
wip more logging,
1 parent 67f77f4 commit 82a40d4

File tree

2 files changed

+86
-56
lines changed

2 files changed

+86
-56
lines changed

packages/qwik/src/core/preloader.ts

Lines changed: 81 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ const enum BundleImportState {
3232
None,
3333
Low,
3434
Queued,
35+
/** Preload link was made */
3536
Loading,
37+
/** All imports are >=Loading */
3638
Loaded,
3739
}
3840
type BundleImport = {
@@ -41,14 +43,25 @@ type BundleImport = {
4143
$state$: BundleImportState;
4244
$imports$: string[];
4345
$dynamicImports$: string[];
44-
$created$?: number | null;
46+
$priority$: boolean;
47+
$created$: number;
48+
$waited$: number;
49+
$loaded$: number;
4550
};
4651
const bundles = new Map<string, BundleImport>();
52+
let gotBundleGraph = false;
4753
const high: BundleImport[] = [];
4854
const low: BundleImport[] = [];
4955

56+
let highCount = 0;
57+
let lowCount = 0;
58+
const loadStart = Date.now();
59+
5060
const log = (...args: any[]) => {
51-
console.log(`PL> ${high.length}hi ${low.length}lo`, ...args);
61+
console.log(
62+
`PL ${Date.now() - loadStart}> hi ${highCount}/${high.length} lo ${lowCount}/${low.length}`,
63+
...args
64+
);
5265
};
5366
let base: string | undefined;
5467

@@ -61,24 +74,15 @@ const checkLoaded = (bundle: BundleImport) => {
6174
if (bundle.$state$ === BundleImportState.Loaded) {
6275
return true;
6376
}
64-
bundle.$imports$ = bundle.$imports$.filter(
65-
(dep) => bundles.get(dep)!.$state$ !== BundleImportState.Loading
66-
);
67-
bundle.$dynamicImports$ = bundle.$dynamicImports$.filter(
68-
(dep) => bundles.get(dep)!.$state$ !== BundleImportState.Loading
69-
);
7077
if (
7178
bundle.$state$ === BundleImportState.Loading &&
72-
!bundle.$imports$.length &&
73-
!bundle.$dynamicImports$.length
79+
bundle.$imports$.every((dep) => bundles.get(dep)!.$state$ >= BundleImportState.Loading)
7480
) {
7581
bundle.$state$ = BundleImportState.Loaded;
7682
return true;
7783
}
7884
};
7985

80-
let highCount = 0;
81-
let lowCount = 0;
8286
/**
8387
* This is called when a bundle is queued or finished loading.
8488
*
@@ -89,13 +93,22 @@ let lowCount = 0;
8993
*/
9094
const trigger = () => {
9195
// high is confirmed needed so we go as wide as possible
92-
while (highCount < 20 && high.length) {
96+
while (high.length) {
9397
const bundle = high.pop()!;
9498
preloadOne(bundle!, true);
9599
}
96-
while (highCount + lowCount < 3 && low.length) {
97-
const bundle = low.pop()!;
98-
preloadOne(bundle!);
100+
// these are opportunistic
101+
if (!highCount && !lowCount) {
102+
while (lowCount < 6 && low.length) {
103+
const bundle = low.pop()!;
104+
preloadOne(bundle!);
105+
}
106+
}
107+
if (!high.length && !low.length) {
108+
const loaded = [...bundles.values()].filter((b) => b.$state$ >= BundleImportState.Loading);
109+
const waitTime = loaded.reduce((acc, b) => acc + b.$waited$, 0);
110+
const loadTime = loaded.reduce((acc, b) => acc + b.$loaded$, 0);
111+
log(`done ${loaded.length} total: ${waitTime}ms waited, ${loadTime}ms loaded`);
99112
}
100113
};
101114

@@ -108,50 +121,46 @@ const rel =
108121
* that slows down interaction
109122
*/
110123
const preloadOne = (bundle: BundleImport, priority?: boolean) => {
111-
if (bundle.$state$ === BundleImportState.Loaded) {
124+
if (checkLoaded(bundle)) {
112125
return;
113126
}
114-
if (bundle.$url$) {
127+
if (bundle.$state$ < BundleImportState.Loading) {
115128
const start = Date.now();
116-
log(
117-
`load ${priority ? 'high' : 'low'} after ${`${start - bundle.$created$!}ms`}`,
118-
bundle.$name$
119-
);
120-
const link = doc.createElement('link');
121-
link.href = bundle.$url$!;
122-
link.rel = rel;
123-
if (priority) {
124-
highCount++;
125-
} else {
126-
lowCount++;
127-
}
128-
link.as = 'script';
129-
link.onload = link.onerror = () => {
130-
const end = Date.now();
131-
log(`DONE ${end - start}ms`, bundle.$name$);
132-
link.remove();
129+
bundle.$waited$ = start - bundle.$created$;
130+
bundle.$state$ = BundleImportState.Loading;
131+
if (bundle.$url$) {
132+
log(`load ${priority ? 'high' : 'low'} after ${`${bundle.$waited$}ms`}`, bundle.$name$);
133+
const link = doc.createElement('link');
134+
link.href = bundle.$url$!;
135+
link.rel = rel;
133136
if (priority) {
134-
highCount--;
137+
highCount++;
135138
} else {
136-
lowCount--;
139+
lowCount++;
137140
}
138-
trigger();
139-
};
141+
link.as = 'script';
142+
link.onload = link.onerror = () => {
143+
const end = Date.now();
144+
bundle.$loaded$ = end - start;
145+
log(`DONE ${bundle.$priority$ ? 'high' : 'low'} ${end - start}ms`, bundle.$name$);
146+
link.remove();
147+
if (priority) {
148+
highCount--;
149+
} else {
150+
lowCount--;
151+
}
152+
trigger();
153+
};
140154

141-
doc.head.appendChild(link);
155+
doc.head.appendChild(link);
156+
}
142157
}
143158

144-
bundle.$state$ = BundleImportState.Loading;
145-
if (!checkLoaded(bundle)) {
146-
/** Now that we processed the bundle, its dependencies are needed ASAP */
147-
if (priority) {
148-
// make sure to queue the high priority imports first so they preloaded before the low priority ones
149-
preload(bundle.$imports$, priority);
150-
preload(bundle.$dynamicImports$);
151-
} else {
152-
// only preload direct imports, low priority
153-
preload(bundle.$imports$);
154-
}
159+
bundle.$priority$ ||= priority!;
160+
preload(bundle.$imports$, priority);
161+
if (bundle.$priority$) {
162+
// make sure to queue the high priority imports first so they preloaded before the low priority ones
163+
preload(bundle.$dynamicImports$);
155164
}
156165
};
157166

@@ -163,12 +172,18 @@ const makeBundle = (path: string, imports: string[], dynamicImports: string[]) =
163172
$state$: BundleImportState.None,
164173
$imports$: imports,
165174
$dynamicImports$: dynamicImports,
175+
$priority$: false,
166176
$created$: Date.now(),
177+
$waited$: 0,
178+
$loaded$: 0,
167179
};
168180
};
169181
const ensureBundle = (name: string) => {
170182
let bundle = bundles.get(name);
171183
if (!bundle) {
184+
if (gotBundleGraph) {
185+
return;
186+
}
172187
bundle = makeBundle(name, [], []);
173188
bundles.set(name, bundle);
174189
}
@@ -179,11 +194,15 @@ const ensureBundle = (name: string) => {
179194
};
180195

181196
const parseBundleGraph = (text: string) => {
197+
log(`parseBundleGraph ${text.length >> 10}kB`);
182198
const graph = JSON.parse(text) as QwikBundleGraph;
183199
let i = 0;
184200
// All existing loading bundles need imports processed
185201
const toProcess = Object.keys(bundles)
186-
.filter((name) => bundles.get(name)!.$state$ === BundleImportState.Loading)
202+
.filter((name) => {
203+
const bundle = bundles.get(name)!;
204+
return bundle.$state$ === BundleImportState.Loading && bundle.$priority$;
205+
})
187206
.reverse();
188207
while (i < graph.length) {
189208
const name = graph[i++] as string;
@@ -207,6 +226,8 @@ const parseBundleGraph = (text: string) => {
207226
bundles.set(name, makeBundle(name, imports, dynamicImports));
208227
}
209228
}
229+
log(`parseBundleGraph done ${bundles.size} bundles`);
230+
gotBundleGraph = true;
210231
for (const name of toProcess) {
211232
const bundle = bundles.get(name)!;
212233
// we assume low priority
@@ -225,12 +246,17 @@ const preload = (name: string | string[], priority?: boolean) => {
225246
}
226247
const queue = priority ? high : low;
227248
if (Array.isArray(name)) {
228-
queue.push(...(name.map(ensureBundle).filter(Boolean) as BundleImport[]).reverse());
249+
const bundles = name.map(ensureBundle).filter(Boolean) as BundleImport[];
250+
if (!bundles.length) {
251+
return;
252+
}
253+
queue.push(...bundles.reverse());
229254
} else {
230255
const bundle = ensureBundle(name);
231-
if (bundle) {
232-
queue.push(bundle);
256+
if (!bundle) {
257+
return;
233258
}
259+
queue.push(bundle);
234260
}
235261
log(`queue ${priority ? 'high' : 'low'}`, name);
236262
trigger();

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,17 @@ function linkJsImplementation(
152152
}
153153

154154
// TODO modulepreload the preloader before ssr, optional because we can't predict if we need it
155+
156+
// TODO order imports by size/number of dependents?
155157
if (prio.length) {
156158
// We mark all the urls as low priority, so that newly needed resources are loaded first
157159
// We use a Promise so the script doesn't block the initial page load
158160
const script = `
161+
const d=Date.now();console.log('preloader loading',d);
159162
import("${base}${preloadChunk}").then(({l,p})=>{
163+
console.log('preloader start',Date.now()-d);
160164
l(${JSON.stringify(base)},${JSON.stringify(manifestHash)});
161-
p(${JSON.stringify(prio.slice(0, 10))});
165+
p(${JSON.stringify(prio.slice(0, 20))});
162166
})
163167
`.replaceAll(/^\s+|\s*\n/gm, '');
164168

0 commit comments

Comments
 (0)