Files
pw/astro.config.mjs
T
Asger Geel Weirsøe 288205630e
Build & Deploy / deploy (push) Successful in 5m55s
Ryd op i kommentarer
2026-10-31 14:43:20 +01:00

176 lines
5.5 KiB
JavaScript

import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
import AstroPWA from '@vite-pwa/astro';
import tailwindcss from '@tailwindcss/vite';
import { execFileSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const ROOT = path.dirname(fileURLToPath(import.meta.url));
// lastmod til sitemap: sidste commit for statiske sider, frontmatter for blogindlæg.
// Kræver fuld git-historik (fetch-depth: 0); ellers ingen lastmod.
const gitLastModified = (file) => {
try {
const out = execFileSync('git', ['log', '-1', '--format=%cI', '--', file], {
cwd: ROOT,
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore'],
}).trim();
return out || null;
} catch {
return null;
}
};
const gitHistoryIsUsable = (() => {
try {
const n = execFileSync('git', ['rev-list', '--count', 'HEAD'], {
cwd: ROOT,
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore'],
}).trim();
return Number(n) > 1;
} catch {
return false;
}
})();
const walk = (dir) =>
fs.existsSync(dir)
? fs.readdirSync(dir, { withFileTypes: true }).flatMap((e) => {
const p = path.join(dir, e.name);
return e.isDirectory() ? walk(p) : [p];
})
: [];
// src/pages/foo.astro -> /foo/ ; src/pages/index.astro -> / ; [dynamiske] springes over
const routeForPage = (file) => {
const rel = path.relative(path.join(ROOT, 'src/pages'), file).replace(/\\/g, '/');
if (rel.includes('[') || rel.startsWith('404.')) return null;
if (!rel.endsWith('.astro')) return null;
const noExt = rel.slice(0, -'.astro'.length);
if (noExt === 'index') return '/';
return `/${noExt.replace(/\/index$/, '')}/`;
};
// Minimal frontmatter-læsning — vi skal kun bruge date/updated/tags/draft.
const readFrontmatter = (file) => {
const src = fs.readFileSync(file, 'utf8');
const m = src.match(/^---\r?\n([\s\S]*?)\r?\n---/);
if (!m) return {};
const fm = {};
for (const line of m[1].split(/\r?\n/)) {
const kv = line.match(/^(\w+):\s*(.*)$/);
if (!kv) continue;
const [, k, rawv] = kv;
const v = rawv.trim().replace(/^['"]|['"]$/g, '');
if (k === 'tags') {
const inline = v.match(/^\[(.*)\]$/);
fm.tags = inline
? inline[1].split(',').map((t) => t.trim().replace(/^['"]|['"]$/g, '')).filter(Boolean)
: [];
} else {
fm[k] = v;
}
}
return fm;
};
const iso = (v) => {
const d = new Date(v);
return Number.isNaN(d.getTime()) ? null : d.toISOString();
};
const newest = (dates) => dates.filter(Boolean).sort().at(-1) ?? null;
const buildLastmodMap = () => {
const map = new Map();
if (!gitHistoryIsUsable) return map;
for (const file of walk(path.join(ROOT, 'src/pages'))) {
const route = routeForPage(file);
if (!route) continue;
const d = gitLastModified(file);
if (d) map.set(route, d);
}
// Blogindlæg: frontmatter er sandheden om hvornår indholdet sidst ændrede sig.
const postDates = [];
const tagDates = new Map();
for (const file of walk(path.join(ROOT, 'src/content/blog'))) {
if (!file.endsWith('.md')) continue;
const fm = readFrontmatter(file);
if (fm.draft === 'true') continue;
const d = iso(fm.updated || fm.date);
if (!d) continue;
const slug = path.basename(file, '.md');
map.set(`/blog/${slug}/`, d);
postDates.push(d);
for (const t of fm.tags ?? []) {
const key = t.toLowerCase();
tagDates.set(key, newest([tagDates.get(key), d]));
}
}
// Oversigtssider er lige så friske som det nyeste de viser.
const latest = newest(postDates);
if (latest) {
map.set('/blog/', latest);
map.set('/tags/', latest);
for (const [tag, d] of tagDates) map.set(`/tags/${tag}/`, d);
}
return map;
};
const lastmodByRoute = buildLastmodMap();
// Preview-build af udkast (PW_PREVIEW=1): hele sitet under /udkast, uden sitemap
// og service worker. Det serveres kun bag login og må aldrig ende i et index.
const PREVIEW = process.env.PW_PREVIEW === '1';
export default defineConfig({
site: 'https://asger.xn--weirse-fya.dk',
...(PREVIEW ? { base: '/udkast' } : {}),
trailingSlash: 'ignore',
integrations: PREVIEW ? [] : [
sitemap({
changefreq: 'weekly',
priority: 0.7,
customPages: ['https://asger.xn--weirse-fya.dk/tarballz/'],
// noindex-sider og omdirigeringer
filter: (page) => {
const p = new URL(page).pathname.replace(/\/$/, '');
return !p.startsWith('/tags') && !p.startsWith('/peppol')
&& !['/cookies', '/status', '/chat'].includes(p);
},
serialize(item) {
const pathname = new URL(item.url).pathname;
if (pathname === '/') item.priority = 1.0;
const lastmod = lastmodByRoute.get(pathname);
if (lastmod) item.lastmod = lastmod;
// Kanonisk form uden afsluttende skråstreg (undtagen /tarballz/)
if (pathname !== '/' && pathname !== '/tarballz/') item.url = item.url.replace(/\/$/, '');
return item;
},
}),
AstroPWA({
registerType: 'autoUpdate',
manifest: false,
includeManifestIcons: false,
workbox: {
globPatterns: ['**/*.{html,css,js,svg,png,woff2,xml,txt,webmanifest}'],
cleanupOutdatedCaches: true,
clientsClaim: true,
skipWaiting: true,
// Ingen fallback til forsiden, så /tarballz/ og 404 virker
navigateFallback: null,
},
devOptions: { enabled: false },
}),
],
prefetch: { prefetchAll: true, defaultStrategy: 'viewport' },
vite: { plugins: [tailwindcss()] },
});