mirror of
https://github.com/samber/awesome-prometheus-alerts.git
synced 2026-06-20 16:46:37 +08:00
* feat: migrate website from Jekyll to Astro Rebuilds the site using Astro (SSG) with Tailwind CSS v4, replacing the Jekyll/Cayman theme. Key changes: - Splits the monolithic /rules page into 110 statically-generated pages (92 per-service + 13 group index + homepage + guide pages) for SEO - URL structure: /rules/[group-slug]/[service-slug]/ with backward- compatibility redirect map for old anchor-based URLs (/rules#redis) - Modern UI: Prometheus-orange accent, dark mode (system + toggle), sticky sidebar, responsive layout, copy-to-clipboard per rule/section - SEO: per-page <title>, <meta description>, Open Graph, Twitter Card, canonical URLs, sitemap.xml via @astrojs/sitemap - GEO: FAQPage JSON-LD schema on each service page (rules as Q&A pairs for AI search engines), TechArticle schema, BreadcrumbList - Search: Pagefind (build-time index, lazy-loaded, ~200KB) - Zero JS by default; copy buttons and theme toggle use inline scripts - New CI: .github/workflows/deploy.yml builds Astro + Pagefind and deploys to GitHub Pages via actions/deploy-pages - Existing dist.yml and test.yml workflows are untouched - _data/rules.yml remains the single source of truth Note: GitHub Pages source must be changed from "Build from branch" (Jekyll) to "GitHub Actions" in repository settings. * doc: new website based on astro * refactor: remove previous website * chore: add npm dependabot for Astro site + scope CI to _data changes * Update site/astro.config.mjs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update site/src/components/CopyButton.astro Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * oops * fix: strip trailing slash from BASE_URL to prevent double slashes in URLs Agent-Logs-Url: https://github.com/samber/awesome-prometheus-alerts/sessions/c85937ba-1855-4b8a-a72b-847eab1c8639 Co-authored-by: samber <2951285+samber@users.noreply.github.com> * fix: resolve Astro build errors in astro.config.mjs - Remove assetsInclude yml which caused Vite to treat YAML files as static assets instead of running them through the custom YAML transform plugin; data.groups was undefined at runtime because the import resolved to a URL rather than parsed content - Deduplicate old-path redirects: emit only the slash-less variant per service to avoid Astro router collision warnings (trailing-slash variant is handled automatically) --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: samber <2951285+samber@users.noreply.github.com>
105 lines
3.8 KiB
JavaScript
105 lines
3.8 KiB
JavaScript
import { defineConfig } from 'astro/config';
|
|
import tailwind from '@astrojs/tailwind';
|
|
import sitemap from '@astrojs/sitemap';
|
|
import icon from 'astro-icon';
|
|
import { parse as parseYaml } from 'yaml';
|
|
import { readFileSync } from 'fs';
|
|
import { resolve, dirname } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
|
function normalizeViteId(id) {
|
|
const cleanId = id.split('?', 1)[0].split('#', 1)[0];
|
|
return cleanId.startsWith('/@fs/') ? cleanId.slice(4) : cleanId;
|
|
}
|
|
|
|
/** Custom Vite plugin that parses YAML files using the 'yaml' package,
|
|
* which tolerates duplicate keys (last one wins) unlike js-yaml 4.x. */
|
|
function yamlPlugin() {
|
|
return {
|
|
name: 'vite-plugin-yaml-tolerant',
|
|
transform(code, id) {
|
|
const normalizedId = normalizeViteId(id);
|
|
if (!normalizedId.endsWith('.yml') && !normalizedId.endsWith('.yaml')) return null;
|
|
const content = typeof code === 'string' ? code : readFileSync(resolve(normalizedId), 'utf-8');
|
|
const data = parseYaml(content, { merge: true, strict: false, uniqueKeys: false });
|
|
return {
|
|
code: `export default ${JSON.stringify(data)};`,
|
|
map: null,
|
|
};
|
|
},
|
|
};
|
|
}
|
|
|
|
const toSlug = (name) =>
|
|
name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
|
|
/** Build redirect map: old flat /rules/{service} paths → new /rules/{group}/{service}/ paths */
|
|
function buildRedirects(base) {
|
|
try {
|
|
const rulesPath = resolve(__dirname, '../_data/rules.yml');
|
|
const raw = readFileSync(rulesPath, 'utf-8');
|
|
const { groups } = parseYaml(raw, { merge: true, strict: false, uniqueKeys: false });
|
|
const redirects = {};
|
|
for (const group of groups) {
|
|
const groupSlug = toSlug(group.name);
|
|
for (const service of group.services) {
|
|
const serviceSlug = toSlug(service.name);
|
|
// Old anchor slug (spaces → hyphens only, no other substitutions)
|
|
const oldSlug = service.name.replace(/ /g, '-').toLowerCase();
|
|
const newPath = `${base}/rules/${groupSlug}/${serviceSlug}/`;
|
|
// Redirect from flat old path (without trailing slash; Astro handles the slash variant)
|
|
const oldPath = `${base}/rules/${oldSlug}`;
|
|
if (oldPath !== newPath && oldPath !== newPath.slice(0, -1)) {
|
|
redirects[oldPath] = { destination: newPath, status: 301 };
|
|
}
|
|
}
|
|
}
|
|
return redirects;
|
|
} catch {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
const base = '/awesome-prometheus-alerts';
|
|
|
|
export default defineConfig({
|
|
site: 'https://samber.github.io',
|
|
base,
|
|
redirects: buildRedirects(base),
|
|
output: 'static',
|
|
integrations: [
|
|
tailwind({ applyBaseStyles: false }),
|
|
sitemap({
|
|
serialize(item) {
|
|
const path = new URL(item.url).pathname;
|
|
const segments = path.replace(/^\/|\/$/g, '').split('/').filter(Boolean);
|
|
// segments[0] = 'awesome-prometheus-alerts', [1] = 'rules'|guide, [2] = group, [3] = service
|
|
|
|
if (segments.length <= 1) {
|
|
// Homepage
|
|
return { ...item, changefreq: 'weekly', priority: 1.0, lastmod: new Date() };
|
|
}
|
|
if (segments.length === 2 && segments[1] === 'rules') {
|
|
// /rules/ index
|
|
return { ...item, changefreq: 'weekly', priority: 0.9, lastmod: new Date() };
|
|
}
|
|
if (segments.length === 3 && segments[1] === 'rules') {
|
|
// /rules/[group]/ index
|
|
return { ...item, changefreq: 'monthly', priority: 0.7, lastmod: new Date() };
|
|
}
|
|
if (segments.length === 4 && segments[1] === 'rules') {
|
|
// /rules/[group]/[service]/ — main content pages
|
|
return { ...item, changefreq: 'monthly', priority: 0.8, lastmod: new Date() };
|
|
}
|
|
// Guide pages and others
|
|
return { ...item, changefreq: 'yearly', priority: 0.6, lastmod: new Date() };
|
|
},
|
|
}),
|
|
icon(),
|
|
],
|
|
vite: {
|
|
plugins: [yamlPlugin()],
|
|
},
|
|
});
|