Skip to content

Temp - modulepreload playground #7489

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

Closed
Closed
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
4 changes: 2 additions & 2 deletions packages/docs/src/root.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { component$, useContextProvider, useStore } from '@builder.io/qwik';
import { QwikCityProvider, RouterOutlet, ServiceWorkerRegister } from '@builder.io/qwik-city';
import { QwikCityProvider, RouterOutlet } from '@builder.io/qwik-city';
import { Insights } from '@builder.io/qwik-labs';
import RealMetricsOptimization from './components/real-metrics-optimization/real-metrics-optimization';
import { RouterHead } from './components/router-head/router-head';
Expand Down Expand Up @@ -56,7 +56,7 @@ export default component$(() => {
<script dangerouslySetInnerHTML={uwu} />
<RouterHead />

<ServiceWorkerRegister />
{/* <ServiceWorkerRegister /> */}

<script dangerouslySetInnerHTML={`(${collectSymbols})()`} />
<Insights publicApiKey={import.meta.env.PUBLIC_QWIK_INSIGHTS_KEY} />
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export default defineConfig(async () => {
],
},
}),
qwikVite({ debug: false }),
qwikVite({ debug: true }),
partytownVite({
dest: resolve('dist', '~partytown'),
}),
Expand Down
3 changes: 3 additions & 0 deletions packages/qwik/src/core/preloader/bundle-graph.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
import { isBrowser } from '@builder.io/qwik/build';
import {
config,
Expand Down Expand Up @@ -53,10 +54,12 @@ export const parseBundleGraph = (serialized: (string | number)[]) => {

export const getBundle = (name: string) => {
let bundle = bundles.get(name);
console.log('bundle :', bundle);
if (!bundle) {
let deps: ImportProbability[] | undefined;
if (graph) {
deps = graph.get(name);
console.log('deps :', deps);
if (!deps) {
return;
}
Expand Down
30 changes: 23 additions & 7 deletions packages/qwik/src/core/preloader/queue.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
import { isBrowser } from '@builder.io/qwik/build';
import { base, getBundle, graph } from './bundle-graph';
import {
Expand Down Expand Up @@ -68,24 +69,38 @@ export const getQueue = () => {
* We make sure to first preload the high priority items.
*/
export const trigger = () => {
const params = new URLSearchParams(window.location.search);
const limit = params.get('limit');
if (!queue.length) {
return;
}
sortQueue();
while (queue.length) {
const bundle = queue[0];
const inverseProbability = bundle.$inverseProbability$;
console.log('inverseProbability', inverseProbability);
const probability = 1 - inverseProbability;
const allowedPreloads = graph
? // The more likely the bundle, the more simultaneous preloads we want to allow
Math.max(1, config[maxSimultaneousPreloadsStr] * probability)
: // While the graph is not available, we limit to 2 preloads
2;
if (preloadCount < allowedPreloads) {
console.log('probability', probability);
console.log('limit :', limit);

if (probability === 1) {
queue.shift();
preloadOne(bundle);
} else {
break;
const allowedPreloads = graph
? // The more likely the bundle, the more simultaneous preloads we want to allow
Math.max(1, (Number(limit) || config[maxSimultaneousPreloadsStr]) * probability)
: // While the graph is not available, we limit to 2 preloads
2;
console.log('allowedPreloads :', allowedPreloads);
console.log('preloadCount :', preloadCount);

if (preloadCount < allowedPreloads) {
queue.shift();
preloadOne(bundle);
} else {
break;
}
}
}
/**
Expand Down Expand Up @@ -169,6 +184,7 @@ export const adjustProbabilities = (
seen ||= new Set();
seen.add(bundle);
for (const dep of bundle.$deps$) {
console.log('dep :', dep);
const depBundle = getBundle(dep.$name$)!;
const prevAdjust = dep.$factor$;
/**
Expand Down
84 changes: 17 additions & 67 deletions packages/qwik/src/optimizer/src/plugins/bundle-graph.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { getSymbolHash } from 'packages/qwik/src/core/qrl/qrl-class';
import type { QwikBundle, QwikBundleGraph, QwikManifest } from '../types';

const minimumSpeed = 300; // kbps
// size that takes 0.5 seconds to download at minimumSpeed
const slowSize = 0.5 / ((minimumSpeed * 1024) / 8);

/**
* A function that returns a map of bundle names to their dependencies.
*
Expand All @@ -13,14 +10,7 @@ export type BundleGraphAdder = (
manifest: QwikManifest
) => Record<string, { imports?: string[]; dynamicImports?: string[] }>;

const getSymbolHash = (symbolName: string) => {
const index = symbolName.lastIndexOf('_');
if (index > -1) {
return symbolName.slice(index + 1);
}
return symbolName;
};

const dynamicTag = '<dynamic>';
/**
* This creates a compact array of dependencies for each bundle. It also contains the symbols. The
* format is:
Expand All @@ -42,18 +32,18 @@ export function convertManifestToBundleGraph(
if (!manifest.bundles) {
return [];
}
// All known chunks and symbols
// All known chunks
const graph = { ...manifest.bundles };
for (const [symbol, bundleName] of Object.entries(manifest.mapping)) {
const hash = getSymbolHash(symbol);
if (hash) {
/**
* We use dynamic imports so that we will get probabilities for the bundle when preloading the
* symbol. We still confirm load at 100% probability with the bundle name.
*/
graph[hash] = { dynamicImports: [bundleName] } as QwikBundle;
}
}
// Symbols
Object.assign(
graph,
Object.fromEntries(
Object.entries(manifest.mapping).map(([symbol, chunkname]) => [
getSymbolHash(symbol),
{ imports: [chunkname] } as QwikBundle,
])
)
);
// Routes etc
if (bundleGraphAdders) {
for (const adder of bundleGraphAdders) {
Expand All @@ -64,11 +54,6 @@ export function convertManifestToBundleGraph(
}
}

// Remove the preloader, it will already be loaded and has no dependencies
if (manifest.preloader) {
delete graph[manifest.preloader];
}

// Filter out external and non-segment dynamic imports
for (const bundleName of Object.keys(graph)) {
const bundle = graph[bundleName];
Expand Down Expand Up @@ -135,47 +120,13 @@ export function convertManifestToBundleGraph(
clearTransitiveDeps(deps, depName);
}
const dynDeps = new Set(bundle.dynamicImports!);
const depProbability = new Map<string, number>();
for (const depName of dynDeps) {
clearTransitiveDeps(dynDeps, depName);
const dep = graph[depName];

// Calculate the probability of the dependency
// Start with a 50% chance
let probability = 0.5;
// Add a 4% chance for each interactivity point (max 20%)
probability += (dep.interactivity || 0) * 0.04;

// If the dependency has a segment from the same parent, it's more likely to be loaded
if (bundle.origins && dep.origins) {
for (const origin of bundle.origins) {
if (dep.origins.some((o) => o.startsWith(origin))) {
// Add a 25% chance
probability += 0.25;
break;
}
}
}

// If the dependency is a likely big import graph, it should be loaded earlier so it doesn't get blocked by smaller files, but when unlikely it should be loaded later so it doesn't block other files
if (dep.total > slowSize) {
probability += probability > 0.5 ? 0.02 : -0.02;
}

depProbability.set(depName, probability);
}

if (dynDeps.size > 0) {
const sorted = Array.from(dynDeps).sort(
(a, b) => depProbability.get(b)! - depProbability.get(a)!
);
let lastProbability = -1;
// We rely on the Set keeping the items in order, everything after this is dynamic
for (const depName of sorted) {
if (depProbability.get(depName)! !== lastProbability) {
lastProbability = depProbability.get(depName)!;
deps.add(-Math.round(lastProbability * 10) as any as string);
}
deps.add(dynamicTag);
for (const depName of dynDeps) {
deps.add(depName);
}
}
Expand All @@ -195,9 +146,8 @@ export function convertManifestToBundleGraph(
let { index, deps } = bundle;
index++;
for (const depName of deps) {
if (typeof depName === 'number') {
// negative number means dynamic import
bundleGraph[index++] = depName;
if (depName === dynamicTag) {
bundleGraph[index++] = -1;
continue;
}
const dep = map.get(depName)!;
Expand Down
Loading