From c122089ef8dbdd07827da04c18db1e61cb86cf0b Mon Sep 17 00:00:00 2001 From: mARTin-B78 Date: Fri, 29 May 2026 20:21:35 +0200 Subject: [PATCH] Parallel-load inactive sections alongside JS to cut startup time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously all 11 section HTMLs had to complete before JS loading began. Now only the active section loads first (needed before JS runs so event listeners find their DOM elements). The other 10 sections fetch in parallel with utils + settings; an explicit await before the 9-module feature batch guarantees all section HTML is injected before any feature module sets up its DOM listeners. On a local server the HTML files finish well before settings.js completes, so the await is typically instant. Sequential steps cut from: sections(11∥) + utils + settings + features + ... to: section(1) + max(utils+settings, sections(10∥)) + features + ... Co-Authored-By: Claude Sonnet 4.6 --- static/loader.js | 80 ++++++++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/static/loader.js b/static/loader.js index 7432dca..d3e992b 100644 --- a/static/loader.js +++ b/static/loader.js @@ -7,9 +7,12 @@ 's-llms', 's-conversation', ]; + // Determine which section to show first (same logic as nav.js) + var _savedSection = localStorage.getItem('ttsvc_section'); + var _activeSection = (_savedSection && SECTIONS.indexOf(_savedSection) !== -1) + ? _savedSection : 's-voices'; + // ── Fetch app version once for JS cache-busting ────────────────────────── - // JS files are served with ?v= so the browser can cache them - // aggressively. Sections use Date.now() to always get fresh HTML. var _appVersion = 'dev'; try { var _vr = await fetch('/api/version'); @@ -17,35 +20,50 @@ _appVersion = _vd.version || _appVersion; } catch (_) {} - // ── 1. Fetch all section HTML partials in parallel ──────────────────────── var _ts = Date.now(); // sections always fresh during a session - await Promise.all(SECTIONS.map(async function (id) { - try { - var res = await fetch('/static/sections/' + id + '.html?v=' + _ts); - if (!res.ok) throw new Error(res.status + ' ' + res.statusText); - var el = document.getElementById(id); - if (el) el.innerHTML = await res.text(); - } catch (e) { - console.error('[loader] section', id, 'failed:', e.message); - var el = document.getElementById(id); - if (el) el.innerHTML = - '

Failed to load section ' + - id + ': ' + e.message + '

'; - } - })); - // ── 2. Load JS in parallel batches ──────────────────────────────────────── + function _inject(id, html) { + var el = document.getElementById(id); + if (el) el.innerHTML = html; + } + + // ── 1. Load ONLY the active section before anything else ───────────────── + // Feature modules set up DOM event listeners — the active section's elements + // must exist when JS runs. Other sections are loaded in step 2. + try { + var _ar = await fetch('/static/sections/' + _activeSection + '.html?v=' + _ts); + if (!_ar.ok) throw new Error(_ar.status + ' ' + _ar.statusText); + _inject(_activeSection, await _ar.text()); + } catch (e) { + var _ael = document.getElementById(_activeSection); + if (_ael) _ael.innerHTML = + '

Failed to load section ' + + _activeSection + ': ' + e.message + '

'; + } + + // ── 2. Fetch remaining sections in background (parallel with JS loading) ── + // These run concurrently with utils + settings below. Because section HTML + // files are much smaller than JS, they finish before the feature-module batch + // needs them. + var _bgSections = Promise.all( + SECTIONS.filter(function (id) { return id !== _activeSection; }) + .map(async function (id) { + try { + var res = await fetch('/static/sections/' + id + '.html?v=' + _ts); + if (!res.ok) throw new Error(res.status + ' ' + res.statusText); + _inject(id, await res.text()); + } catch (e) { + var el = document.getElementById(id); + if (el) el.innerHTML = + '

Failed to load section ' + + id + ': ' + e.message + '

'; + } + }) + ); + + // ── 3. Load JS in parallel batches ──────────────────────────────────────── // Scripts with async=false are FETCHED in parallel but EXECUTED in DOM // insertion order — safe for modules that share a global scope. - // - // Batch order: - // A) utils.js — defines $, toast, escHtml; needed by everything - // B) settings.js — declares _appSettings; needed before features read it - // C) Feature modules — parallel fetch + ordered execute - // D) init.js — calls loadSettings() + initBenchmarkSampleControls() - // E) Post-init modules — parallel fetch + ordered execute - // F) nav.js — navigation overrides; must be last - function _load(src) { return new Promise(function (resolve, reject) { var s = document.createElement('script'); @@ -58,8 +76,6 @@ } function _loadBatch(srcs) { - // Append all