0.2.0 • Published 7 months ago

@reunmedia/astro-og-images v0.2.0

Weekly downloads
-
License
MIT
Repository
-
Last release
7 months ago

Astro OG Images

Yet another Astro integration to generate Open Graph images. More lightweight than most alternatives.

!IMPORTANT

Only static build and dev mode are currently supported, but since dev mode uses on-demand rendering, a custom SSR implementation is possible.

Getting started

Install package

Usng astro add:

pnpm astro add @reunmedia/astro-og-images

Manually:

pnpm add @reunmedia/astro-og-images

Configure integration

// astro.config.mjs
import { defineConfig } from "astro/config";
import ogImages from "@reunmedia/astro-og-images";
import { readFile } from "fs/promises";

export default defineConfig({
  // OpenGraph images require a valid site configuration
  site: "https://example.com",
  integrations: [
    ogImages({
      // At least one font is required
      fonts: [
        {
          name: "Roboto",
          data: await readFile(
            "./node_modules/@fontsource/roboto/files/roboto-latin-400-normal.woff",
          ),
        },
      ],
    }),
  ],
});

See IntegrationOptions.ts for more configuration options.

Usage

!TIP

See Playground for a complete Astro example project.

Create a template

// src/ogImageTemplates/myTemplate.ts
import { html } from "@reunmedia/astro-og-images";

export default function myTemplate(text: string) {
  return html`
    <div style=${{ display: "flex" }}>
      <p>${text}</p>
    </div>
  `;
}

See Playground templates for additional examples.

Astro OG Images uses htm for templating by default to avoid requiring React as a dependency, but you may use JSX as well.

Add image OpenGraph property

---
import { ogImage } from "@reunmedia/astro-og-images";
import myTemplate from "../ogImageTemplates/myTemplate";

// ogImage returns absolute URL to rendered image
const image = await ogImage(myTemplate("Hello World!"));
---

<html lang="en">
  <head>
    <meta property="og:image" content={ogImage} />
  </head>
  ...
</html>

Since ogImage() simply returns an absolute URL, you can use the images for other purposes such as oEmbed.

Preview images during development

In development mode, ogImage() returns the full rendered image as a base64 encoded data URL. This allows you to preview the images during development using various OpenGraph preview tools. You can even create your own image preview using <img> tag:

---
import { ogImage } from "@reunmedia/astro-og-images";
import myTemplate from "../ogImageTemplates/myTemplate";

const image = await ogImage(myTemplate("Hello World!"));
---

<img style="max-width: 100%;" src={image} />

Previewing template as HTML

If you're not using React or Preact and want to preview template HTML during development, you can do so by following these steps:

  1. Install dependencies to render template to HTML
pnpm add -D preact preact-render-to-string htm
  1. Add custom compiler parameter to your template
// src/ogImageTemplates/myTemplate.ts
import { html } from "@reunmedia/astro-og-images";
import type { Compiler } from "@reunmedia/astro-og-images";

export default function myTemplate(text: string): ReturnType<typeof html>;
export default function myTemplate<T>(text: string, compiler: Compiler<T>): T;
export default function myTemplate<T>(text: string, compiler?: Compiler<T>) {
  return (compiler || html)/* html */ `
    <div style=${{ display: "flex" }}>
      <p>${text}</p>
    </div>
  `;
}

If you don't want to add the compiler parameter, you can alternatively just temporarily change the html compiler in the template:

// src/ogImageTemplates/myTemplate.ts
// import { html } from "@reunmedia/astro-og-images";
import { html } from "htm/preact";
  1. Compile template using htm/preact compiler, render template using preact-render-to-string and pass it to OgTemplatePreview.astro component. It's best to use a blank page to prevent global CSS from affecting the template.
---
// src/pages/og-preview.astro
import { html } from "htm/preact";
import { render } from "preact-render-to-string";
import { OgTemplatePreview } from "@reunmedia/astro-og-images/components";
import myTemplate from "../ogImageTemplates/myTemplate";

const preactTemplate = myTemplate("Hello World!", html);
const templateHtml = render(preactTemplate);
---

<body style={{ margin: 0 }}>
  <OgTemplatePreview templateHtml={templateHtml} />
</body>

!IMPORTANT

You should also always preview the rendered image, because some HTML may be rendered differently by Satori.

Motivation

There are multiple OpenGraph image integrations for Astro already. Here's why this one exists:

  • Uses sharp instead of resvg-js to render Satori SVG to PNG. Astro already uses sharp for image processing, so it makes sense to use the same package for OpenGraph images as well.
  • Doesn't require (but supports) React. If you don't use React (or Preact), pulling a complete framework as a dependency just for OpenGraph images seems ovekill. Since Satori also supports "React-elements-like objects" in addition to JSX, we use htm with a custom renderer instead. JSX is supported by simply passing a JSX template to ogImage().
  • Doesn't rewrite output HTML and you get the URL before build is done. Other integrations work by manipulating og:image tags in the built HTML files. This makes it impossible to use the same (or different) image with oEmbed for example. Since this library gives you the resulting URL beforehand, you can even do things like display the image in <img> tag.
  • Allows you to preview OG images during development. This feature is not unique to this library, but our implementation provides more flexibility.