Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support default human readable URLs #44

Merged
merged 2 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/layouts/base.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,19 @@ import { ViewTransitions } from "astro:transitions";

interface Props {
title: string;
id: string;
description?: string;
}

const { id, title } = Astro.props;
const { title, description } = Astro.props;
---

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<!-- <meta name="description" content="Astro description" /> -->
{description && <meta name="description" content={description} />}
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
<link rel="canonical" href=`${Astro.site}${id}` />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
<ViewTransitions />
Expand Down
6 changes: 3 additions & 3 deletions src/layouts/default.astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import BaseLayout from "./base.astro";
import Header from "@components/Header.astro";

interface Props {
id: string;
title: string;
description?: string;
}

const { id, title } = Astro.props;
const { title, description } = Astro.props;
---

<BaseLayout id={id} title={title}>
<BaseLayout title={title} description={description}>
<main class="lg-:container mx-auto px-6 py-2 max-w-screen-lg">
<Header />
<article class="prose lg:prose-xl mb-16">
Expand Down
5 changes: 2 additions & 3 deletions src/layouts/homepage.astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import BaseLayout from "./base.astro";
import Header from "@components/Header.astro";

interface Props {
id: string;
title: string;
}

const { id, title } = Astro.props;
const { title } = Astro.props;
---

<BaseLayout id={id} title={title}>
<BaseLayout title={title} description="Justin Bennett's personal website">
<main class="lg-:container mx-auto px-6 py-2 max-w-screen-lg">
<Header expanded={true} />
<article class="prose lg:prose-xl">
Expand Down
97 changes: 64 additions & 33 deletions src/pages/[...slug].astro
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
export const prerender = false;

/** 1 month in seconds */
const CACHE_TTL = 60 * 60 * 24 * 30;

// This matches to the note in my obsidian setup
// that's homepage. I probably could avoid hard coding this
// by having a mapping in the KV store, but this is
Expand All @@ -13,54 +16,82 @@ function isULID(ulid: string) {
return ulidRegex.test(ulid);
}

/**
* If a `get` KV request returns null and it was requested with a cacheTTL,
* the empty result will be cached. That's usually not what we want, so this
* function requests the slug again without a cacheTTL to bust the cache.
*/
function bustKVCache(slug: string) {
// We don't actually want to wait for this, we just want to make sure it happens
Astro.locals.runtime.ctx.waitUntil(
Astro.locals.runtime.env.KV_MAPPINGS.get(slug)
);
}

let { slug } = Astro.params;

// Automatically redirect home slug to root
if (slug === HOME_SLUG) {
return Astro.redirect("/", 308);
}

const originalSlug = slug;
// default to homepage slug
slug ??= HOME_SLUG;

let html = "";
let layout = "default";
let title = "";

if (!isULID(slug)) {
slug = (await Astro.locals.runtime.env.KV_MAPPINGS.get(slug)) as string;
if (!slug) return Astro.rewrite("/404");
slug = (await Astro.locals.runtime.env.KV_MAPPINGS.get(slug, {
cacheTtl: CACHE_TTL,
})) as string;
if (!slug) {
bustKVCache(slug);
return Astro.rewrite("/404");
}
}
slug = slug.toUpperCase();

if (isULID(slug)) {
let content = "";

// In dev read note from symlinked directory
if (process.env.NODE_ENV === "development") {
const fs = await import("node:fs/promises");
content = await fs.readFile(`./notes/${slug}.md`, "utf-8");

// In prod pull from R2
} else {
const result = await Astro.locals.runtime.env.R2_BUCKET.get(
slug.toUpperCase()
);
if (!result) return Astro.rewrite("/404");
content = await result.text();
// We've already done redirection of the home slug, so skip if it matches that
if (slug !== HOME_SLUG) {
// If the original path is different from the canonical mapping, redirect
const redirectPath = await Astro.locals.runtime.env.KV_MAPPINGS.get(slug, {
cacheTtl: CACHE_TTL,
});
if (redirectPath && redirectPath !== originalSlug) {
return Astro.redirect(redirectPath, 308);
}

if (!redirectPath) {
bustKVCache(slug);
}
if (!content) return Astro.rewrite("/404");
const { code, metadata } = await Astro.locals.render(content);
html = code;
title = metadata.frontmatter.title;
// The slice here is a hack to remove the "@layouts/" and ".astro" from the layout name
// so that the import below works correctly
layout = metadata.frontmatter.layout.slice(9, -6);
}

let content = "";

// In dev read note from symlinked directory
if (process.env.NODE_ENV === "development") {
const fs = await import("node:fs/promises");
content = await fs.readFile(`./notes/${slug}.md`, "utf-8");

// In prod pull from R2
} else {
const result = await Astro.locals.runtime.env.R2_BUCKET.get(slug);
if (!result) return Astro.rewrite("/404");
content = await result.text();
}
if (!content) return Astro.rewrite("/404");

const { code: html = "", metadata } = await Astro.locals.render(content);
if (!html) return Astro.rewrite("/404");

// The slug is used to determine the canonical URL. For every page that _isn't_ the hope page I want that
// to the the ULID. For the home page, I just want the root URL to be canonical.
slug = slug === HOME_SLUG ? "" : slug;
const { title, description, layout = "default" } = metadata.frontmatter;

// The slice here is a hack to remove the "@layouts/" and ".astro" from the layout name
// so that the import below works correctly
const layoutName = layout.slice(9, -6);

const Layout = (await import(`../layouts/${layout}.astro`)).default;
const Layout = (await import(`../layouts/${layoutName}.astro`)).default;
---

<Layout id={slug} title={title}>
<Layout title={title} description={description}>
<Fragment set:html={html} />
</Layout>
Loading