From 65b4ac5ad309d343cf0a594b0ba27fc1d2817333 Mon Sep 17 00:00:00 2001 From: Local Dev Date: Sat, 3 Oct 2026 16:39:45 +0200 Subject: [PATCH] =?UTF-8?q?perf(aegis):=20251=20KB=20off=20every=20panel?= =?UTF-8?q?=20open=20=E2=80=94=20jsQR=20loads=20when=20it=20is=20wanted?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit panel.html loaded lib/jsqr.js synchronously: 257 KB and 10,105 lines of vendored decoder parsed on every panel open, so on every hide/show, for a feature most sessions never touch. It is now fetched the first time someone imports a QR image, with concurrent callers sharing one load and a failed load retryable rather than cached as a permanent rejection. qr.js and panel.js get `defer`, so the browser can paint the (already dark) document before executing 300 KB of panel.js. Order is preserved, so qr.js is still defined before panel.js runs. Parsed on open: 650 KB -> 399 KB. This shortens the blank window but does not remove it. The white box itself is Theseus-side: the sidebar panel's view is built as new WebContentsView({ webPreferences: { preload: "sidebar-preload.js" } }) with no backgroundColor, and Electron defaults a view's background to white — so white shows from view-attach until the page paints. Every other view in the app passes a colour, and registerSidebarPanel takes only {id, title, icon, page}, so an add-on cannot declare one. Not fixed here: main.js belongs to the Theseus work in flight. --- bundled-addons/aegis/addon.json | 2 +- bundled-addons/aegis/panel.html | 12 +++++++++--- bundled-addons/aegis/panel.js | 20 +++++++++++++++++++- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/bundled-addons/aegis/addon.json b/bundled-addons/aegis/addon.json index 9298ab4d..f87b5b92 100644 --- a/bundled-addons/aegis/addon.json +++ b/bundled-addons/aegis/addon.json @@ -1,7 +1,7 @@ { "id": "aegis", "name": "Aegis Wallet", - "version": "0.28.0", + "version": "0.28.1", "category": "plugin", "description": "Multi-chain wallet (BCH, BTC, TRX, ETH, SOL, SC, DGB) derived from your Theseus vault. Dapps get window.bitcoincash and window.wizardconnect on any site; window.tronWeb / window.tronLink / window.ethereum / window.solana too. Every call needs your approval.", "author": "Silent Mode", diff --git a/bundled-addons/aegis/panel.html b/bundled-addons/aegis/panel.html index 594e5478..117fb6bf 100644 --- a/bundled-addons/aegis/panel.html +++ b/bundled-addons/aegis/panel.html @@ -1387,8 +1387,14 @@ - - - + + + diff --git a/bundled-addons/aegis/panel.js b/bundled-addons/aegis/panel.js index d5817974..dc501fa4 100644 --- a/bundled-addons/aegis/panel.js +++ b/bundled-addons/aegis/panel.js @@ -1619,8 +1619,26 @@ function classifyScannedSecret(text) { return { kind: "unknown", value: s }; } +// jsQR is 257 KB of vendored decoder and it is only needed when someone +// actually imports a QR image. Loading it from panel.html meant every panel +// open — every hide/show — parsed all of it before panel.js even started. +// Fetch it the first time it is wanted instead. +let jsqrLoad = null; +function loadJsQr() { + if (typeof jsQR === "function") return Promise.resolve(); + if (jsqrLoad) return jsqrLoad; + jsqrLoad = new Promise((resolve, reject) => { + const el = document.createElement("script"); + el.src = "lib/jsqr.js"; + el.onload = () => (typeof jsQR === "function" ? resolve() : reject(new Error("the QR decoder loaded but exposed nothing"))); + el.onerror = () => { jsqrLoad = null; reject(new Error("the QR decoder failed to load")); }; + document.head.appendChild(el); + }); + return jsqrLoad; +} + async function decodeQrFile(file) { - if (typeof jsQR !== "function") throw new Error("the QR decoder failed to load"); + await loadJsQr(); const bitmap = await createImageBitmap(file); try { // Very large photos cost time and memory for no accuracy gain; jsQR wants