/** * Computed data resolved during the data cascade. * * Eleventy 3.x parallel rendering causes `page.url`, `page.fileSlug`, * and `page.inputPath` to return values from OTHER pages being processed * concurrently. This affects both templates and eleventyComputed functions. * * IMPORTANT: Only `permalink` is computed here, because it reads from the * file's own frontmatter data (per-file, immune to race conditions). * OG image lookups are done in templates using the `permalink` data value * and Nunjucks filters (see base.njk). * * NEVER use `page.url`, `page.fileSlug`, or `page.inputPath` here. * * See: https://github.com/11ty/eleventy/issues/3183 */ const normalizeOutputPermalink = (permalink) => { if (typeof permalink !== "string") return permalink; // Convert accidental absolute URLs to Eleventy output paths. if (/^https?:\/\//i.test(permalink)) { try { const { pathname } = new URL(permalink); if (!pathname) return "/"; return pathname.endsWith("/") ? pathname : `${pathname}/`; } catch { return permalink; } } return permalink; }; export default { eleventyComputed: { // Compute permalink from file path for posts without explicit frontmatter permalink. // Pattern: content/{type}/{yyyy}-{MM}-{dd}-{slug}.md → /{type}/{yyyy}/{MM}/{dd}/{slug}/ permalink: (data) => { // Convert stale /content/ permalinks from pre-beta.37 posts to canonical format const explicitPermalink = normalizeOutputPermalink(data.permalink); if (explicitPermalink && typeof explicitPermalink === "string") { const contentMatch = explicitPermalink.match( /^\/content\/([^/]+)\/(\d{4})-(\d{2})-(\d{2})-(.+?)\/?$/ ); if (contentMatch) { const [, type, year, month, day, slug] = contentMatch; return `/${type}/${year}/${month}/${day}/${slug}/`; } // Valid non-/content/ permalink — use as-is return explicitPermalink; } // No frontmatter permalink — compute from file path // NOTE: data.page.inputPath may be wrong due to parallel rendering, // but posts without frontmatter permalink are rare (only pre-beta.37 edge cases) const inputPath = data.page?.inputPath || ""; const match = inputPath.match( /content\/([^/]+)\/(\d{4})-(\d{2})-(\d{2})-(.+)\.md$/ ); if (match) { const [, type, year, month, day, slug] = match; return `/${type}/${year}/${month}/${day}/${slug}/`; } // For non-matching files (pages, root files), let Eleventy decide return data.permalink; }, }, };