GithubHelp home page GithubHelp logo

kiwikilian / eleventy-plugin-og-image Goto Github PK

View Code? Open in Web Editor NEW
52.0 2.0 3.0 3.01 MB

Create Open Graph images in Eleventy using your templates, data and CSS. Fast and reproducible, without a headless browser.

License: MIT License

JavaScript 86.81% Nunjucks 13.19%
eleventy eleventy-plugin

eleventy-plugin-og-image's Introduction

Eleventy Plugin OG Image npm

This plugin helps to create Open Graph images in Eleventy using a template language of your choice12 and CSS3 via satori. No headless browser will be harmed 😉.

Usage

Note

This is the documentation for eleventy-plugin-og-image ^2.0.0. If your project already uses @11ty/eleventy >=3.0.0-alpha.1 and switched to ESM it's recommended to use the current beta of this plugin.

Install the package:

npm install eleventy-plugin-og-image --save-dev

Add the plugin to your .eleventy.js:

const EleventyPluginOgImage = require('eleventy-plugin-og-image');

module.exports = (eleventyConfig) => {
  eleventyConfig.addPlugin(EleventyPluginOgImage, {
    satoriOptions: {
      fonts: [
        {
          name: 'Inter',
          data: fs.readFileSync('../path/to/font-file/inter.woff'),
          weight: 700,
          style: 'normal',
        },
      ],
    },
  });
};

Create an OG-image-template, using the supported HTML elements2 and CSS properties3. CSS in <style> tags will be inlined, remote images fetched. This is an example og-image.og.njk:

