okaryo.log

JSX構文でOG画像を作成できるGatsbyプラグインgatsby-plugin-satorareを公開した | okaryo.log

JSX構文でOG画像を作成できるGatsbyプラグインgatsby-plugin-satorareを公開した

    #個人開発#Gatsby#satori

どんなプラグインか

記事ごとに動的なOG画像をJSX構文で記述して作成できるGatsbyプラグイン。作成した画像へのパスはMarkdownRemarkごとのGraphQLクエリから取得できる。

詳しい使い方はREADMEに書いたのでそちらを読んでみてほしい。

簡単に使い方を説明してみると、以下のようなJSX/TSXファイルを作成しておくと、

export default function(frontmatter: MyFrontmatter) {
  const { title } = frontmatter

  return {
    image: (
      <div
        style={{ ... }}
      >
        {title}
      </div>
    ),
    options: {
      width: 1200,
      height: 630
    }
  }
}

MarkdownRemarkに対するGraphQLのクエリでOG画像用のパスを取得できるようになり、そのパスへアクセスしてみると上記のJSX/TSXファイルで作成したOG画像が生成されている、というものだ。

// query
`
query MyQuery {
  markdownRemark(id: {eq: "45a4a997-f230-56cc-a94a-004db0b667d7"}) {
    ogImage {
      publicURL
    }
  }
}
`

// result
{
  "data": {
    "markdownRemark": {
      "ogImage": {
        "publicURL": "/static/8d5a6b2a951985acb20f041bf8f52e61/8d5a6b2a951985acb20f041bf8f52e61.png"
      }
    }
  }
}

実際にプラグインを使ってこの記事に対して生成されたOG画像がこちら。かなりリッチなOG画像になった。

OG画像

作成したきっかけ

去年の末にvercel/satoriというJSX構文でSVGを生成できるライブラリを知り、感銘を受けた。自分もこれを使って何か作ってみたいと思っていたところ、1月末くらいに自分のGatsby製のブログのOG画像を生成できるようなプラグインを作ろうと思いついた。

Gatsbyのプラグイン一覧で同様の手法を使っているライブラリはないかと探したところ、まだなさそうなのだったので早速取りかかり始めた。

苦労したこと

プラグインの使い方やGatsbyのAPI自体は公式のドキュメントがあったのでかなり助かった。ただ、実際に自分がやりたいことがどうやって実現できるのか、そもそもできるのかが全然わからなかったので苦労した。似たようなことをやってそうなプラグインのソースコードをGitHubでたくさん読んだ。

これから作るプラグインが開発者にどんな使われ方をすれば使いやすいかという設計にも悩んだ。ある方針が見えてきて実装し始めたとしてもGatsbyのAPI的に実現が難しそうで断念したりとプラグインの方針を二転三転した。

また、このプラグインでは開発者が作成したJSX/TSXファイルを実行時に読み込んでOG画像に変換しているのだが、この変換処理は今も悩んでいる。開発者が作成したJSX/TSXファイルをどうやって動的に実行すれば良いのか全然分からなかった。もしかすると一般的な良い方法があるのかもしれないが、さっぱり分からなかったので以下のような力技でお茶を濁した。実行時にJSX/TSXファイルを読み込んでトランスパイルし、それで生成されたJavaScriptコードの文字列をVM上で実行した。

import typescript from 'typescript'
import { NodeVM, VMScript } from 'vm2'

// 開発者が作成したファイルを読み込み
const jsxCode = fs.readFileSync(jsxCodePath, 'utf8')
// 実行時にトランスパイルする
const transpileModule = typescript.transpileModule(jsxCode, {
  compilerOptions: {
    jsx: typescript.JsxEmit.ReactJSX,
  }
})
// トランスパイルしたJavaScriptコード文字列をVM上で実行する
const vm = new NodeVM({
  require: {
    external: true
  }
})
const jsCode = new VMScript(transpileModule.outputText)
vm.run(jsCode).default(frontmatter)

スマートな方法をご存知の方がいらっしゃれば教えてください…mm

改善したいこと

まずは動くものをリリース、を目標にやってきたのでいろんなことを置き去りにした。とりあえずは以下を対応していきたい。

  • MarkdownRemark以外の種類のNodeにもOG画像用のパスを生やす
  • 開発者がフォントの種類を選べるようにする
  • 絵文字が動かなかったので対応する
  • ホットリロードのたびにも処理が走っているぽいのでなんとかする
  • キャッシュ周りが不穏なので調べる

おわり

拙作のプラグインですがもし興味があれば使ってみてくださいmm

バグや機能要望があればGitHubのイシューにてお気軽にお申し付けください。


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

This site uses Google Analytics.