tag:crieit.net,2005:https://crieit.net/tags/OGP%E8%8A%B8/feed
「OGP芸」の記事 - Crieit
Crieitでタグ「OGP芸」に投稿された最近の記事
2019-10-17T05:05:57+09:00
https://crieit.net/tags/OGP%E8%8A%B8/feed
tag:crieit.net,2005:PublicArticle/15487
2019-10-17T05:05:57+09:00
2019-10-17T05:05:57+09:00
https://crieit.net/posts/fly-io-SPA-OGP-package-json
fly.ioでSPA&OGP芸を最速かつゼロ依存でやる(package.jsonすら不要)
<p>個人開発界隈ではOGP芸というものが流行っているみたいですね。</p>
<p>SNSにシェアする際に表示されるOGPの設定や画像をいい感じにするみたいなことのことですが、SPAではこれを生成するのが割と面倒だったりします。</p>
<p>自分が作っている<a target="_blank" rel="nofollow noopener" href="https://www.g-g-g-g.games">g4</a>でもOGPを使ったシェアを実装していますが、SSRを使って配信していて、割と設定が面倒だったりしています。</p>
<p>こんなの<br />
<a href="https://crieit.now.sh/upload_images/0f6a4a0608c5dc3550a5c44abd805d7e5da777f12f09e.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/0f6a4a0608c5dc3550a5c44abd805d7e5da777f12f09e.png?mw=700" alt="68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f35313430322f63356465616336612d333663642d366131342d646434302d3139333036306636353732612e706e67.png" /></a></p>
<p>今回、なるべくSSRをしないでSPAのままやってみることはできないかというのをfly.ioで試してみました。</p>
<h1 id="作ったものの概要"><a href="#%E4%BD%9C%E3%81%A3%E3%81%9F%E3%82%82%E3%81%AE%E3%81%AE%E6%A6%82%E8%A6%81">作ったものの概要</a></h1>
<ul>
<li>実際にOGP画像として表示される画像は<code>/image.png?i=0</code>で配信する。</li>
<li><code>/</code>に<code>?i=0</code>のようなパラメータをアクセスすると、入力した↑を含むOGPが反映されたhtmlを表示する</li>
<li>fly.ioが日本語に対応してないので、titleに日本語は使えない</li>
<li>せっかくfly.ioを使ってますが、今回はOGPだけにフォーカスしたいのでキャッシュ周りは実装してません</li>
</ul>
<h1 id="作ったもの"><a href="#%E4%BD%9C%E3%81%A3%E3%81%9F%E3%82%82%E3%81%AE">作ったもの</a></h1>
<p><a target="_blank" rel="nofollow noopener" href="https://og-image-sample.edgeapp.net?i=0">https://og-image-sample.edgeapp.net?i=0</a></p>
<p>or</p>
<p><a target="_blank" rel="nofollow noopener" href="https://og-image-sample.edgeapp.net?i=1">https://og-image-sample.edgeapp.net?i=1</a></p>
<p>これをtwitterやfacebookなどでシェアしてみてください。</p>
<h1 id="作り方"><a href="#%E4%BD%9C%E3%82%8A%E6%96%B9">作り方</a></h1>
<p>事前にflyのcliをPCにインストールしておく<br />
npmは必要ないです(あったほうが便利だけど最速なので)</p>
<p>必要なファイルは4つだけ<br />
- index.js: なんか処理書くやつ<br />
- template.html: テンプレートです。ここに情報を流し込む<br />
- fly.yml: なんか設定書くやつ<br />
- sample.svg: OGP芸したい適当なsvg。今回はURLによって内容を書き換えるため雑に<span>{</span><span>{</span>title<span>}</span><span>}</span>みたいなやつをここに書いて、テキスト置換でそこに内容を埋め込んでます。</p>
<p>``` html:template.html<br />
<!DOCTYPE html><br />
<html lang="ja"><br />
<head><br />
<meta charset="utf-8" /><br />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /><br />
<meta name="theme-color" content="#000000" /><br />
<title>fly.ioで最速ogp芸</title><br />
<meta name="description" content="by shwld" /><br />
<meta name="twitter:card" content="summary_large_image" /><br />
<meta name="twitter:creator" content="@shwld" /><br />
<meta property="og:type" content="website" /><br />
<meta property="og:url" content="https://www.g-g-g-g.games" /><br />
<meta property="og:title" content="shwld" /><br />
<meta property="og:description" content="shwld" /><br />
<meta property="og:image" content="https://www.g-g-g-g.games/assets/image.png" /><br />
<meta property="og:image:alt" content="shwld" /><br />
</head><br />
<body><br />
<h1 id="fly.ioでogp芸をする場合のサンプルだよ"><a href="#fly.io%E3%81%A7ogp%E8%8A%B8%E3%82%92%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AE%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%81%A0%E3%82%88">fly.ioでogp芸をする場合のサンプルだよ</a></h1><br />
</body><br />
</html></p>
<pre><code><br />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('<span>{</span><span>{</span>content<span>}</span><span>}</span>', 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)
</code></pre>
<p>index.jsはこんな感じ。<br />
<code>/</code> は<code>template.html</code> のogpを書き換えて出すだけ。<br />
<code>/image</code> はsvgファイルを読み込んで文字列を置換したものをpngに変換して返してます。</p>
<p>fly.ymlやsvgファイルは特に特別な設定はないのでドキュメントや最後にソースを貼るのでそちらを見ていただければ。</p>
<p>あとは、fly.ioのコンソールでアプリを作って、<code>fly deploy</code> するだけ。</p>
<p>再度になりますが、</p>
<p><a target="_blank" rel="nofollow noopener" href="https://og-image-sample.edgeapp.net?i=0">https://og-image-sample.edgeapp.net?i=0</a></p>
<p>or</p>
<p><a target="_blank" rel="nofollow noopener" href="https://og-image-sample.edgeapp.net?i=1">https://og-image-sample.edgeapp.net?i=1</a></p>
<p>これをtwitterやfacebookなどでシェアしてみてください。</p>
<p>以上になります。ソースは<a target="_blank" rel="nofollow noopener" href="https://github.com/shwld/fly.io-og-image">こちら</a>にあります。</p>
shwld