176 lines
5.5 KiB
JavaScript
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()] },
|
|
});
|