okaryo.log

HTMLとCSSからSVGを生成できるvercel/satoriを動かしてみる | okaryo.log

HTMLとCSSからSVGを生成できるvercel/satoriを動かしてみる

    #HTML#CSS#SVG#satori#Vercel#React

はじめに

Next.jsではVercelのEdgeFunctions上で動作して動的にOGP画像を生成するライブラリに@vercel/ogというものがある。その中ではHTMLとCSSからSVGを生成するsatoriというライブラリが使われている。

去年の末にそのことを知ってからsatoriずっと触ってみたかった。今回触ってみて実際に動かすことができたので紹介する。

動かし方

パッケージのインストール

今回はsatoriを動かすことだけが目的なので最小限の構成で行う。

npm i -D satori typescript ts-node react @types/react

TypeScriptを使いたいのでそれを実行するためのts-nodeもインストールする。

また、satoriではJSX構文を使ってHTML/CSSを記述することもでき、今回もJSX構文でsatoriを利用する。JSX構文で書く場合はreactが必要なので一緒にインストールしておく。

tsconfig.jsonの準備

軽く動かしたいだけなのでtsc --initでtsconfig.jsonを作成した。

./node_modules/.bin/tsc --init

また、JSXを利用するのでcompilerOptions"jsx": "react-jsx"を指定する。

{
  "compilerOptions": {
    ...その他の設定
    "jsx": "react-jsx" // これを追加
  }
}

フォントデータの準備

satoriではSVG内で利用するフォントのデータを用意しておく必要がある。今回はGoogleFontsから適当にRobotoフォントをダウンロードして利用する。

これをsrc/assets/Roboto-Medium.ttfに配置しておいた。

satoriの記述

src/App.tsxに以下の処理を書いた。fsでフォントデータを読み込み、satori関数でSVGを生成する。第一引数でJSX形式でSVGのレイアウトを記述し、第二引数でSVGのサイズやフォントなどのオプションを設定する。

// src/App.tsx
import fs from 'fs'
import satori from 'satori'

async function App() {
  const font = fs.readFileSync('./src/assets/Roboto-Medium.ttf')
  const svg = await satori(
    <div
      style={{
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        height: '100%',
        width: '100%',
        color: 'black',
        backgroundColor: 'green'
      }}
    >
      hello, world
    </div>,
    {
      width: 600,
      height: 400,
      fonts: [
        {
          name: 'Roboto',
          data: font,
          weight: 400,
          style: 'normal',
        },
      ],
    },
  )

  console.log(svg)
}

export default App

src/main.tsにこれを実行するための処理を書いた。軽く動かすだけならファイルを分割する必要はないと思われる。

// src/main.ts
import App from './App'

App()

いざ実行

package.jsonに実行スクリプトを用意しておく。

{
  "scripts": {
    "dev": "ts-node src/main.ts"
  },
}

これを実行してみるとSVGが出力された。

$ npm run dev

