Skip to content

Commit 6749f62

Browse files
authored
fix: add an option to disable dynamic OG image generation (#476)
* fix: add an option to disable dynamic OG image generation Add new `dynamicOgImage` option in the `SITE` object inside `src/config.ts` file to disable auto og-image generation during build. Resolves #428 * docs: update guides for `SITE.dynamicOgImage` option
1 parent dc5ca47 commit 6749f62

6 files changed

Lines changed: 70 additions & 29 deletions

File tree

src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ export const SITE = {
1616
text: "Suggest Changes",
1717
appendFilePath: true,
1818
},
19+
dynamicOgImage: true,
1920
} as const;

src/data/blog/dynamic-og-images.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
author: Sat Naing
33
pubDatetime: 2022-12-28T04:59:04.866Z
4+
modDatetime: 2025-03-12T13:39:20.763Z
45
title: Dynamic OG image generation in AstroPaper blog posts
56
slug: dynamic-og-image-generation-in-astropaper-blog-posts
67
featured: false
@@ -80,6 +81,14 @@ async function loadGoogleFonts(
8081

8182
> Check out [this PR](https://github.com/satnaing/astro-paper/pull/318) for more info.
8283
84+
## Trade-off
85+
86+
While this is a nice feature to have, there's a trade-off. Each OG image takes roughly one second to generate. This might not be noticeable at first, but as the number of blog posts grows, you might want to disable this feature. Since every OG image takes time to generate, having many of them will increase the build time linearly.
87+
88+
For example: If one OG image takes one second to generate, then 60 images will take around one minute, and 600 images will take approximately 10 minutes. This can significantly impact build times as your content scales.
89+
90+
Related issue: [#428](https://github.com/satnaing/astro-paper/issues/428)
91+
8392
## Limitations
8493

8594
At the time of writing this, [Satori](https://github.com/vercel/satori) is fairly new and has not reached major release yet. So, there are still some limitations to this dynamic OG image feature.

src/data/blog/how-to-configure-astropaper-theme.md

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
author: Sat Naing
33
pubDatetime: 2022-09-23T04:58:53Z
4-
modDatetime: 2025-03-07T14:01:26.494Z
4+
modDatetime: 2025-03-12T13:39:39.057Z
55
title: How to configure AstroPaper theme
66
slug: how-to-configure-astropaper-theme
77
featured: true
@@ -42,26 +42,28 @@ export const SITE = {
4242
text: "Suggest Changes",
4343
appendFilePath: true,
4444
},
45+
dynamicOgImage: true, // enable automatic dynamic og-image generation
4546
} as const;
4647
```
4748

4849
Here are SITE configuration options
4950

50-
| Options | Description |
51-
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
52-
| `website` | Your deployed website URL |
53-
| `author` | Your name |
54-
| `profile` | Your personal/portfolio website URL which is used for better SEO. Put `null` or empty string `""` if you don't have any. |
55-
| `desc` | Your site description. Useful for SEO and social media sharing. |
56-
| `title` | Your site name |
57-
| `ogImage` | Your default OG image for the site. Useful for social media sharing. OG images can be an external image URL or they can be placed under `/public` directory. |
58-
| `lightAndDarkMode` | Enable or disable `light & dark mode` for the website. If disabled, primary color scheme will be used. This option is enabled by default. |
59-
| `postPerIndex` | The number of posts to be displayed at the home page under `Recent` section. |
60-
| `postPerPage` | You can specify how many posts will be displayed in each posts page. (eg: if you set `SITE.postPerPage` to 3, each page will only show 3 posts per page) |
61-
| `scheduledPostMargin` | In Production mode, posts with a future `pubDatetime` will not be visible. However, if a post's `pubDatetime` is within the next 15 minutes, it will be visible. You can set `scheduledPostMargin` if you don't like the default 15 minutes margin. |
62-
| `showArchives` | Determines whether to display the `Archives` menu (positioned between the `About` and `Search` menus) and its corresponding page on the site. This option is set to `true` by default. |
63-
| `showBackButton` | Determines whether to display the `Go back` button in each blog post. |
64-
| `editPost` | This option allows users to suggest changes to a blog post by providing an edit link under blog post titles. This feature can be disabled by removing it from the `SITE` config. You can also set `appendFilePath` to `true` to automatically append the file path of the post to the url, directing users to the specific post they wish to edit. |
51+
| Options | Description |
52+
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
53+
| `website` | Your deployed website URL |
54+
| `author` | Your name |
55+
| `profile` | Your personal/portfolio website URL which is used for better SEO. Put `null` or empty string `""` if you don't have any. |
56+
| `desc` | Your site description. Useful for SEO and social media sharing. |
57+
| `title` | Your site name |
58+
| `ogImage` | Your default OG image for the site. Useful for social media sharing. OG images can be an external image URL or they can be placed under `/public` directory. |
59+
| `lightAndDarkMode` | Enable or disable `light & dark mode` for the website. If disabled, primary color scheme will be used. This option is enabled by default. |
60+
| `postPerIndex` | The number of posts to be displayed at the home page under `Recent` section. |
61+
| `postPerPage` | You can specify how many posts will be displayed in each posts page. (eg: if you set `SITE.postPerPage` to 3, each page will only show 3 posts per page) |
62+
| `scheduledPostMargin` | In Production mode, posts with a future `pubDatetime` will not be visible. However, if a post's `pubDatetime` is within the next 15 minutes, it will be visible. You can set `scheduledPostMargin` if you don't like the default 15 minutes margin. |
63+
| `showArchives` | Determines whether to display the `Archives` menu (positioned between the `About` and `Search` menus) and its corresponding page on the site. This option is set to `true` by default. |
64+
| `showBackButton` | Determines whether to display the `Go back` button in each blog post. |
65+
| `editPost` | This option allows users to suggest changes to a blog post by providing an edit link under blog post titles. This feature can be disabled by removing it from the `SITE` config. You can also set `appendFilePath` to `true` to automatically append the file path of the post to the url, directing users to the specific post they wish to edit. |
66+
| `dynamicOgImage` | This option controls whether to [generate dynamic og-image](https://astro-paper.pages.dev/posts/dynamic-og-image-generation-in-astropaper-blog-posts/) if no `ogImage` is specified in the blog post frontmatter. If you have many blog posts, you might want to disable this feature. See the [trade-off](https://astro-paper.pages.dev/posts/dynamic-og-image-generation-in-astropaper-blog-posts/#trade-off) for more details. |
6567

6668
## Configuring locale
6769

src/layouts/Layout.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ const {
2323
author = SITE.author,
2424
profile = SITE.profile,
2525
description = SITE.desc,
26-
ogImage = SITE.ogImage,
26+
ogImage = SITE.ogImage ? `/${SITE.ogImage}` : "/og.png",
2727
canonicalURL = new URL(Astro.url.pathname, Astro.url),
2828
pubDatetime,
2929
modDatetime,
3030
scrollSmooth = false,
3131
} = Astro.props;
3232
33-
const socialImageURL = new URL(ogImage ?? SITE.ogImage ?? "og.png", Astro.url);
33+
const socialImageURL = new URL(ogImage, Astro.url);
3434
3535
const structuredData = {
3636
"@context": "https://schema.org",

src/layouts/PostDetails.astro

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const {
2424
title,
2525
author,
2626
description,
27-
ogImage,
27+
ogImage: initOgImage,
2828
canonicalURL,
2929
pubDatetime,
3030
modDatetime,
@@ -34,11 +34,24 @@ const {
3434
3535
const { Content } = await render(post);
3636
37-
const ogImageUrl = typeof ogImage === "string" ? ogImage : ogImage?.src;
38-
const ogUrl = new URL(
39-
ogImageUrl ?? `/posts/${slugifyStr(title)}/index.png`,
40-
Astro.url.origin
41-
).href;
37+
let ogImageUrl: string | undefined;
38+
39+
// Determine OG image source
40+
if (typeof initOgImage === "string") {
41+
ogImageUrl = initOgImage; // Remote OG image (absolute URL)
42+
} else if (initOgImage?.src) {
43+
ogImageUrl = initOgImage.src; // Local asset
44+
}
45+
46+
// Use dynamic OG image if enabled and no remote|local ogImage
47+
if (!ogImageUrl && SITE.dynamicOgImage) {
48+
ogImageUrl = `/posts/${slugifyStr(title)}/index.png`;
49+
}
50+
51+
// Resolve OG image URL (or fallback to SITE.ogImage / default `og.png`)
52+
const ogImage = ogImageUrl
53+
? new URL(ogImageUrl, Astro.url.origin).href
54+
: undefined;
4255
4356
const layoutProps = {
4457
title: `${title} | ${SITE.title}`,
@@ -47,7 +60,7 @@ const layoutProps = {
4760
pubDatetime,
4861
modDatetime,
4962
canonicalURL,
50-
ogImage: ogUrl,
63+
ogImage,
5164
scrollSmooth: true,
5265
};
5366

src/pages/posts/[slug]/index.png.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@ import type { APIRoute } from "astro";
22
import { getCollection, type CollectionEntry } from "astro:content";
33
import { generateOgImageForPost } from "@/utils/generateOgImages";
44
import { slugifyStr } from "@/utils/slugify";
5+
import { SITE } from "@/config";
56

67
export async function getStaticPaths() {
8+
if (!SITE.dynamicOgImage) {
9+
return [];
10+
}
11+
712
const posts = await getCollection("blog").then(p =>
813
p.filter(({ data }) => !data.draft && !data.ogImage)
914
);
@@ -14,7 +19,18 @@ export async function getStaticPaths() {
1419
}));
1520
}
1621

17-
export const GET: APIRoute = async ({ props }) =>
18-
new Response(await generateOgImageForPost(props as CollectionEntry<"blog">), {
19-
headers: { "Content-Type": "image/png" },
20-
});
22+
export const GET: APIRoute = async ({ props }) => {
23+
if (!SITE.dynamicOgImage) {
24+
return new Response(null, {
25+
status: 404,
26+
statusText: "Not found",
27+
});
28+
}
29+
30+
return new Response(
31+
await generateOgImageForPost(props as CollectionEntry<"blog">),
32+
{
33+
headers: { "Content-Type": "image/png" },
34+
}
35+
);
36+
};

0 commit comments

Comments
 (0)