What’s up everyone? I’m wiring up a theming panel and I’m trying to fetch a brand palette from an API without hammering it, but I also don’t want stale colors to stick around after a deploy (ETag/304 weirdness + cache invalidation races).
const mem = new Map();
export async function getThemePalette(url, { ttlMs = 5 * 60_000 } = {}) {
const now = Date.now();
const hit = mem.get(url);
if (hit && hit.expiresAt > now) return hit.value;
const res = await fetch(url, {
cache: "no-cache", // allow revalidation, avoid stuck CDN/browser cache
headers: hit?.etag ? { "If-None-Match": hit.etag } : {}
});
if (res.status === 304 && hit) return hit.value;
const etag = res.headers.get("etag") || undefined;
const json = await res.json();
const value = normalizePalette(json); // expects { primaryHsl: [h,s,l], ... }
mem.set(url, { value, etag, expiresAt: now + ttlMs });
return value;
}
export function themeCssVars(p) {
const [h, s, l] = p.primaryHsl;
const bg = `hsl(${h} ${s}% ${Math.max(6, l - 42)}%)`;
const fg = `hsl(${h} ${Math.min(22, s)}% ${Math.min(96, l + 52)}%)`;
return {
"--primary": `hsl(${h} ${s}% ${l}%)`,
"--bg": bg,
"--fg": fg,
"--grad": `linear-gradient(135deg, ${bg}, hsl(${h} ${s}% ${l}%))`
};
}
The neat part is it gives me a stable HSL-based palette and a quick gradient/contrast-ish set of CSS vars while still playing nice with revalidation, so the UI doesn’t flash between old/new themes when the network is flaky.