<svg width="600" height="400" viewBox="0 0 600 400" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="600" height="400" fill="green"/><path fill="black" d="M261.8 193.5L261.8 198.0Q262.8 196.9 264.2 196.9L264.2 196.9Q266.9 196.9 266.9 200.0L266.9 200.0L266.9 205.5L265.0 205.5L265.0 200.0Q265.0 199.2 264.7 198.8Q264.3 198.4 263.5 198.4L263.5 198.4Q262.4 198.4 261.8 199.4L261.8 199.4L261.8 205.5L259.9 205.5L259.9 193.5L261.8 193.5ZM272.6 205.6L272.6 205.6Q270.8 205.6 269.7 204.5Q268.5 203.4 268.5 201.5L268.5 201.5L268.5 201.2Q268.5 200.0 269.0 199.0Q269.5 198.0 270.4 197.4Q271.3 196.9 272.4 196.9L272.4 196.9Q274.1 196.9 275.0 198.0Q276.0 199.1 276.0 201.1L276.0 201.1L276.0 201.9L270.4 201.9Q270.5 202.9 271.1 203.5Q271.8 204.1 272.7 204.1L272.7 204.1Q274.0 204.1 274.8 203.1L274.8 203.1L275.8 204.0Q275.3 204.8 274.5 205.2Q273.6 205.6 272.6 205.6ZM272.4 198.4L272.4 198.4Q271.6 198.4 271.1 198.9Q270.6 199.5 270.5 200.5L270.5 200.5L274.1 200.5L274.1 200.3Q274.0 199.4 273.6 198.9Q273.1 198.4 272.4 198.4ZM279.5 193.5L279.5 205.5L277.6 205.5L277.6 193.5L279.5 193.5ZM283.5 193.5L283.5 205.5L281.6 205.5L281.6 193.5L283.5 193.5ZM285.3 201.3L285.3 201.2Q285.3 199.9 285.8 198.9Q286.2 197.9 287.1 197.4Q288.0 196.9 289.2 196.9L289.2 196.9Q290.9 196.9 292.0 198.0Q293.0 199.1 293.1 200.9L293.1 200.9L293.1 201.3Q293.1 202.6 292.6 203.6Q292.2 204.6 291.3 205.1Q290.4 205.6 289.2 205.6L289.2 205.6Q287.4 205.6 286.3 204.4Q285.3 203.3 285.3 201.3L285.3 201.3ZM287.2 201.3L287.2 201.3Q287.2 202.6 287.7 203.4Q288.2 204.1 289.2 204.1Q290.2 204.1 290.7 203.4Q291.2 202.6 291.2 201.2L291.2 201.2Q291.2 199.9 290.7 199.1Q290.1 198.4 289.2 198.4L289.2 198.4Q288.3 198.4 287.7 199.1Q287.2 199.9 287.2 201.3ZM295.0 208.0L295.0 208.0L294.0 207.4Q294.4 206.7 294.6 206.2Q294.8 205.7 294.8 205.1L294.8 205.1L294.8 203.6L296.5 203.6L296.5 205.0Q296.5 205.8 296.1 206.7Q295.6 207.5 295.0 208.0Z M307.9 197.0L309.6 202.9L311.0 197.0L312.8 197.0L310.5 205.5L309.0 205.5L307.2 199.7L305.4 205.5L303.8 205.5L301.5 197.0L303.4 197.0L304.7 202.8L306.5 197.0L307.9 197.0ZM313.8 201.3L313.8 201.2Q313.8 199.9 314.3 198.9Q314.7 197.9 315.6 197.4Q316.5 196.9 317.7 196.9L317.7 196.9Q319.4 196.9 320.5 198.0Q321.5 199.1 321.6 200.9L321.6 200.9L321.6 201.3Q321.6 202.6 321.1 203.6Q320.7 204.6 319.8 205.1Q318.9 205.6 317.7 205.6L317.7 205.6Q315.9 205.6 314.8 204.4Q313.8 203.3 313.8 201.3L313.8 201.3ZM315.7 201.3L315.7 201.3Q315.7 202.6 316.2 203.4Q316.7 204.1 317.7 204.1Q318.7 204.1 319.2 203.4Q319.7 202.6 319.7 201.2L319.7 201.2Q319.7 199.9 319.2 199.1Q318.6 198.4 317.7 198.4L317.7 198.4Q316.8 198.4 316.2 199.1Q315.7 199.9 315.7 201.3ZM327.7 197.0L327.6 198.8Q327.3 198.7 326.9 198.7L326.9 198.7Q325.6 198.7 325.1 199.7L325.1 199.7L325.1 205.5L323.2 205.5L323.2 197.0L325.0 197.0L325.1 198.0Q325.8 196.9 327.0 196.9L327.0 196.9Q327.4 196.9 327.7 197.0L327.7 197.0ZM330.9 193.5L330.9 205.5L329.0 205.5L329.0 193.5L330.9 193.5ZM332.6 201.2L332.6 201.2Q332.6 199.2 333.5 198.1Q334.4 196.9 335.9 196.9L335.9 196.9Q337.3 196.9 338.1 197.8L338.1 197.8L338.1 193.5L340.0 193.5L340.0 205.5L338.3 205.5L338.2 204.6Q337.3 205.6 335.9 205.6L335.9 205.6Q334.4 205.6 333.5 204.4Q332.6 203.2 332.6 201.2ZM334.5 201.4L334.5 201.4Q334.5 202.6 335.0 203.4Q335.5 204.1 336.4 204.1L336.4 204.1Q337.5 204.1 338.1 203.1L338.1 203.1L338.1 199.4Q337.6 198.4 336.4 198.4L336.4 198.4Q335.5 198.4 335.0 199.2Q334.5 199.9 334.5 201.4Z "/></svg>

これを表示してみたものが以下の画像だ。無事にsatoriを動かせたようだ。

今回のコードは以下のレポジトリに置いておいた。必要に応じて参考にしてみてほしい。

おわり

SVGをJSX構文で記述できて簡単に生成できたのはかなり便利で驚いた。satoriは内部で独自のレンダリングエンジンを実装しているっぽくて、完全にCSSのプロパティに対応できているというわけではないようだ。詳しくはREADMEを読んでみてほしい。


関連記事
最新記事
プロモーション

This site uses Google Analytics.