Skip to content

Instantly share code, notes, and snippets.

@maiah
Created July 14, 2026 23:34
Show Gist options
  • Select an option

  • Save maiah/599be4017ce96190db1880b037f1dcc9 to your computer and use it in GitHub Desktop.

Select an option

Save maiah/599be4017ce96190db1880b037f1dcc9 to your computer and use it in GitHub Desktop.
Astro Client Router with Cache
---
import { ClientRouter } from "astro:transitions";
---
<ClientRouter />
<script>
import { pathCache } from "./path-cache";
document.addEventListener("astro:before-preparation", (ev) => {
// 1. Grab the element from the event payload, or fallback to querying the DOM
const anchor =
(ev.sourceElement as HTMLElement) ||
document.querySelector(`a[href="${ev.to.pathname}"]`);
const cacheKey = anchor?.dataset.astroCachePath || ev.to.pathname;
console.log("========== astro:before-preparation triggered!!!", cacheKey);
const cachedDocument = pathCache.get(cacheKey);
if (cachedDocument) {
console.log("======== cache hit");
ev.loader = async () => {};
}
});
document.addEventListener("astro:before-swap", (ev) => {
console.log("========== astro:before-swap triggered!!!");
console.log("ev.to:", ev.to);
const anchor = document.querySelector(
`a[href="${ev.to.pathname}"]`,
) as HTMLElement | null;
const cacheKey = anchor?.dataset.astroCachePath || ev.to.pathname;
const cachedDoc = pathCache.get(cacheKey);
if (cachedDoc) {
console.log("======== re-using cached document");
const newDoc = document.implementation.createHTMLDocument("New Document");
newDoc.replaceChild(
cachedDoc.documentElement.cloneNode(true),
newDoc.documentElement,
);
ev.newDocument = newDoc;
} else {
console.log(
"======== caching new document",
ev.newDocument.body.firstChild,
);
const newDoc = document.implementation.createHTMLDocument("New Document");
newDoc.replaceChild(
ev.newDocument.documentElement.cloneNode(true),
newDoc.documentElement,
);
pathCache.save(cacheKey, newDoc);
}
});
</script>
class PathCache {
private cache = new Map<string, Document>();
private tags = new Map<string, { id: string; document: Document }[]>();
get(path: string): Document | undefined {
return this.cache.get(path);
}
save(path: string, document: Document) {
this.cache.set(path, document);
}
saveTag(tag: string, id: string, document: Document) {
const tagEntries = this.tags.get(tag) || [];
tagEntries.push({ id, document });
this.tags.set(tag, tagEntries);
}
invalidate(path: string) {
this.cache.delete(path);
}
invalidateTag(tag: string) {
this.tags.delete(tag);
}
}
export const pathCache = new PathCache();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment