fix(aliases): Teach SPA and popovers to handle HTML redirects

Currently alias links do a full *double* page refresh when clicked
and have no popovers, which is caused by the HTML redirect pages
that are emitted by AliasRedirects.

This is very bad, but the fix was easy
This commit is contained in:
Anton Bulakh 2024-12-24 02:03:09 +02:00
parent a582505daf
commit cd08056cea
No known key found for this signature in database
GPG Key ID: 071FE3E324DD7333
3 changed files with 23 additions and 2 deletions

View File

@ -1,5 +1,6 @@
import { computePosition, flip, inline, shift } from "@floating-ui/dom" import { computePosition, flip, inline, shift } from "@floating-ui/dom"
import { normalizeRelativeURLs } from "../../util/path" import { normalizeRelativeURLs } from "../../util/path"
import { fetchCanonical } from "./util"
const p = new DOMParser() const p = new DOMParser()
async function mouseEnterHandler( async function mouseEnterHandler(
@ -37,7 +38,7 @@ async function mouseEnterHandler(
targetUrl.hash = "" targetUrl.hash = ""
targetUrl.search = "" targetUrl.search = ""
const response = await fetch(`${targetUrl}`).catch((err) => { const response = await fetchCanonical(targetUrl).catch((err) => {
console.error(err) console.error(err)
}) })

View File

@ -1,5 +1,6 @@
import micromorph from "micromorph" import micromorph from "micromorph"
import { FullSlug, RelativeURL, getFullSlug, normalizeRelativeURLs } from "../../util/path" import { FullSlug, RelativeURL, getFullSlug, normalizeRelativeURLs } from "../../util/path"
import { fetchCanonical } from "./util"
// adapted from `micromorph` // adapted from `micromorph`
// https://github.com/natemoo-re/micromorph // https://github.com/natemoo-re/micromorph
@ -45,7 +46,7 @@ window.addCleanup = (fn) => cleanupFns.add(fn)
let p: DOMParser let p: DOMParser
async function navigate(url: URL, isBack: boolean = false) { async function navigate(url: URL, isBack: boolean = false) {
p = p || new DOMParser() p = p || new DOMParser()
const contents = await fetch(`${url}`) const contents = await fetchCanonical(url)
.then((res) => { .then((res) => {
const contentType = res.headers.get("content-type") const contentType = res.headers.get("content-type")
if (contentType?.startsWith("text/html")) { if (contentType?.startsWith("text/html")) {

View File

@ -24,3 +24,22 @@ export function removeAllChildren(node: HTMLElement) {
node.removeChild(node.firstChild) 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 = /<link rel="canonical" href="([^"]*)">/
export async function fetchCanonical(url: URL): Promise<Response> {
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
}