mirror of
https://github.com/apophenia-news/apophenia.news.git
synced 2026-10-29 14:54:54 +00:00
Feat: Add a 404 page so unknown URLs stop serving the homepage
Cloudflare Pages falls back to the homepage with a 200 when there's no 404.html, which Google treats as soft 404s. The generated 404.html is noindex and shows a detective gif from vibegif. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@ import { marked } from "marked";
|
|||||||
import markedKatex from "marked-katex-extension";
|
import markedKatex from "marked-katex-extension";
|
||||||
import { ARTICLES_GLOB, AUTHOR_PAGES, ROOT, SRC, UNLISTED_PATH } from "./lib/constants.mjs";
|
import { ARTICLES_GLOB, AUTHOR_PAGES, ROOT, SRC, UNLISTED_PATH } from "./lib/constants.mjs";
|
||||||
import { fixInternalLinks } from "./lib/utils.mjs";
|
import { fixInternalLinks } from "./lib/utils.mjs";
|
||||||
import { renderArticle, renderHome, renderWritePage, renderNewsletterPage, renderUnsubscribePage, renderAuthorPage } from "./lib/renderers.mjs";
|
import { renderArticle, renderHome, renderWritePage, renderNewsletterPage, renderUnsubscribePage, renderAuthorPage, renderNotFound } from "./lib/renderers.mjs";
|
||||||
import { ensureCleanGenerated, writeDiscoveryFiles, writePage } from "./lib/io.mjs";
|
import { ensureCleanGenerated, writeDiscoveryFiles, writePage } from "./lib/io.mjs";
|
||||||
|
|
||||||
marked.use(markedKatex({ throwOnError: false, nonStandard: true }));
|
marked.use(markedKatex({ throwOnError: false, nonStandard: true }));
|
||||||
@@ -67,6 +67,7 @@ const run = async () => {
|
|||||||
await writePage([SRC, "write", "index.html"], renderWritePage());
|
await writePage([SRC, "write", "index.html"], renderWritePage());
|
||||||
await writePage([SRC, "newsletter", "index.html"], renderNewsletterPage());
|
await writePage([SRC, "newsletter", "index.html"], renderNewsletterPage());
|
||||||
await writePage([SRC, "newsletter", "unsubscribe.html"], renderUnsubscribePage());
|
await writePage([SRC, "newsletter", "unsubscribe.html"], renderUnsubscribePage());
|
||||||
|
await writePage([SRC, "404.html"], renderNotFound());
|
||||||
|
|
||||||
for (const author of AUTHOR_PAGES) {
|
for (const author of AUTHOR_PAGES) {
|
||||||
await writePage([SRC, "author", author.slug, "index.html"], renderAuthorPage(author));
|
await writePage([SRC, "author", author.slug, "index.html"], renderAuthorPage(author));
|
||||||
@@ -79,7 +80,7 @@ const run = async () => {
|
|||||||
|
|
||||||
await writeDiscoveryFiles(listedArticles, AUTHOR_PAGES);
|
await writeDiscoveryFiles(listedArticles, AUTHOR_PAGES);
|
||||||
|
|
||||||
console.log(`Generated ${articles.length} article pages (${listedArticles.length} listed) + home + write + newsletter + unsubscribe + author pages + rss/sitemap/robots.`);
|
console.log(`Generated ${articles.length} article pages (${listedArticles.length} listed) + home + write + newsletter + unsubscribe + author pages + 404 + rss/sitemap/robots.`);
|
||||||
};
|
};
|
||||||
|
|
||||||
run().catch((err) => {
|
run().catch((err) => {
|
||||||
|
|||||||
@@ -95,6 +95,29 @@ ${nav}
|
|||||||
${footer}
|
${footer}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
// Served by Cloudflare Pages with a 404 status for any path that doesn't exist (instead of falling back to the homepage)
|
||||||
|
export const renderNotFound = () => `
|
||||||
|
${shellHead({
|
||||||
|
title: "Page not found — apophenia.news",
|
||||||
|
desc: "This page doesn't exist.",
|
||||||
|
type: "website",
|
||||||
|
noindex: true
|
||||||
|
})}
|
||||||
|
${nav}
|
||||||
|
<main class="shell py-10">
|
||||||
|
<section class="card p-6 sm:p-10 text-center bg-gradient-to-b from-white to-indigo-50/50">
|
||||||
|
<img src="https://vibegif.direct-img.link/detective/clue.webp" alt="Detective searching for clues with a magnifying glass" width="256" height="256" class="mx-auto h-48 w-48" />
|
||||||
|
<p class="tag mt-6 mb-3"><i data-lucide="search" class="h-3.5 w-3.5"></i>404</p>
|
||||||
|
<h1 class="text-4xl sm:text-5xl font-bold leading-tight">No pattern here</h1>
|
||||||
|
<p class="mt-4 text-zinc-700 max-w-xl mx-auto">This page doesn't exist or has moved. Even pattern seekers hit a dead end sometimes.</p>
|
||||||
|
<a href="/" class="mt-6 inline-flex items-center gap-2 rounded-xl bg-accent px-5 py-3 text-sm font-medium text-white transition hover:bg-indigo-700">
|
||||||
|
<i data-lucide="arrow-left" class="h-4 w-4"></i> Back to Home
|
||||||
|
</a>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
${footer}
|
||||||
|
`;
|
||||||
|
|
||||||
export const renderNewsletterPage = () => `
|
export const renderNewsletterPage = () => `
|
||||||
${shellHead({
|
${shellHead({
|
||||||
title: "Newsletter — apophenia.news",
|
title: "Newsletter — apophenia.news",
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export const merch = `
|
|||||||
</section>
|
</section>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const shellHead = ({ title, desc, image, url, type = "website" }) => `<!doctype html>
|
export const shellHead = ({ title, desc, image, url, type = "website", noindex = false }) => `<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
@@ -85,6 +85,7 @@ export const shellHead = ({ title, desc, image, url, type = "website" }) => `<!d
|
|||||||
${url ? `<meta property="og:url" content="${url}" />` : ""}
|
${url ? `<meta property="og:url" content="${url}" />` : ""}
|
||||||
${image ? `<meta property="og:image" content="${image}" />` : ""}
|
${image ? `<meta property="og:image" content="${image}" />` : ""}
|
||||||
<meta name="theme-color" content="#fcfcfa" />
|
<meta name="theme-color" content="#fcfcfa" />
|
||||||
|
${noindex ? `<meta name="robots" content="noindex" />` : ""}
|
||||||
${url ? `<link rel="canonical" href="${url}" />` : ""}
|
${url ? `<link rel="canonical" href="${url}" />` : ""}
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<link rel="alternate" type="application/rss+xml" title="apophenia.news RSS" href="${SITE_URL}/rss.xml" />
|
<link rel="alternate" type="application/rss+xml" title="apophenia.news RSS" href="${SITE_URL}/rss.xml" />
|
||||||
|
|||||||
Reference in New Issue
Block a user