Deno で Satori を使ってSVGを生成する
Deno/Lume でOGPを利用するために, まずは Satori を使ってSVGを生成する方法を調べました. もともと Deno/Lume で Preact を使っていたため, SVGが生成されないというところがスタートです.
環境
- Deno 1.41.3
- React 18.2.0
- Satori 0.10.13
React の設定
まずは Deno でJSXを扱えるように設定を行います. Deno では React 17 以降の JSX transform に対応しています[1]. 利用するには deno.json
に compilerOptions
を追加します. 設定項目は tsconfig
と同様のようです. Deno 公式では Preact を使った例が紹介されていますが, 通常の React を利用することも可能です. というか React じゃないと Satori が動かないため, React を設定します. React 17 以降の JSX transform を使うには react-jsx
を指定します[2][3].
{
"jsx": "react-jsx",
"jsxImportSource": "react",
}
また, React と React DOM API を imports
に加えます.
{
"imports": {
"react": "https://esm.sh/react",
"react/": "https://esm.sh/react/",
"react-dom": "https://esm.sh/react-dom",
"react-dom/": "https://esm.sh/react-dom/",
},
}
Satori の利用
Satori の利用方法に関しては, チュートリアル通りに設定するだけです. ただし, Language Server がJSXを正しく解釈してくれないため, React を明示的にインポートする必要があります(New JSX import ってなんだっけ).
また, フォントの指定が必要なため, Vercelで利用されている Inter[4] という欧文フォントを使用します[5].
import React from "react";
import satori from "satori";
const response = await fetch(
"https://cdn.jsdelivr.net/npm/@xz/fonts@1/serve/src/inter/Inter-Regular.woff",
);
const fontBuf = await response.arrayBuffer();
const svg = await satori(
<div style={{ color: "black" }}>hello, world</div>,
{
width: 600,
height: 400,
fonts: [
{
name: "inter",
weight: 400,
style: "normal",
data: fontBuf,
},
],
},
);
これでSVGファイルを生成することができました.
日本語フォントのダウンロード
先ほど Inter という欧文フォントを利用しましたが, このままだと日本語が全て豆腐 (□
) になってしまうため, 日本語に対応したフォントを設定します. ローカルのフォントを使うこともできますが, CI/CDツールを使用することを想定して, フォントをダウンロードしてきて, 設定してみましょう.
今回は GitHub 上で配布されている Morisawa BIZ UDGothic[6] を利用します. GitHub の Release ページから. ZIP形式で配布されているフォントをダウンロードしてきて解凍し, フォントファイルを読み込みます.
フォントファイルのダウンロードには fetch
を利用することもできますが, バイナリファイルのダウンロードに適した download
というライブラリを利用します[7]. URLとダウンロード先を指定するだけです.
import { download } from "download";
await download(
"https://github.com/googlefonts/morisawa-biz-ud-gothic/releasesdownload/v1.051/BIZUDGothic.zip",
{
dir: ".",
file: "download.zip",
},
);
ZIPファイルの展開は zip
というライブラリを使用します[8]. 展開したいZIPファイルと展開先を指定すると, 展開したディレクトリのパスが返ってきます.
import { decompress } from "zip";
const destination = await decompress("./download.zip", ".");
バイナリファイルの読み込みは Deno の標準APIと std
ライブラリで行うことができます. 普通にファイルを開いて読み込むだけです.
import { readAll } from "std/io/read_all.ts";
const fontFile = await Deno.open(fontPath);
const fontBuf = await readAll(fontFile);
fontFile.close();
これでフォントファイルの読み込みができました. あとは Satori に設定するだけです. fonts
の設定にはいろいろと項目がありますが, 最低限名前 name
と data
を設定するだけで良いです. また日本語であればフォールバックされるため, font-family
を指定しなくても設定したフォントが利用されます.
import satori from "satori";
const svg = await satori(
<div
style={{
height: "100%",
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
backgroundColor: "#fff",
fontSize: 32,
}}
lang="ja-JP"
>
<div>あのイーハトーヴォのすきとおった風</div>
</div>,
{
width: 600,
height: 400,
fonts: [{
name: "BIZUDPGothic-Regular",
data: fontBuf,
}],
},
);
日本語フォントを利用してSVGファイルを生成することができました.
これで Deno でも動的にOGPを生成することができます.
Discussion