mirror of
https://github.com/svemagie/blog-eleventy-indiekit.git
synced 2026-04-02 16:44:56 +02:00
fix: derive OG slug from page.url to avoid Nunjucks race condition
page.fileSlug suffers from a race condition in Eleventy 3.x parallel rendering where Nunjucks shares state across template compilations, causing slugs to get mixed up between pages. page.url is always correct, so derive the OG slug from it instead.
This commit is contained in:
@@ -12,10 +12,11 @@
|
||||
{% set _bookmarkedUrl = _prevPost.data.bookmarkOf or _prevPost.data.bookmark_of %}
|
||||
{% set _repostedUrl = _prevPost.data.repostOf or _prevPost.data.repost_of %}
|
||||
{% set _replyToUrl = _prevPost.data.inReplyTo or _prevPost.data.in_reply_to %}
|
||||
{% set _prevHasOg = _prevPost.fileSlug | hasOgImage %}
|
||||
{% set _prevOgSlug = _prevPost.url | ogSlug %}
|
||||
{% set _prevHasOg = _prevOgSlug | hasOgImage %}
|
||||
<a href="{{ _prevPost.url }}" class="group flex items-start gap-3 text-sm text-primary-600 dark:text-primary-400 hover:underline">
|
||||
{% if _prevHasOg %}
|
||||
<img src="/og/{{ _prevPost.fileSlug }}.png" alt="" class="w-20 h-[42px] object-cover rounded flex-shrink-0 opacity-80 group-hover:opacity-100 transition-opacity" loading="lazy" eleventy:ignore>
|
||||
<img src="/og/{{ _prevOgSlug }}.png" alt="" class="w-20 h-[42px] object-cover rounded flex-shrink-0 opacity-80 group-hover:opacity-100 transition-opacity" loading="lazy" eleventy:ignore>
|
||||
{% endif %}
|
||||
<span class="line-clamp-2 flex items-center gap-1.5">
|
||||
{% if _likedUrl %}
|
||||
@@ -46,7 +47,8 @@
|
||||
{% set _bookmarkedUrl = _nextPost.data.bookmarkOf or _nextPost.data.bookmark_of %}
|
||||
{% set _repostedUrl = _nextPost.data.repostOf or _nextPost.data.repost_of %}
|
||||
{% set _replyToUrl = _nextPost.data.inReplyTo or _nextPost.data.in_reply_to %}
|
||||
{% set _nextHasOg = _nextPost.fileSlug | hasOgImage %}
|
||||
{% set _nextOgSlug = _nextPost.url | ogSlug %}
|
||||
{% set _nextHasOg = _nextOgSlug | hasOgImage %}
|
||||
<a href="{{ _nextPost.url }}" class="group flex items-start gap-3 text-sm text-primary-600 dark:text-primary-400 hover:underline {% if _prevPost %}justify-end{% endif %}">
|
||||
<span class="line-clamp-2 flex items-center gap-1.5 {% if _prevPost %}justify-end{% endif %}">
|
||||
{% if _likedUrl %}
|
||||
@@ -66,7 +68,7 @@
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if _nextHasOg %}
|
||||
<img src="/og/{{ _nextPost.fileSlug }}.png" alt="" class="w-20 h-[42px] object-cover rounded flex-shrink-0 opacity-80 group-hover:opacity-100 transition-opacity" loading="lazy" eleventy:ignore>
|
||||
<img src="/og/{{ _nextOgSlug }}.png" alt="" class="w-20 h-[42px] object-cover rounded flex-shrink-0 opacity-80 group-hover:opacity-100 transition-opacity" loading="lazy" eleventy:ignore>
|
||||
{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
<meta property="og:type" content="{% if page.url == '/' %}website{% else %}article{% endif %}">
|
||||
<meta property="og:description" content="{{ ogDesc }}">
|
||||
<meta name="description" content="{{ ogDesc }}">
|
||||
{% set hasGeneratedOg = page.fileSlug | hasOgImage %}
|
||||
{% set ogFileSlug = page.url | ogSlug %}
|
||||
{% set hasGeneratedOg = ogFileSlug | hasOgImage %}
|
||||
{% if ogPhoto and ogPhoto != "" and (ogPhoto | length) > 10 %}
|
||||
<meta property="og:image" content="{% if 'http' in ogPhoto %}{{ ogPhoto }}{% else %}{{ site.url }}{% if ogPhoto[0] != '/' %}/{% endif %}{{ ogPhoto }}{% endif %}">
|
||||
{% elif image and image != "" and (image | length) > 10 %}
|
||||
@@ -31,7 +32,7 @@
|
||||
{% elif contentImage and contentImage != "" and (contentImage | length) > 10 %}
|
||||
<meta property="og:image" content="{% if 'http' in contentImage %}{{ contentImage }}{% else %}{{ site.url }}{% if contentImage[0] != '/' %}/{% endif %}{{ contentImage }}{% endif %}">
|
||||
{% elif hasGeneratedOg %}
|
||||
<meta property="og:image" content="{{ site.url }}/og/{{ page.fileSlug }}.png">
|
||||
<meta property="og:image" content="{{ site.url }}/og/{{ ogFileSlug }}.png">
|
||||
{% else %}
|
||||
<meta property="og:image" content="{{ site.url }}/images/og-default.png">
|
||||
{% endif %}
|
||||
@@ -51,7 +52,7 @@
|
||||
{% elif contentImage and contentImage != "" and (contentImage | length) > 10 %}
|
||||
<meta name="twitter:image" content="{% if 'http' in contentImage %}{{ contentImage }}{% else %}{{ site.url }}/{{ contentImage }}{% endif %}">
|
||||
{% elif hasGeneratedOg %}
|
||||
<meta name="twitter:image" content="{{ site.url }}/og/{{ page.fileSlug }}.png">
|
||||
<meta name="twitter:image" content="{{ site.url }}/og/{{ ogFileSlug }}.png">
|
||||
{% endif %}
|
||||
|
||||
{# Favicon #}
|
||||
|
||||
@@ -362,10 +362,18 @@ export default function (eleventyConfig) {
|
||||
}
|
||||
});
|
||||
|
||||
// Check if a generated OG image exists for this page slug
|
||||
eleventyConfig.addFilter("hasOgImage", (fileSlug) => {
|
||||
if (!fileSlug) return false;
|
||||
const ogPath = resolve(__dirname, ".cache", "og", `${fileSlug}.png`);
|
||||
// Derive OG slug from page.url (reliable) instead of page.fileSlug
|
||||
// (which suffers from Nunjucks race conditions in Eleventy 3.x parallel rendering)
|
||||
eleventyConfig.addFilter("ogSlug", (url) => {
|
||||
if (!url) return "";
|
||||
const last = url.replace(/\/$/, "").split("/").pop();
|
||||
return last.replace(/^\d{4}-\d{2}-\d{2}-/, "");
|
||||
});
|
||||
|
||||
// Check if a generated OG image exists for this slug
|
||||
eleventyConfig.addFilter("hasOgImage", (slug) => {
|
||||
if (!slug) return false;
|
||||
const ogPath = resolve(__dirname, ".cache", "og", `${slug}.png`);
|
||||
return existsSync(ogPath);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user