From 7ca70a759fd4dd2609d75cffc11d275c94254cf9 Mon Sep 17 00:00:00 2001 From: goenning Date: Tue, 19 May 2026 15:04:34 +0200 Subject: [PATCH 1/4] move to ssr --- astro.config.mjs | 16 +---------- src/pages/[slug]/[...args].astro | 49 -------------------------------- src/pages/[slug]/index.astro | 15 +--------- src/pages/sitemap.xml.ts | 36 +++++++++++++++++++++++ 4 files changed, 38 insertions(+), 78 deletions(-) create mode 100644 src/pages/sitemap.xml.ts diff --git a/astro.config.mjs b/astro.config.mjs index d30630f..c65ba23 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,32 +1,18 @@ // @ts-check import { defineConfig } from "astro/config"; import tailwindcss from "@tailwindcss/vite"; -import sitemap from "@astrojs/sitemap"; import react from "@astrojs/react"; import vercel from "@astrojs/vercel"; -import { valid } from "semver"; import { astroExpressiveCode } from "astro-expressive-code"; // https://astro.build/config export default defineConfig({ site: "https://kubespec.dev", + output: "server", trailingSlash: "never", integrations: [ - sitemap({ - filter: (page) => { - const path = new URL(page).pathname; - const parts = path.split("/").filter(Boolean); - if (parts.length >= 2) { - if (parts[1].startsWith("v1.") || valid(parts[1])) { - return false; // Skip versioned pages, only include latest (which doesn't have a version in the path) - } - } - - return true; - }, - }), react(), astroExpressiveCode({ themes: ["github-light", "github-dark"], diff --git a/src/pages/[slug]/[...args].astro b/src/pages/[slug]/[...args].astro index c333cfe..4cb8a71 100644 --- a/src/pages/[slug]/[...args].astro +++ b/src/pages/[slug]/[...args].astro @@ -3,59 +3,10 @@ import SiteLayout from "@layouts/SiteLayout.astro"; import DefinitionPage from "@components/DefinitionPage.astro"; import { findProject, - listAllResources, - listProjects, parseGVKRef, } from "@lib/kube"; import HomePage from "@components/HomePage.astro"; -export async function getStaticPaths() { - const paths: Array<{ params: { slug: string; args: string } }> = []; - - const projects = await listProjects(); - for (const project of projects) { - if (!project.tags || project.tags.length === 0) { - continue; - } - - // For each tag, list all resources and create paths - for (const tag of project.tags) { - const isLatest = tag === project.tags[0]; - - if (!isLatest) { - paths.push({ - params: { - slug: project.slug, - args: tag, - }, - }); - } - - const resources = await listAllResources(project.slug, tag); - for (const resource of resources) { - const gvkRef = [ - resource.gvk.group, - resource.gvk.version, - resource.gvk.kind, - ] - .filter(Boolean) - .join("/"); - - const args = isLatest ? [gvkRef] : [tag, gvkRef]; - - paths.push({ - params: { - slug: project.slug, - args: args.join("/"), - }, - }); - } - } - } - - return paths; -} - const { slug, args } = Astro.params; if (!slug || !args) { diff --git a/src/pages/[slug]/index.astro b/src/pages/[slug]/index.astro index 3ecc804..f6e3439 100644 --- a/src/pages/[slug]/index.astro +++ b/src/pages/[slug]/index.astro @@ -1,20 +1,7 @@ --- import HomePage from "@components/HomePage.astro"; import SiteLayout from "@layouts/SiteLayout.astro"; -import { findProject, listProjects } from "@lib/kube"; - -export async function getStaticPaths() { - const paths: Array<{ params: { slug: string } }> = []; - - const projects = await listProjects(); - for (const project of projects) { - paths.push({ - params: { slug: project.slug }, - }); - } - - return paths; -} +import { findProject } from "@lib/kube"; const { slug } = Astro.params; if (!slug) { diff --git a/src/pages/sitemap.xml.ts b/src/pages/sitemap.xml.ts new file mode 100644 index 0000000..cc9521e --- /dev/null +++ b/src/pages/sitemap.xml.ts @@ -0,0 +1,36 @@ +import type { APIRoute } from "astro"; +import { listProjects, listAllResources } from "@lib/kube"; + +export const GET: APIRoute = async () => { + const site = "https://kubespec.dev"; + const urls: string[] = [site]; + + const projects = await listProjects(); + for (const project of projects) { + if (!project.tags || project.tags.length === 0) continue; + + const latestTag = project.tags[0]; + + urls.push(`${site}/${project.slug}`); + + const resources = await listAllResources(project.slug, latestTag); + for (const resource of resources) { + const gvkRef = [resource.gvk.group, resource.gvk.version, resource.gvk.kind] + .filter(Boolean) + .join("/"); + urls.push(`${site}/${project.slug}/${gvkRef}`); + } + } + + const xml = ` + +${urls.map((url) => ` ${url}`).join("\n")} +`; + + return new Response(xml, { + headers: { + "Content-Type": "application/xml", + "Cache-Control": "public, max-age=3600", + }, + }); +}; From 77d5d23bc761fa62bd8c84d88bf2a66b2669e5a0 Mon Sep 17 00:00:00 2001 From: goenning Date: Tue, 19 May 2026 15:09:28 +0200 Subject: [PATCH 2/4] try again --- astro.config.mjs | 4 +++- src/pages/sitemap.xml.ts | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/astro.config.mjs b/astro.config.mjs index c65ba23..91f5b0d 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -25,5 +25,7 @@ export default defineConfig({ plugins: [tailwindcss()], }, - adapter: vercel(), + adapter: vercel({ + includeFiles: ["./content/**"], + }), }); diff --git a/src/pages/sitemap.xml.ts b/src/pages/sitemap.xml.ts index cc9521e..6141254 100644 --- a/src/pages/sitemap.xml.ts +++ b/src/pages/sitemap.xml.ts @@ -15,7 +15,11 @@ export const GET: APIRoute = async () => { const resources = await listAllResources(project.slug, latestTag); for (const resource of resources) { - const gvkRef = [resource.gvk.group, resource.gvk.version, resource.gvk.kind] + const gvkRef = [ + resource.gvk.group, + resource.gvk.version, + resource.gvk.kind, + ] .filter(Boolean) .join("/"); urls.push(`${site}/${project.slug}/${gvkRef}`); From 77547e769e96aee43ac5d98ee1158783351aa3d1 Mon Sep 17 00:00:00 2001 From: goenning Date: Tue, 19 May 2026 15:13:23 +0200 Subject: [PATCH 3/4] use fast-glob --- astro.config.mjs | 3 ++- src/lib/kube/index.ts | 53 ++++++++++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/astro.config.mjs b/astro.config.mjs index 91f5b0d..c624702 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -2,6 +2,7 @@ import { defineConfig } from "astro/config"; import tailwindcss from "@tailwindcss/vite"; import react from "@astrojs/react"; +import { sync as globSync } from "fast-glob"; import vercel from "@astrojs/vercel"; import { astroExpressiveCode } from "astro-expressive-code"; @@ -26,6 +27,6 @@ export default defineConfig({ }, adapter: vercel({ - includeFiles: ["./content/**"], + includeFiles: globSync("./content/**/*"), }), }); diff --git a/src/lib/kube/index.ts b/src/lib/kube/index.ts index 6e008f3..487b12c 100644 --- a/src/lib/kube/index.ts +++ b/src/lib/kube/index.ts @@ -17,27 +17,35 @@ export async function listProjects(): Promise { return cachedProjects; } - const projects: Project[] = []; - for (const project of ALL_PROJECTS) { - const baseDir = `./content/projects/${project.slug}`; - const entries = await readdir(baseDir, { withFileTypes: true }); - const tags = entries - .filter((entry) => entry.isDirectory()) - .map((entry) => entry.name) - .filter((tag) => - project.slug === "kubernetes" ? true : semver.valid(tag) !== null - ); + // Parallelize directory reads and tag extraction + const projects: Project[] = await Promise.all( + ALL_PROJECTS.map(async (project) => { + const baseDir = `./content/projects/${project.slug}`; + let entries: Awaited> = []; + try { + entries = await readdir(baseDir, { withFileTypes: true }); + } catch (e) { + // Directory may not exist, skip + entries = []; + } + const tags = entries + .filter((entry) => entry.isDirectory()) + .map((entry) => entry.name) + .filter((tag) => + project.slug === "kubernetes" ? true : semver.valid(tag) !== null + ); - projects.push({ - name: project.name, - slug: project.slug, - logo: project.logo, - tags: - project.slug === "kubernetes" - ? tags.sort(compareVersions).reverse() - : semver.rsort(tags), - }); - } + return { + name: project.name, + slug: project.slug, + logo: project.logo, + tags: + project.slug === "kubernetes" + ? tags.sort(compareVersions).reverse() + : semver.rsort(tags), + }; + }) + ); cachedProjects = projects; return projects; } @@ -74,7 +82,10 @@ export async function listAllResources( const latestByKind = new Map(); for (const resource of resources) { - const key = `${resource.gvk.group}/${resource.gvk.version.substring(0, 2)}/${resource.gvk.kind}`; + const key = `${resource.gvk.group}/${resource.gvk.version.substring( + 0, + 2 + )}/${resource.gvk.kind}`; const existing = latestByKind.get(key); if (existing) { if (compareCRDVersion(resource.gvk.version, existing.gvk.version) > 0) { From 9e0cf3362ea7c0cd1131760b0db24c104fa5c928 Mon Sep 17 00:00:00 2001 From: goenning Date: Tue, 19 May 2026 15:14:36 +0200 Subject: [PATCH 4/4] again --- astro.config.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/astro.config.mjs b/astro.config.mjs index c624702..7586e38 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -2,7 +2,7 @@ import { defineConfig } from "astro/config"; import tailwindcss from "@tailwindcss/vite"; import react from "@astrojs/react"; -import { sync as globSync } from "fast-glob"; +import fastGlob from "fast-glob"; import vercel from "@astrojs/vercel"; import { astroExpressiveCode } from "astro-expressive-code"; @@ -27,6 +27,6 @@ export default defineConfig({ }, adapter: vercel({ - includeFiles: globSync("./content/**/*"), + includeFiles: fastGlob.sync("./content/**/*"), }), });