lewisdale.dev
Colour scheme

Adding statically-generated Open Graph images

Open Graph images are what websites such as Twitter choose to display when showing a preview to a page. There are plenty of ways to generate these dynamically - like using Netlify Edge Functions, for one.

But recently somebody posted a plugin they'd built the Eleventy Discord server, which gives the ability to create (fairly simple) Open Graph images at build time.

Installation

Installation was pretty straightforward:

npm i --save-dev eleventy-plugin-og-image
// .eleventy.js
const EleventyPluginOgImage = require('eleventy-plugin-og-image');

module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(EleventyPluginOgImage, {
satoriOptions: {
fonts: [
{
name: 'Pixeboy',
data: fs.readFileSync('./fonts/Pixeboy.ttf'),
weight: 700,
style: 'normal',
},
],
},
});
}

Usage

Next I created a template file that can be converted to an image. It's worth mentioning that the plugin uses Vercel's Satori under the hood, so there are restrictions to the CSS that can be applied. I mostly just followed the example from the documentation for this, with a couple of minor tweaks:

<div style="height: 100%; width: 100%; display: flex; align-items: stretch; background-color: white;">
<div style="display: flex; flex-direction: column; flex-grow: 1; align-items: center; margin: 80px; background-color: white;">
<div style="display: flex; flex-grow: 1; flex-direction: column; align-items: center; justify-content: center; font-family: 'Pixeboy'; font-weight: 700; color: black; text-align: center;">
<h1 style="font-size: 80px;">Adding statically-generated Open Graph images</h1>
<h2 style="font-size: 44px;"></h2>
</div>
<div style="display: flex; justify-self: flex-end; flex-grow: 0; font-family: 'Pixeboy'; font-weight: 700; color: black; text-align: center;">
<h3 style="font-size: 30px;">Lewisdale.dev</h3>
</div>
</div>
</div>

And then finally, I just needed to include it in my header. I have a computedData variable called pageTitle I use on some pages, so I simply used that + page description for my data:

{# _includes/layout.njk #} 

<head>
...
{% ogImage "./src/og-post.og.njk", { title: pageTitle or title, subTitle: description } %}
</head>

Issues

The first issue I encountered was a rather cryptic error message:

[11ty] 2. (./src/_includes/layout.njk)
[11ty] EleventyShortcodeError: Error with Nunjucks shortcode `ogImage` (via Template render error)
[11ty] 3. Cannot use 'in' operator to search for 'buffer' in undefined (via Template render error)

This turned out to just be because I had forgotten to include the font file in my configuration initially, which Satori requires. Once I added it to the configuration, everything worked as expected.

The second issue I had was because this method creates an image for every page on the website - I don't really want that. In particular, this caused issues for pages with permalinks that had no directories, such as my 404 page. The plugin doesn't handle those cases at the moment, and was trying to write to _site/404.html/og-post.png.

To fix this, I wrapped my usage with an if statement that meant it now is only generated for blog posts:

{# _includes/layout.njk #}

{% if tags and "posts" in tags and not "drafts" in tags %}
{% ogImage "./src/og-post.og.njk", { title: pageTitle or title, subTitle: description } %}
{% endif %}

Finally, this plugin does no caching currently - that means that the images are generated on every single build. If you've got a lot of pages, this could mean a significantly increased build time, in which case I'd recommend doing this via Edge Functions.

Add a comment