UNPKG

@builder.io/qwik

Version:

An Open-Source sub-framework designed with a focus on server-side-rendering, lazy-loading, and styling/animation.

201 lines (200 loc) 5.57 kB
import { isBrowser } from "@builder.io/qwik/build"; const doc = isBrowser ? document : void 0; const modulePreloadStr = "modulepreload"; const preloadStr = "preload"; const config = { t: 0, o: 25, l: 0.65 }; const rel = isBrowser && doc.createElement("link").relList.supports(modulePreloadStr) ? modulePreloadStr : preloadStr; const loadStart = Date.now(); const isJSRegex = /\.[mc]?js$/; const BundleImportState_None = 0; const BundleImportState_Queued = 1; const BundleImportState_Preload = 2; const BundleImportState_Alias = 3; const BundleImportState_Loaded = 4; const bundles = /* @__PURE__ */ new Map(); let queueDirty; let preloadCount = 0; const queue = []; const log = (...e) => { console.log(`Preloader ${Date.now() - loadStart}ms ${preloadCount}/${queue.length} queued>`, ...e); }; const sortQueue = () => { if (queueDirty) { queue.sort((e, t) => e.u - t.u); queueDirty = 0; } }; const trigger = () => { if (!queue.length) return; sortQueue(); while (queue.length) { const e = queue[0]; const t = e.u; const o = 1 - t; const n = graph ? ( // The more likely the bundle, the more simultaneous preloads we want to allow Math.max(1, config.o * o) ) : ( // While the graph is not available, we limit to 2 preloads 2 ); if (o >= 0.99 || preloadCount < n) { queue.shift(); preloadOne(e); } else break; } if (config.t && !queue.length) { const e = [...bundles.values()].filter((e2) => e2.i > BundleImportState_None); const t = e.reduce((e2, t2) => e2 + t2.p, 0); const o = e.reduce((e2, t2) => e2 + t2.$, 0); log(`>>>> done ${e.length}/${bundles.size} total: ${t}ms waited, ${o}ms loaded`); } }; const preloadOne = (e) => { if (e.i >= BundleImportState_Preload) return; preloadCount++; const t = Date.now(); e.p = t - e.m; e.i = BundleImportState_Preload; config.t && log(`<< load ${Math.round((1 - e.u) * 100)}% after ${`${e.p}ms`}`, e.B); const o = doc.createElement("link"); o.href = new URL(`${base}${e.B}`, doc.baseURI).toString(); o.rel = rel; o.as = "script"; o.onload = o.onerror = () => { preloadCount--; const n = Date.now(); e.$ = n - t; e.i = BundleImportState_Loaded; config.t && log(`>> done after ${e.$}ms`, e.B); o.remove(); trigger(); }; doc.head.appendChild(o); }; const adjustProbabilities = (e, t, o) => { if (o?.has(e)) return; const n = e.u; e.u = t; if (n - e.u < 0.01) return; if ( // don't queue until we have initialized the preloader base != null && e.i < BundleImportState_Preload && e.u < config.l ) { if (e.i === BundleImportState_None) { e.i = BundleImportState_Queued; queue.push(e); config.t && log(`queued ${Math.round((1 - e.u) * 100)}%`, e.B); } queueDirty = 1; } if (e.h) { o ||= /* @__PURE__ */ new Set(); o.add(e); const t2 = 1 - e.u; for (const n2 of e.h) { const e2 = getBundle(n2.B); if (e2.u === 0) continue; let r; if (n2.S > 0.5 && (t2 === 1 || t2 >= 0.99 && depsCount < 100)) { depsCount++; r = Math.min(0.01, 1 - n2.S); } else { const o2 = 1 - n2.S * t2; const l = n2.q; const s = o2 / l; r = Math.max(0.02, e2.u * s); n2.q = s; } adjustProbabilities(e2, r, o); } } }; const handleBundle = (e, t) => { const o = getBundle(e); if (o && o.u > t) adjustProbabilities(o, t); }; let depsCount; const preload = (e, t) => { if (!e?.length) return; depsCount = 0; let o = t ? 1 - t : 0.4; if (Array.isArray(e)) for (let t2 = e.length - 1; t2 >= 0; t2--) { const n = e[t2]; if (typeof n === "number") o = 1 - n / 10; else handleBundle(n, o); } else handleBundle(e, o); if (isBrowser) trigger(); }; if (isBrowser) document.addEventListener("qsymbol", (e) => { const { symbol: t, href: o } = e.detail; if (o) { const e2 = t.slice(t.lastIndexOf("_") + 1); preload(e2, 1); } }); let base; let graph; const makeBundle = (e, t) => ({ B: e, i: isJSRegex.test(e) ? BundleImportState_None : BundleImportState_Alias, h: t, u: 1, m: Date.now(), p: 0, $: 0 }); const parseBundleGraph = (e) => { const t = /* @__PURE__ */ new Map(); let o = 0; while (o < e.length) { const n = e[o++]; const r = []; let l; let s = 1; while (l = e[o], typeof l === "number") { if (l < 0) s = -l / 10; else r.push({ B: e[l], S: s, q: 1 }); o++; } t.set(n, r); } return t; }; const getBundle = (e) => { let t = bundles.get(e); if (!t) { let o; if (graph) { o = graph.get(e); if (!o) return; if (!o.length) o = void 0; } t = makeBundle(e, o); bundles.set(e, t); } return t; }; const loadBundleGraph = (e, t, o) => { if (o) { if ("d" in o) config.t = !!o.d; if ("P" in o) config.o = o["P"]; if ("Q" in o) config.l = 1 - o["Q"]; } if (!isBrowser || e == null) return; base = e; if (t) t.then((e2) => e2.text()).then((e2) => { graph = parseBundleGraph(JSON.parse(e2)); const t2 = []; for (const [e3, o2] of graph.entries()) { const n = getBundle(e3); n.h = o2; if (n.u < 1) { t2.push([n, n.u]); n.u = 1; } } config.t && log(`parseBundleGraph got ${graph.size} bundles, adjusting ${t2.length}`); for (const [e3, o2] of t2) adjustProbabilities(e3, o2); trigger(); }).catch(console.warn); }; export { parseBundleGraph as g, handleBundle as h, loadBundleGraph as l, preload as p };