🧘

Deno で Satori を使ってSVGを生成する

2024/04/03に公開

Deno/Lume でOGPを利用するために, まずは Satori を使ってSVGを生成する方法を調べました. もともと Deno/Lume で Preact を使っていたため, SVGが生成されないというところがスタートです.

環境

  • Deno 1.41.3
  • React 18.2.0
  • Satori 0.10.13

https://github.com/toms74209200/deno-satori-example

React の設定

まずは Deno でJSXを扱えるように設定を行います. Deno では React 17 以降の JSX transform に対応しています[1]. 利用するには deno.jsoncompilerOptions を追加します. 設定項目は tsconfig と同様のようです. Deno 公式では Preact を使った例が紹介されていますが, 通常の React を利用することも可能です. というか React じゃないと Satori が動かないため, React を設定します. React 17 以降の JSX transform を使うには react-jsx を指定します[2][3].

deno.json
{
  "jsx": "react-jsx",
  "jsxImportSource": "react",
}

https://github.com/toms74209200/deno-satori-example/blob/master/deno.json#L2-L3

また, React と React DOM API を imports に加えます.

deno.json
{
  "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/",
  },
}

https://github.com/toms74209200/deno-satori-example/blob/master/deno.json#L9-L15

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ファイルを生成することができました.

生成したSVGの画像. 「hello, world」と書いてある

日本語フォントのダウンロード

先ほど 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 の設定にはいろいろと項目がありますが, 最低限名前 namedata を設定するだけで良いです. また日本語であればフォールバックされるため, 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ファイルを生成することができました.

生成したSVGの画像. 「あのイーハトーヴォのすきとおった風」と書いてある

これで Deno でも動的にOGPを生成することができます.

脚注
  1. Configuring JSX in Deno | Deno Docs ↩︎

  2. TypeScript: TSConfig Reference - Docs on every TSConfig option ↩︎

  3. Deno+React+jsxImportSourceの設定 ↩︎

  4. Inter font family ↩︎

  5. OG images - Lume ↩︎

  6. googlefonts/morisawa-biz-ud-gothic ↩︎

  7. download@v2.0.2 | Deno ↩︎

  8. zip@v1.2.5 | Deno ↩︎

Discussion