2019-10-17に投稿

fly.ioでSPA&OGP芸を最速かつゼロ依存でやる(package.jsonすら不要)

個人開発界隈ではOGP芸というものが流行っているみたいですね。

SNSにシェアする際に表示されるOGPの設定や画像をいい感じにするみたいなことのことですが、SPAではこれを生成するのが割と面倒だったりします。

自分が作っているg4でもOGPを使ったシェアを実装していますが、SSRを使って配信していて、割と設定が面倒だったりしています。

こんなの
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f35313430322f63356465616336612d333663642d366131342d646434302d3139333036306636353732612e706e67.png

今回、なるべくSSRをしないでSPAのままやってみることはできないかというのをfly.ioで試してみました。

作ったものの概要

  • 実際にOGP画像として表示される画像は/image.png?i=0で配信する。
  • /?i=0のようなパラメータをアクセスすると、入力した↑を含むOGPが反映されたhtmlを表示する
  • fly.ioが日本語に対応してないので、titleに日本語は使えない
  • せっかくfly.ioを使ってますが、今回はOGPだけにフォーカスしたいのでキャッシュ周りは実装してません

作ったもの

https://og-image-sample.edgeapp.net?i=0

or

https://og-image-sample.edgeapp.net?i=1

これをtwitterやfacebookなどでシェアしてみてください。

作り方

事前にflyのcliをPCにインストールしておく
npmは必要ないです(あったほうが便利だけど最速なので)

必要なファイルは4つだけ
- index.js: なんか処理書くやつ
- template.html: テンプレートです。ここに情報を流し込む
- fly.yml: なんか設定書くやつ
- sample.svg: OGP芸したい適当なsvg。今回はURLによって内容を書き換えるため雑に{{title}}みたいなやつをここに書いて、テキスト置換でそこに内容を埋め込んでます。

``` html:template.html






fly.ioで最速ogp芸











fly.ioでogp芸をする場合のサンプルだよ




templateはこんな感じになりました。 ogpのcontentは置き換えるので何でもいいです。とりあえずさり気なくg4のものを入れてアピールしておきます。 次に`index.js`です。こちらにすべての処理を書きます。 ``` js:index.js import { Image } from '@fly/image' import { mount } from "@fly/fetch/mount" // templateをテキストで取得するFunction async function getTemplate() { const resp = await fetch("file://src/template.html") return await resp.text() } // svgをテキストで取得しつつ中身ちょっと埋め込めるFunction async function getSvgText(title) { const resp = await fetch("file://src/sample.svg") const text = await resp.text() // g4(https://www.g-g-g-g.games)ではReactでテキスト化されたsvgを吐いてるが、とりあえず単純に置換する return text.replace('{{content}}', title) } // 画像形式のレスポンス作るFunction async function responseImage(svgText) { const svgResp = new Response(Buffer.from(svgText)) const buf = await svgResp.arrayBuffer() const png = new Image(buf).png() const result = await png.toBuffer() return new Response(result.data, { headers: { 'Content-Type': 'image/png', 'Content-Length': result.data.byteLength.toString(), } }) } // 出力データのパターン const TITLES = [ 'g4 is pomodoro rpg!', 'fly.io de OGP!!', ] // fly.ioのrouterみたいなやつ。ここに処理を書いてく。 const mounts = mount({ // このパスでogpの画像を生成する '/image.png': async (req, init) => { const url = new URL(req.url) // URLからQueryStringを取得 const index = url.searchParams.get('i') if (index !== '0' && index !== '1') { return new Response('not found', { status: 404 }) } // 対応したタイトルを取得 const title = TITLES[index] // タイトルをsvgに埋め込んだテキストを作る const svgText = await getSvgText(title) // svgからpng画像を生成する return responseImage(svgText) }, // このパスをシェアする '/': async (req, init) => { const url = new URL(req.url) // URLからQueryStringを取得 const index = url.searchParams.get('i') if (index !== '0' && index !== '1') { return new Response('not found', { status: 404 }) } // 対応したタイトルを取得 const title = TITLES[index] // テンプレートをparseして編集できるようにする const doc = Document.parse(await getTemplate()) // テンプレートにOGPを埋め込む doc.querySelector('meta[name="description"]').setAttribute('content', title) doc.querySelector('meta[property="og:url"]').setAttribute('content', url.href) doc.querySelector('meta[property="og:title"]').setAttribute('content', title) doc.querySelector('meta[property="og:description"]').setAttribute('content', title) doc.querySelector('meta[property="og:image"]').setAttribute('content', `${url.origin}/image.png?i=${index}`) doc.querySelector('meta[property="og:image:alt"]').setAttribute('content', title) // htmlを返す return new Response(doc.documentElement.outerHTML, { headers: { 'Content-Type': 'text/html' }, status: 200, }) }, }) // リクエストをmountsの定義を使って処理するように設定する fly.http.respondWith(mounts)

index.jsはこんな感じ。
/template.html のogpを書き換えて出すだけ。
/image はsvgファイルを読み込んで文字列を置換したものをpngに変換して返してます。

fly.ymlやsvgファイルは特に特別な設定はないのでドキュメントや最後にソースを貼るのでそちらを見ていただければ。

あとは、fly.ioのコンソールでアプリを作って、fly deploy するだけ。

再度になりますが、

https://og-image-sample.edgeapp.net?i=0

or

https://og-image-sample.edgeapp.net?i=1

これをtwitterやfacebookなどでシェアしてみてください。

以上になります。ソースはこちらにあります。

Originally published at qiita.com

shwld

フリーランスエンジニア js, Rails, Swift, React Native, 機械学習など何でもやります pomodoroの合間につぶやくことがあります

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

関連記事

コメント