Deno/Lume でOGPを設定する
Deno の静的サイトジェネレータである Lume[1] で動的なOGP生成をします.
環境
- Deno 1.41.0
- Lume 2.1.2
- React 18.3.0
OG images の利用
OGPの画像を生成するためには OG images というプラグインを利用します[2]. ほとんど公式ドキュメントの通りです. OG images のプラグインを読み込み, OGP画像を生成するテンプレートファイルを配置して, OGPを設定したいページで宣言するだけです.
プラグインの読み込み
まず _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].
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画像を生成する関数は title
や description
など, ページ内で指定できるプロパティを引数としてとることができるようです.
またこのプラグインでは Satori を利用するため, React のみ利用できます. Preact を使っているとレンダリングがうまくいきません[5].
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
の設定を加えます. タイトルなどの設定と同様に定数として宣言するだけです.
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].
import metas from "lume/plugins/metas.ts";
site.use(metas());
OGPに関する meta タグは基本的に自動で生成されるため, ページごとに設定する値はほとんどありません. X(旧Twitter)では og:title
が必要なため, これだけ設定します. JSXでは meta
をオブジェクトとして宣言すればいいようです.
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].
import lume from "lume/mod.ts";
const site = lume({
location: new URL("https://example.com"),
});
動的なページ生成
Lume ではジェネレーター関数を使うことで, 一度に複数のページを生成することができます[8]. この場合のOGPの設定についても触れます. とはいえこれまでとほとんど変わりません. ページのプロパティを Generator オブジェクトとして返却するだけです. OGP画像のテンプレートファイルなど共通のプロパティは通常通り宣言すると全てのページに反映されます. タイトルなど個別の設定は Generator オブジェクトに設定すると個別の値として反映されます.
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を設定することができました.
-
Layout files are loaded from a special directory named
_includes
. Layouts - Lume ↩︎ -
Satori is the library used to generate the images and only accepts JSX elements (or React-elements-like objects). OG images - Lume ↩︎
Discussion