<style>
    .root {
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        align-items: center;
        background: linear-gradient(135deg, #ef629f, #eecda3);
    }

    .title {
        color: white;
        font-size: 80px;
        margin: auto 0;
    }
</style>

<div class="root">
    <h1 class="title">{{ title }}</h1>
</div>

Call the ogImage shortcode inside the <head> in a template. The first argument is the filePath of the OG-image-template (required, relative to the location from where you execute the eleventy command), second argument is for data (optional). Usage example in Nunjucks, e.g. example-page.njk:

{% ogImage "./og-image.og.njk", { title: "Hello World!" } %}

Result

Generated OG image _site/og-images/s0m3h4sh.png:

Generated OG image

HTML output generated by the shortcode in _site/example-page/index.html (can be modified via the generateHTML option):

<meta property="og:image" content="/og-images/s0m3h4sh.png" />

For applied usage see the example.

Note The template language of the page and OG-image-template can be mixed and matched.1

Configuration

The following options can be passed when adding the plugin:

Property Type Default
inputFileGlob glob **/*.og.* This must match the OG-image-templates to prevent HTML compilation.
getOutputFileSlug function See source Generation of the output file slug. Return must be url safe and exclude the file extension.
outputFileExtension sharp output file formats png
outputDir string _site/og-images/ Directory into which OG images will be emitted. Relative to the location from where you execute the eleventy command. Change urlPath accordingly.
urlPath string /og-images/ URL-prefix which will be used in returned meta-tags. Change outputDir accordingly.
generateHTML function See source Change the rendered HTML in pages.
satoriOptions satori options { width: 1200, height: 630, fonts: [] } If an OG-image-template contains text, it's required to load a font (example).
sharpOptions sharp output options undefined Options must be corresponding to chosen outputFileExtension.

Development Mode

During development the OG image file name is the url slug of the page it's generated from. In production builds, a hash of the content will be used. You'll have to handle this yourself, if you pass a custom getOutputFileSlug.

Advanced Usage

Custom Shortcode

If you would like to build your own shortcode, you can directly use the renderOgImage function.

const { renderOgImage } = require('eleventy-plugin-og-image/render');

const { html, svg, pngBuffer } = await renderOgImage({ inputPath, data, satoriOptions, templateConfig });

Capture Output URL

If you don't want to directly generate HTML with the shortcode, you can modify the generateHTML option to directly return the outputUrl:

eleventyConfig.addPlugin(EleventyPluginOgImage, {
  generateHTML: (outputUrl) => outputUrl,
});

Now you can capture the outputUrl in your page, e.g. in Nunjucks:

{% setAsync "ogOutputUrl" -%}
    {% ogImage "./og-image.og.njk", { title: "Hello World!" } %}
{%- endsetAsync %}

And use it anywhere below with {{ ogOutputUrl }}.

Acknowledgements & Attributions

This plugin is deeply inspired by @vercel/og.

Furthermore, it would not be possible without:

Footnotes

  1. Handlebars doesn't support async shortcodes and therefore can't use the ogImage shortcode. Nevertheless, an OG-image-template can use Handlebars (.og.hbs). 2

  2. Only a subset of HTML elements is supported by satori. 2

  3. Only a subset of CSS properties are supported by yoga-layout, which is used by satori. 2

eleventy-plugin-og-image's People

Contributors

dependabot[bot] avatar kiwikilian avatar semantic-release-bot avatar tylermercer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

eleventy-plugin-og-image's Issues

Stable files in production

I'd like to see the option of stable file names for production. I'm interested in predetermining the URL to the image on another one of my sites and having the filename hash makes this difficult. Looks like it might be as simple as exposing the previewFilenames Boolean in the plugin options (maybe as a new name: stableFilenames?).

Ability to disable preview

Hey! Thanks for such an awesome plugin!

I have some linters like W3C and Linthtml on the Git pre-commit hook. Since the preview folder contains a lot of invalid HTML, I receive errors when committing changes. Of course, I can create a production build and then try to commit, but this takes time, and during development, I want to commit quickly.

I do not want to change my linters' configuration, and I do not use the preview functionality. Therefore, I think it would be better to add an option to disable the creation of the preview folder altogether.

I’m interested to know what you think about this.

Issue with Github actions

Thanks to your previous help I got the ogImage working locally, but when I pushed the changes to git, a github action runs and compiles everything and then copies the results over to my server. When this process happened with the ogImage content, it threw an error. Is it related to it not being able to find the template?

[11ty] 1. Having trouble writing to "html/books/index.html" from "./src/books/books.11ty.js" (via EleventyTemplateError)
[11ty] 2. (./src/_includes/books.njk)
[11ty]   Template render error: (/github/workspace/src/_includes/header-books.njk)
[11ty]   EleventyShortcodeError: Error with Nunjucks shortcode `ogImage` (via Template render error)
[11ty] 3. Cannot read properties of undefined (reading 'includes') (via Template render error)
[11ty] 
[11ty] Original error stack trace: TypeError: Cannot read properties of undefined (reading 'includes')
[11ty]     at new TemplateRender (/github/workspace/node_modules/@11ty/eleventy/src/TemplateRender.js:29:73)
[11ty]     at compileFile (/github/workspace/node_modules/@11ty/eleventy/src/Plugins/RenderPlugin.js:66:12)
[11ty]     at renderOgImage (/github/workspace/node_modules/eleventy-plugin-og-image/src/renderOgImage.js:24:31)
[11ty]     at Object.ogImage (/github/workspace/node_modules/eleventy-plugin-og-image/.eleventy.js:56:40)
[11ty]     at Object.<anonymous> (/usr/local/lib/node_modules/@11ty/eleventy/src/BenchmarkGroup.js:32:26)
[11ty]     at ShortcodeFunction.run (/usr/local/lib/node_modules/@11ty/eleventy/src/Engines/Nunjucks.js:200:14)
[11ty]     at Template.root [as rootRenderFunc] (eval at _compile (/usr/local/lib/node_modules/@11ty/eleventy/node_modules/nunjucks/src/environment.js:527:18), <anonymous>:12:35)
[11ty]     at Template.render (/usr/local/lib/node_modules/@11ty/eleventy/node_modules/nunjucks/src/environment.js:454:10)
[11ty]     at eval (eval at _compile (/usr/local/lib/node_modules/@11ty/eleventy/node_modules/nunjucks/src/environment.js:527:18), <anonymous>:18:10)
[11ty]     at fn (/usr/local/lib/node_modules/@11ty/eleventy/node_modules/a-sync-waterfall/index.js:26:24)

Support for woff2?

My site uses woff2 fonts (Source Sans Pro). When I attempt to reference them with this plugin I get this error:

Unsupported OpenType signature wOF2 (via Template render error)

I've worked around it by also adding the woff version to my assets directory, but if possible it would be nice if the plugin supported woff2 directly.

Handling of kebab-cased styles

Since installing this plugin I've had an error message in my terminal:

`container` unknown or invalid utility

I've now worked out this is coming from me using kebab-cased class names in my template. The class was text-container. If I swap it to being camel-cased, the error goes away. Other kebab cased classes on the templates don't seem to be causing issues interestingly.

The only similar mention of this I could find was on Satori, where it sounds like unrecognised options being passed. If I understand how this plugin works correctly, the styles from the template get inlined with each element before passing to Satori - I wonder if something is going slightly wrong with kebab-cased styles.

Should OG Image Templates live in includes dir?

Currently the .og.* templates can live anywhere – helps to keep the templates near where they might be needed. Plugin could also use the includes per default, would there be a benefit?

Local Images

How to use local/relative images inside OG image template?

Where does the OG image partial need to be placed in a project?

Howdy!

I was trying to replicate the demo from the README:

{% ogImage "./og-image.og.njk", { title: "Hello World!" } %}

But I kept getting an error that Eleventy was unable to find my og-image.og.njk partial file relative to the template that was requesting it (src/_layouts/base.html).

Does the OG image partial need to be placed inside _layouts/ if it's being requested from a layout file? Or does it need to live in _includes or somewhere else?

Sorry, I can't put together a repro case right now, but I'll see if I can a bit later.

Error when building, can't find the template file, even though it's in the same directory

I'm trying to use your plugin, but I'm having a bit of trouble. I'm on Eleventy v2, node v20. When I do npm run serve it throws the following error:

[11ty]   EleventyShortcodeError: Error with Nunjucks shortcode `ogImage` (via Template render error)
[11ty] 3. Could not find file for the `ogImage` shortcode, looking for: ./og-post.njk (via Template render error)

This is even when the og-post.njk file is in the same directory as the template file being parsed.

The line in the template looks like this:

{% ogImage "./og-post.njk", { title: "Hello World!" } %}

I have tried without the ./ and that doesn't work either.

Any suggestions? Thanks in advance!

Using `this` within `getOutputFileSlug` and `generateHTML` throws error (v4.0.0-beta.2)

Thanks for all the hard work that went into the version 4 beta! Love that there’s caching built-in now! It should really speed up my builds. ❤️

Unfortunately, I’ve been running into problems with the new format of the getOutputFileSlug and generateHTML options.

The new docs say that I should be able to access the og image instance by using this in these functions, e.g.

eleventyConfig.addPlugin(EleventyPluginOgImage, {
  generateHTML: () => this.outputUrl(),
});

But doing so throws the following error:

[11ty] 1. Having trouble writing to "_site/example.html" from "./src/pages/example.md" (via EleventyTemplateError)
[11ty] 2. (./src/eleventy/layouts/root.njk)
[11ty]   EleventyShortcodeError: Error with Nunjucks shortcode `ogImage` (via Template render error)
[11ty] 3. Cannot read properties of undefined (reading 'outputURL') (via Template render error)
[11ty] 
[11ty] Original error stack trace: TypeError: Cannot read properties of undefined (reading 'outputURL')
[11ty]     at OgImage.generateHTML (file:///Users/chrisburnell/Developer/example.com/eleventy.config.js:59:28)
[11ty]     at OgImage.generateHtml (file:///Users/chrisburnell/Developer/example.com/node_modules/eleventy-plugin-og-image/src/OgImage.js:136:48)
[11ty]     at Object.ogImageShortcode (file:///Users/chrisburnell/Developer/example.com/node_modules/eleventy-plugin-og-image/.eleventy.js:125:22)

It seems that this is undefined in this context. A similar error is thrown when I try using this inside my option’s getOutputFileSlug function as well.

For clarity’s sake, I’m using the shortcode in my root.njk layout like so:

{% setAsync 'ogOutputUrl' -%}
  {% ogImage './eleventy/layouts/og-image.og.njk', { title: meta_title, description: description, date: date } %}
{%- endsetAsync %}
<meta property="og:image" content="{{ ogOutputUrl }}" data-pagefind-meta="image[content]">

Apologies if I’m overlooking something here! 😅

Sharper resolution option

The images look a bit less crisp than I'd like. I see that the default Sharp png compression is 6 (out of 9) – is that what's used here? Is there an option to change it?

Thanks!

Issues with rendering / Satori

This is just a note for others, as I've found Satori's rendering to be unreliable. I spent some time yesterday making a good looking template, but have now found it to be unrenderable.

The primary issue is that Satori seems to break positioning of inline elements, on which my design relies.

I've also found the limited (and somewhat buggy) implementation of css means that what renders well in browser can often not be reproduced.

Feature request: ignore frontmatter

Firstly, thank you for producing this plugin.

My request is for the plugin to ignore any frontmatter it comes across. At the moment, it's unhandled and gets rendered in to the final image.

Background:
I found testing the rendering to be a bit cumbersome - as I often wanted to directly edit the styles in the browser. To get around this, I've set up Eleventy to render the template as a normal page. So the same template is used to render a page for development, and for the opengraph plugin. I've tried using Frontmatter to set some testing data, assuming it wouldn't get used by the plugin. However it still gets rendered.

I can obviously work around this, but feel it would be good for the plugin to either make use of front-matter, or disregard it.

New context (`this`) way for working with plugin

Hi! Thanks for such an awesome plugin!

I wanted to ask why the new beta version uses the context (this) style for working with the plugin? For example:

config.addPlugin(ogImage, {
  outputFileSlug: function () {
    return this.data.page.fileSlug;
  },
});

While the current version uses the approach of passing context through function parameters:

config.addPlugin(ogImage, {
  getOutputFileSlug: ({ context }) => context.page.fileSlug,
});

In my opinion, the approach using parameters is better. Here are my main points:

  1. It is simpler to understand and maintain.
  2. It is easier to type (using jsdoc or similar).
  3. It generally fits better with the style of native 11ty plugins (for example, the image plugin and the filenameFormat function).
	config.addPlugin(Image.eleventyImageTransformPlugin, {
  	filenameFormat: (_id, source, width, format) => {
  		let extension = extname(source)
  		let name = basename(source, extension)

  		return `${name}-${width}w.${format}`
  	}
  })

These are the points that come to mind, but it would be great to hear what you think about this.

Generated path are backslashes that prevents OpenGraph images to be displayed

I have a very weird bug : generated folder in _site (my output) is made with backslashes (antislash) but it seems that browser can't render OG image if it the path is not made with / rather than antislash :
here is my .eleventy.js plugin config :

const fs = require('node:fs');
const path = require('node:path')
const EleventyPluginOgImage = require('eleventy-plugin-og-image');

module.exports = function(eleventyConfig) {
  
  // AUTO GENERATED OPENGRAPH IMAGES
  eleventyConfig.addPlugin(EleventyPluginOgImage, {
    outputDir: "_site/og-images",
    urlPath: "/og-images/",
    satoriOptions: {
      fonts: [
        {
          name: 'Satoshi-Variable',
          data: fs.readFileSync('./src/fonts/Satoshi-Variable.woff'),
          weight: 500,
          style: 'normal',
        },
      ],
    },
  });
  }

my og-image.og.njk is absolute classic and is placed at root (sibling to .eleventy.js, tried putting it in ./src or inner folders but don't change anything) :

<div class="background">
    <div class="card">
        <h1 class="title">{{ title }}</h1>
     </div>
</div>

here is ./src/_includes/head.html :

{% ogImage "og-image.og.njk", { title: title} %}

here is the log I get when running build or dev :

[11ty] Writing _site\og-images\blog-sq-lite.png from og-image.og.njk
[11ty] Writing _site\og-images\blog.png from og-image.og.njk

and on and on....

tried every config option on the plugin but don't do anything...

HTML GENERATED ON BROWSER : the backslashed prevent the OG image to be rendered

<meta property="og:image" content="\og-images\index.png">

ELEVENTY VERSION

2.0.1

Improve Path Handling

I think there is still a lot to be improved with how the output path is generated. A few ideas or topics to investigate:

  • Is it working on Windows?
  • Permalinks handling
  • Better usage of TemplatePath form @11ty/eleventy-utils?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.