Cache sx component definitions in localStorage across page loads
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m30s

Server computes SHA-256 hash of all component source at startup.
Client signals its cached hash via cookie (sx-comp-hash). On full
page load: cookie match → server sends empty script tag with just
the hash; mismatch → sends full source. Client loads from
localStorage on hit, parses inline + caches on miss.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-02 00:57:53 +00:00
parent 4ede0368dc
commit 5436dfe76c
3 changed files with 122 additions and 13 deletions

View File

@@ -1342,9 +1342,56 @@
var text = s.textContent;
if (!text || !text.trim()) continue;
// data-components: load as component definitions
// data-components: load as component definitions (with localStorage caching)
if (s.hasAttribute("data-components")) {
Sx.loadComponents(text);
var hash = s.getAttribute("data-hash");
if (hash) {
var hasInline = text && text.trim();
try {
var cachedHash = localStorage.getItem("sx-components-hash");
if (cachedHash === hash) {
// Cache hit
if (hasInline) {
// Server sent full source (cookie was missing/stale) — update cache
localStorage.setItem("sx-components-src", text);
Sx.loadComponents(text);
} else {
// Server omitted source — load from cache
var cached = localStorage.getItem("sx-components-src");
if (cached) {
Sx.loadComponents(cached);
} else {
// Cache entry missing — clear cookie and reload to get full source
_clearSxCompCookie();
location.reload();
return;
}
}
} else {
// Cache miss — hash mismatch
if (hasInline) {
// Server sent full source — parse and cache
localStorage.setItem("sx-components-hash", hash);
localStorage.setItem("sx-components-src", text);
Sx.loadComponents(text);
} else {
// Server omitted source but our cache is stale — clear and reload
localStorage.removeItem("sx-components-hash");
localStorage.removeItem("sx-components-src");
_clearSxCompCookie();
location.reload();
return;
}
}
} catch (e) {
// localStorage unavailable — fall back to inline
if (hasInline) Sx.loadComponents(text);
}
_setSxCompCookie(hash);
} else {
// Legacy: no hash attribute — just load inline
if (text && text.trim()) Sx.loadComponents(text);
}
continue;
}
@@ -2396,6 +2443,18 @@
return text;
}
// ---------------------------------------------------------------------------
// sx-comp-hash cookie helpers (component caching)
// ---------------------------------------------------------------------------
function _setSxCompCookie(hash) {
document.cookie = "sx-comp-hash=" + hash + ";path=/;max-age=31536000;SameSite=Lax";
}
function _clearSxCompCookie() {
document.cookie = "sx-comp-hash=;path=/;max-age=0;SameSite=Lax";
}
if (typeof document !== "undefined") {
var init = function () {
console.log("[sx.js] v" + Sx.VERSION + " init");