fix: generate sitemap.xml in eleventy.after hook instead of template

The @quasibit/eleventy-plugin-sitemap shortcode triggers
TemplateContentPrematureUseError on paginated templates in Eleventy 3.x.
Move sitemap generation to eleventy.after hook which scans the output
directory for index.html files after all templates are rendered. Remove
the plugin import/registration and the sitemap.njk template.
This commit is contained in:
Ricardo
2026-03-29 11:05:42 +02:00
parent 489c467a3f
commit 7f26d7398b
2 changed files with 49 additions and 37 deletions
+49 -30
View File
@@ -2,7 +2,7 @@ import pluginWebmentions from "@chrisburnell/eleventy-cache-webmentions";
import pluginRss from "@11ty/eleventy-plugin-rss"; import pluginRss from "@11ty/eleventy-plugin-rss";
import embedEverything from "eleventy-plugin-embed-everything"; import embedEverything from "eleventy-plugin-embed-everything";
import { eleventyImageTransformPlugin } from "@11ty/eleventy-img"; import { eleventyImageTransformPlugin } from "@11ty/eleventy-img";
import sitemap from "@quasibit/eleventy-plugin-sitemap";
import markdownIt from "markdown-it"; import markdownIt from "markdown-it";
import markdownItAnchor from "markdown-it-anchor"; import markdownItAnchor from "markdown-it-anchor";
import syntaxHighlight from "@11ty/eleventy-plugin-syntaxhighlight"; import syntaxHighlight from "@11ty/eleventy-plugin-syntaxhighlight";
@@ -352,12 +352,6 @@ export default function (eleventyConfig) {
return eleventyConfig.htmlTransformer.transformContent(this.outputPath, content, this); return eleventyConfig.htmlTransformer.transformContent(this.outputPath, content, this);
}); });
// Sitemap generation
eleventyConfig.addPlugin(sitemap, {
sitemap: {
hostname: siteUrl,
},
});
// Wrap <table> elements in <table-saw> for responsive tables // Wrap <table> elements in <table-saw> for responsive tables
eleventyConfig.addTransform("table-saw-wrap", function (content, outputPath) { eleventyConfig.addTransform("table-saw-wrap", function (content, outputPath) {
@@ -674,29 +668,6 @@ export default function (eleventyConfig) {
}); });
}); });
// Exclude pages from sitemap by URL pattern
// Usage: collections.all | excludeFromSitemap
eleventyConfig.addFilter("excludeFromSitemap", (items) => {
const excludePatterns = [
/^\/replies\//,
/^\/feed\.(xml|json)$/,
/\/feed\.(xml|json)$/,
/^\/categories\//,
/^\/digest/,
/^\/webmention-debug\//,
/^\/404\.html$/,
/^\/sitemap\.xml$/,
/^\/dashboard/,
/^\/homepage/,
/^\/search\//,
/^\/graph\//,
];
return items.filter((item) => {
const url = item.url || "";
return !excludePatterns.some((pattern) => pattern.test(url));
});
});
// Slugify filter // Slugify filter
eleventyConfig.addFilter("slugify", (str) => { eleventyConfig.addFilter("slugify", (str) => {
if (!str) return ""; if (!str) return "";
@@ -1426,6 +1397,54 @@ export default function (eleventyConfig) {
} }
} }
// Sitemap generation — scan output HTML files, exclude URL patterns
if (!incremental) {
const sitemapOutputDir = directories?.output || dir.output;
const excludePatterns = [
/^\/replies\//,
/\/feed\.(xml|json)$/,
/^\/categories\//,
/^\/digest/,
/^\/webmention-debug\//,
/^\/404\.html$/,
/^\/dashboard/,
/^\/homepage/,
/^\/search\//,
/^\/graph\//,
/^\/sitemap\.xml$/,
];
try {
const walkHtml = (base, prefix = "") => {
const entries = [];
for (const entry of readdirSync(resolve(base, prefix), { withFileTypes: true })) {
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
if (entry.isDirectory()) {
entries.push(...walkHtml(base, rel));
} else if (entry.name === "index.html") {
const urlPath = prefix ? `/${prefix}/` : "/";
entries.push(urlPath);
}
}
return entries;
};
const allUrls = walkHtml(sitemapOutputDir)
.filter((url) => !excludePatterns.some((p) => p.test(url)))
.sort();
const xmlLines = [
'<?xml version="1.0" encoding="UTF-8"?>',
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
];
for (const url of allUrls) {
xmlLines.push(` <url><loc>${siteUrl}${url}</loc></url>`);
}
xmlLines.push("</urlset>");
writeFileSync(resolve(sitemapOutputDir, "sitemap.xml"), xmlLines.join("\n"));
console.log(`[sitemap] Generated sitemap.xml with ${allUrls.length} URLs`);
} catch (err) {
console.error("[sitemap] Generation failed:", err.message);
}
}
// Pagefind indexing — run exactly once per process lifetime // Pagefind indexing — run exactly once per process lifetime
if (!pagefindDone) { if (!pagefindDone) {
pagefindDone = true; pagefindDone = true;
-7
View File
@@ -1,7 +0,0 @@
---
permalink: /sitemap.xml
layout: null
eleventyExcludeFromCollections: true
---
{% set sitemapItems = collections.all | excludeFromSitemap %}
{% sitemap sitemapItems %}