From 99011cb1b0d20da9cb523729ed0e9ff4e9c27405 Mon Sep 17 00:00:00 2001 From: Anton Bulakh Date: Fri, 27 Dec 2024 16:18:22 +0200 Subject: [PATCH] fix(spa): handle HTML redirects for aliases (#1680) --- quartz/components/scripts/popover.inline.ts | 3 ++- quartz/components/scripts/spa.inline.ts | 3 ++- quartz/components/scripts/util.ts | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/quartz/components/scripts/popover.inline.ts b/quartz/components/scripts/popover.inline.ts index 49f4382..b01af0e 100644 --- a/quartz/components/scripts/popover.inline.ts +++ b/quartz/components/scripts/popover.inline.ts @@ -1,5 +1,6 @@ import { computePosition, flip, inline, shift } from "@floating-ui/dom" import { normalizeRelativeURLs } from "../../util/path" +import { fetchCanonical } from "./util" const p = new DOMParser() async function mouseEnterHandler( @@ -37,7 +38,7 @@ async function mouseEnterHandler( targetUrl.hash = "" targetUrl.search = "" - const response = await fetch(`${targetUrl}`).catch((err) => { + const response = await fetchCanonical(targetUrl).catch((err) => { console.error(err) }) diff --git a/quartz/components/scripts/spa.inline.ts b/quartz/components/scripts/spa.inline.ts index b67dad0..df48f04 100644 --- a/quartz/components/scripts/spa.inline.ts +++ b/quartz/components/scripts/spa.inline.ts @@ -1,5 +1,6 @@ import micromorph from "micromorph" import { FullSlug, RelativeURL, getFullSlug, normalizeRelativeURLs } from "../../util/path" +import { fetchCanonical } from "./util" // adapted from `micromorph` // https://github.com/natemoo-re/micromorph @@ -59,7 +60,7 @@ let p: DOMParser async function navigate(url: URL, isBack: boolean = false) { startLoading() p = p || new DOMParser() - const contents = await fetch(`${url}`) + const contents = await fetchCanonical(url) .then((res) => { const contentType = res.headers.get("content-type") if (contentType?.startsWith("text/html")) { diff --git a/quartz/components/scripts/util.ts b/quartz/components/scripts/util.ts index d0a16c6..c1db8ba 100644 --- a/quartz/components/scripts/util.ts +++ b/quartz/components/scripts/util.ts @@ -24,3 +24,22 @@ export function removeAllChildren(node: HTMLElement) { node.removeChild(node.firstChild) } } + +// AliasRedirect emits HTML redirects which also have the link[rel="canonical"] +// containing the URL it's redirecting to. +// Extracting it here with regex is _probably_ faster than parsing the entire HTML +// with a DOMParser effectively twice (here and later in the SPA code), even if +// way less robust - we only care about our own generated redirects after all. +const canonicalRegex = // + +export async function fetchCanonical(url: URL): Promise { + const res = await fetch(`${url}`) + if (!res.headers.get("content-type")?.startsWith("text/html")) { + return res + } + // reading the body can only be done once, so we need to clone the response + // to allow the caller to read it if it's was not a redirect + const text = await res.clone().text() + const [_, redirect] = text.match(canonicalRegex) ?? [] + return redirect ? fetch(redirect) : res +}