英語の勉強ブログみたいの復帰させようとして、GitHubでやるのがいいと思ってたタイミングでGitHub IssueをCMSとして使う話を見たので作った。
元ネタ:
元ネタからの変更点
URLを number
のIDベースにしたかったので、GraphQLのクエリも特定のIssue Idを元に取得するものへ変更している。
|
const ISSUE_QUERY = ` |
|
query issue($owner: String!, $repo: String!, $id: Int!) { |
|
repository(owner: $owner, name: $repo) { |
|
issue(number: $id) { |
|
number |
|
title |
|
bodyHTML |
|
bodyText |
|
labels(first: 5) { |
|
nodes { |
|
name |
|
} |
|
} |
|
url |
|
createdAt, |
|
comments(first: 1){ |
|
totalCount |
|
} |
|
} |
|
} |
|
} |
|
`; |
このクエリをもっと頑張ると、特定のissueやprのURLからその情報をまとめて取得するクエリとかも作れる。
これをREST APIでやるとn回のAPIコールする必要があるけど、GraphQLだと1回でできる(ただし、クエリもそれなりに遅い。数十コだと2-3秒かかることある)
元のコードだと、Cloudflareの$5/monthで使えるCloudflare Workers KVという機能を使っていた。
ただ、元データはIssueでブログ自体はIssueの別Viewでしかないので、ただのキャッシュで問題なさそうと思ってCache APIベースに変更した。
Cloudflare Workers KVはKey-Value Storageなので、もっとインタラクティブな機能とか、デプロイせずに状態を変更したい場合は必要になってくる感じ。
ブログみたいなやつでは、リクエストに対するレスポンスがキャッシュできて、それが配信できればよかったのでCache APIでほぼカバーできていた。
Cache APIの制限として、キャッシュのDeleteや中身を見ての処理などは制限されていた。
Cache APIはService WorkerででてくるCache インターフェイスの実装になっているけど、caches.delete(namespace)
や cache.keys()
、cache.has()
などは実装されてなくて、キャシュを列挙したりキャッシュの中身を見ることはできないようになっていた。
なので、Cache APIではopaque responseを扱う感じになって、明示的にキャッシュを中身を見て処理を分ける - つまりCache APIをKey-Value Storageみたいに使うようにはできてなかった。
デプロイしたときに、Cache APIのキャッシュをすべてクリアしたい場合はcaches.open(namespace)
で、デプロイ時に新しいキーを渡してそれを元にキャッシュを扱うと擬似的にキャッシュをクリアできる。
const currentCaches = await caches.open(新しいネームスペース);
CloudflareのAPIにPurge All Filesもあるけど、workers_dev
(worker.dev
ドメイン)を使っている場合は、そもそもzone idがないため、このAPIの使い方が謎な状態になっていた。(よくわからない)
Cloudflare Workers KVの場合は、ちゃんと削除コマンドが用意されているので、Issueを変更したらキャッシュだけ消すみたいのも実装できる。
GitHub Actionでcurl叩くのに10秒ぐらいなので、大体20秒ぐらいで反映されるブログが作れると思う。
今のCache APIを使った仕組みだと、Issueやコードに変更があるたびにGitHub Actionsでデプロイしているので、反映まで1-2分かかる感じになっている。
デバッグ
Cache APIは wrangler preview
では無効化されているので、基本的にデプロイしないとデバッグできない。
また、Cloudflare Workerにはデバッグ用のダッシュボードとかがまだないので(管理画面はログすら見れない)、wrangler tail
を使ってデプロイしたもの標準出力/標準エラーをコンソールに出す感じでデバッグした。
wrangler tail
の使い方がめっちゃわかりにくいので使い方のメモ。
デフォルトのCloudflare Worker用のトークンには"Workers Tails"のパーミッションがついてないので、トークンにパーミッションをつけるところから始める必要がある(最小権限の原則らしい)
次のようなエラーがでた場合は"Workers Tails"のパーミッションがついてない。
🦚 Setting up log streaming from Worker script "xxx". Using ports 8080 and 8081.
Closing tail session...
Error: ⚠️ Code 10000: Authentication error
🕵️ Make sure your API token has permission to both edit and read workers on your account
wrangler tail
の使い方
- https://dash.cloudflare.com/profile/api-tokens からログインしてるトークンに"アカウント > Workers Tails > 読み取り"の権限を追加する
wrangler tail --env production
で待機する(たまに失敗する)
- 実際にアクセスしてエラーを発生させる
パフォーマンス
元ネタとほぼ同じ。
GitHub Issueを直で見たときも最速は30msでDocumentは返ってくる。
ただ他のJavaScriptをまったり、たまにつっかかるときがある感じ。
ブログの方は余計なものがまだ何もないので、常にその最速のパターンを引いている感じ。
GitHubリポジトリを別の見せ方したいことは結構あるので、そういう用途にはCloudflare Workersは結構向いているかもしれない。
エディタ
Issue画面でそのまま入力している。
textlint editorとかGrammarlyの拡張とか動くし、画像もそのままアップロードできるし、リロードで保存されてるからまあ普通によさそう。
もっといいエディタ使いたかったらコピペするとか、korefileみたいのを使ってリポジトリをCMS的に使うとかもできるけどあんまり気軽じゃなくなるので、ウェブで完結する形であることに意味がありそう。
おもしろいポイント
GitHub Issueなので、 #1 や @azu みたいなリファレンスリンクやメンションがもそのままブログにリンクとして反映される。
これは、レンダリングはGitHub側がやっているHTMLをそのまま表示しているからだと思う。
GitHubのCSSを使うと表示も似た感じになる。(コードリンクの埋め込みやシンタックスハイライトも機能する)
この発想自体は、昔書いてたものと似ているので、結構馴染みある。
これを書いてたときと違ってGitHub Actionsがあるので、自分のブログ(GitHub Issues)に対するbotみたいなものが簡単につくれるというのがおもしろいポイントになるかもしれない。
特定のワードがあったらIssueに反映する仕組みとか、そういうのもGitHub Actionsでイベントで書けるし、GraphQLがかなり柔軟なのでREST APIでは面倒なアグリゲーションとかもできてしまうので、いろいろ遊び方がありそう。
その他
- Jekyllとかのブログと違って、Pull Requestで修正みたいなことができない
- 権限的にCollaboratorにやってもらうしかできない
- レビューみたいなのはやりにくい(PRだとコメント書けるのでセルフレビューしやすいし、CIもつなぎ込みやすい)
- ファイルベースではないので、まとめて編集みたいのは仕組みが必要になる
- ローカルで編集するときにgit pullしなくてもいいので楽
- コンテンツとコメント欄が一体的になっているので遊びの余地がありそう
- GitHub Issueはmp4のアップロードに対応していない
- デプロイ時に記事やサイトを静的サイトとしてビルドするわけじゃないので、反映が比較的早い
- リクエスト受けたタイミングでSSRして、それをCDNにキャッシュというのをCDN Edgeで動かしている
- キャッシュがない場合はSSRを含め表示されるまで400~500msぐらいかかってる