🔥

Deno/Lume でOGPを設定する

2024/04/07に公開

Deno の静的サイトジェネレータである Lume[1] で動的なOGP生成をします.

環境

  • Deno 1.41.0
  • Lume 2.1.2
  • React 18.3.0

https://github.com/toms74209200/gist-blog

OG images の利用

OGPの画像を生成するためには OG images というプラグインを利用します[2]. ほとんど公式ドキュメントの通りです. OG images のプラグインを読み込み, OGP画像を生成するテンプレートファイルを配置して, OGPを設定したいページで宣言するだけです.

プラグインの読み込み

まず _config.ts でプラグインを読み込みます.

_config.ts
import lume from "lume/mod.ts";
import ogImages from "lume/plugins/og_images.ts";

const site = lume();
site.use(ogImages());

基本的にはこれだけですが, オプションで Satori の設定をします. デフォルトでは Inter という欧文フォントが利用されるため, 日本語が描画されません. そのため日本語を利用できるフォントを設定することができます. _config.ts で日本語フォントをダウンロードして設定します. 詳細については別記事に記載しているので, ここでは割愛します[3].

_config.ts
import lume from "lume/mod.ts";
import ogImages from "lume/plugins/og_images.ts";

await downloadFont({ url: FONT_URL, downloadDir: "." });
const fontBuf = await loadFont({ fontPath: "./BIZUDPGothic-Regular.ttf" });

const site = lume();
site.use(ogImages(
  {
    satori: {
      width: 1200,
      height: 630,
      fonts: [
        {
          name: "BIZUDPGothic-Regular",
          data: fontBuf,
        },
      ],
    },
  },
));

テンプレートファイルの作成

OGP画像を描画するためのテンプレートファイルを作成します. layout.tsx と同様に _includes/ ディレクトリに配置すると各ページのファイルから呼び出すことができます[4].

OGP画像を生成する関数は titledescription など, ページ内で指定できるプロパティを引数としてとることができるようです.

またこのプラグインでは Satori を利用するため, React のみ利用できます. Preact を使っているとレンダリングがうまくいきません[5].

includes/og_images.tsx
export default function ({ title }: { title: string }) {
  const [pageTitle, blogTitle] = title.split("|");
  return (
    <div
      style={{
        height: "100%",
        width: "100%",
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        justifyContent: "center",
        backgroundColor: "#fff",
        fontSize: 32,
        fontWeight: 600,
      }}
    >
      <p
        style={{
          margin: "1rem",
          maxWidth: "630px",
          fontSize: "3.75rem",
          lineHeight: 1.5,
        }}
      >
        {pageTitle.trim()}
      </p>
      <p
        style={{
          position: "absolute",
          bottom: "1rem",
          right: "3rem",
          fontSize: "1.5rem",
        }}
      >
        {blogTitle.trim()}
      </p>
    </div>
  );
}

最後にOGPを設定したいページに openGraphLayout の設定を加えます. タイトルなどの設定と同様に定数として宣言するだけです.

index.tsx
export const title = "タイトル";
export const url = "/";
export const layout = "layout.tsx";
+ export const openGraphLayout = "og_images.tsx";

これでビルドしてみると, 画像ファイルが生成されていることがわかります.

$ deno task build
🔥 /index.png <- (generated)

Metas の設定

画像を生成することができましたが, OGPとして設定するには meta タグを設定する必要があります. Metas プラグインを導入することでOGPに関する meta タグが自動で設定されます[6].

_config.ts
import metas from "lume/plugins/metas.ts";

site.use(metas());

OGPに関する meta タグは基本的に自動で生成されるため, ページごとに設定する値はほとんどありません. X(旧Twitter)では og:title が必要なため, これだけ設定します. JSXでは meta をオブジェクトとして宣言すればいいようです.

index.tsx
export const title = "タイトル";
export const url = "/";
export const layout = "layout.tsx";
export const openGraphLayout = "og_images.tsx";
+ export const metas = {
+   title: "タイトル",
+ };

meta タグに設定される画像のURLはサイトの設定に対する相対パスとして設定されます. デフォルトでは http://localhost:3000 となっているため, Web上ではOGP画像に到達しません. _config.ts でデプロイ先のURLを指定することでWeb上で正しく表示されるようになります[7].

_config.ts
import lume from "lume/mod.ts";

const site = lume({
  location: new URL("https://example.com"),
});

動的なページ生成

Lume ではジェネレーター関数を使うことで, 一度に複数のページを生成することができます[8]. この場合のOGPの設定についても触れます. とはいえこれまでとほとんど変わりません. ページのプロパティを Generator オブジェクトとして返却するだけです. OGP画像のテンプレートファイルなど共通のプロパティは通常通り宣言すると全てのページに反映されます. タイトルなど個別の設定は Generator オブジェクトに設定すると個別の値として反映されます.

[post].tsx
const posts = [
  {
    title: "post1",
    contents: "content1"
  },
  {
    title: "post2",
    contents: "content2"
  },
]

export const layout = "layout.tsx";
export const openGraphLayout = "og_images.tsx";

function* PostPages() {
  const postPages = posts.map((post) => {
    return {
      title: `${post.title} | タイトル`,
      url: `/${post.title}.html`,
      content: post.content,
      metas: {
        title: `${post.title} | タイトル`,
      },
    };
  });

  for (const postPage of postPages) {
    yield postPage;
  }
}

export default PostPages;

これで Lume でOGPを設定することができました.

https://twitter.com/toms74209200/status/1773366737892782513

脚注
  1. Lume, the static site generator for Deno - Lume ↩︎

  2. OG images - Lume ↩︎

  3. Deno で Satori を使ってSVGを生成する ↩︎

  4. Layout files are loaded from a special directory named _includes. Layouts - Lume ↩︎

  5. Satori is the library used to generate the images and only accepts JSX elements (or React-elements-like objects). OG images - Lume ↩︎

  6. Metas - Lume ↩︎

  7. The _config file - Lume ↩︎

  8. Create multiple pages - Lume ↩︎

Discussion