loader.js:
- Fetch /api/version first; append ?v=<version> to every script URL
- Load scripts with async=false (fetch in parallel, execute in DOM order)
- 4 sequential batches instead of 17 sequential awaits:
utils → settings → [9 feature modules] → init → [4 post-init] → nav
- 17 round-trips → 6 round-trips; 9 and 4 files now download in parallel
- Section HTML keeps ?v=<timestamp> (no-store, always fresh)
server.py:
- Add static_cache_headers middleware:
/static/js/*?v=... → Cache-Control: max-age=31536000, immutable
/static/sections/* → Cache-Control: no-store
/static/* (no v=) → Cache-Control: max-age=3600
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
97 lines
3.7 KiB
JavaScript
97 lines
3.7 KiB
JavaScript
(async function () {
|
|
'use strict';
|
|
|
|
const SECTIONS = [
|
|
's-voices', 's-clone', 's-design', 's-studio', 's-tryout',
|
|
's-performance', 's-routing', 's-connect', 's-settings',
|
|
's-llms', 's-conversation',
|
|
];
|
|
|
|
// ── Fetch app version once for JS cache-busting ──────────────────────────
|
|
// JS files are served with ?v=<version> 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');
|
|
var _vd = await _vr.json();
|
|
_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 =
|
|
'<p style="color:var(--red);padding:24px">Failed to load section <b>' +
|
|
id + '</b>: ' + e.message + '</p>';
|
|
}
|
|
}));
|
|
|
|
// ── 2. 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');
|
|
s.src = src + '?v=' + _appVersion;
|
|
s.async = false; // fetch in parallel, execute in DOM order
|
|
s.onload = resolve;
|
|
s.onerror = function () { reject(new Error('Failed to load ' + src)); };
|
|
document.body.appendChild(s);
|
|
});
|
|
}
|
|
|
|
function _loadBatch(srcs) {
|
|
// Append all <script async=false> at once → browser fetches all in parallel
|
|
// and executes them in the order they were appended.
|
|
return Promise.all(srcs.map(_load));
|
|
}
|
|
|
|
// A — foundation (sequential: each must finish before the next batch starts)
|
|
await _load('/static/js/utils.js');
|
|
await _load('/static/js/settings.js');
|
|
|
|
// C — feature modules (9 files fetched in parallel, executed in order)
|
|
await _loadBatch([
|
|
'/static/js/voice-inspector.js',
|
|
'/static/js/voice-sources.js',
|
|
'/static/js/integrations.js',
|
|
'/static/js/routing.js',
|
|
'/static/js/voice-clone.js',
|
|
'/static/js/voice-library.js',
|
|
'/static/js/tts-preview.js',
|
|
'/static/js/benchmark.js',
|
|
'/static/js/stt.js',
|
|
]);
|
|
|
|
// D — init (needs everything above to be defined)
|
|
await _load('/static/js/init.js');
|
|
|
|
// E — post-init modules (4 files fetched in parallel, executed in order)
|
|
await _loadBatch([
|
|
'/static/js/engines.js',
|
|
'/static/js/ai-backends.js',
|
|
'/static/js/generation.js',
|
|
'/static/js/conversation.js',
|
|
]);
|
|
|
|
// F — navigation
|
|
await _load('/static/nav.js');
|
|
})();
|