pagez

Redirects

A page that moved lists the paths it used to have under redirects, and Pagez writes each to dist/_redirects as a 301 to where the page is now (site.ts checks them). Cloudflare Pages and Netlify read that file, before the files they serve.

A page's path is still its file's. A redirect only points old addresses at it, so a site can move its files without breaking links from elsewhere. Nothing on the site goes through one, since a link to a redirect fails, asking for the page it reaches.

A host serves a page's folder at /x/ and sends /x and /x.html there itself, but an old address is no page's, so nothing sends its spellings. Each is a line, and a page lists an old address once. With a url in pagez.md, both sides are written from its path, as 404.html's links are, so a site served under /stories/ redirects there. A _redirects in public/ comes first, for the redirects that aren't a page's, such as to another site.

dev and preview send them too, from the root, where they serve the site (vite.ts).

import { spellings, type Site } from "./site.ts";

/** `_redirects`, one line for each spelling of each old address: `/old /blog/new/ 301`. */
export function redirectsFile(site: Site): string {
  const { url } = site.metadata;
  const base = typeof url === "string" ? new URL(url).pathname.replace(/\/$/, "") : "";
  const lines = [];
  for (const [address, { to }] of [...site.redirects].sort(([a], [b]) => (a < b ? -1 : 1))) {
    for (const from of spellings(address)) lines.push(`${base}${from} ${base}/${to.path} 301`);
  }
  return `${lines.join("\n")}\n`;
}

/** Where a request for `path`, from the root, is sent, when it's an old address's. */
export function redirectTo(site: Site, path: string): string | undefined {
  for (const [address, { to }] of site.redirects) {
    if (spellings(address).includes(path)) return `/${to.path}`;
  }
  return undefined;
}