dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

2023年1月のふりかえり

今年もなるべく1ヶ月おきに書く。

前回:2022年のふりかえりと2023年にやりたいこと - dackdive's blog

✨ やったこと

簿記3級を取った

現職の業務ドメイン理解のためにようやく取得した。(正確には1月中には間に合わず合格したのは2/4)
1年ぐらい前に一度挫折してたのだが、年明けにやらねばという気持ちが再燃して3週間ぐらい集中して取り組んだ。
1月後半から大学の授業が始まるというので良い意味でお尻が決まってたのがよかった。

勉強にあたっては CPA Learning というサイトが無料で簿記の勉強ができてめちゃくちゃよかった。

大学(UoPeople)の新学期が始まった

1月後半から大学の新学期がスタートした。今期は CS1104 Computer Systems を取っている。

この講義で使用する教科書の1つが、気になってた「コンピュータシステムの理論と実装」らしい。早速買った。

今は NAND 回路とか加算器とかを学んでいる。この先どういうふうに発展していくのか楽しみ。

📝ブログ・登壇

今月はなし。

💬 所感

今月は簿記3級取得に大半の時間を費やしてその他のことが手つかずだったが、これぐらい1つのことに集中して取り組めたのはよかったと思う。
反面、業務で何をやっていたかという記憶がほとんどなく、達成感や成長を感じにくい月だった。四半期の境目で次に向けた準備をしていたからというのもあるが、週・月でやったことを振り返るようにしないとなかなかこの問題は解決しないのではないかという不安もある。何か良い方法あったら知りたい。コーチングとか受けるといいんだろうか。

💪2月のテーマ

一度オリャっと興味薄くなったものを削除した。来月は基本的には大学の授業で精一杯だと思う。。。

💸 買ったもの

正確には昨年末だが、左右分離式のキーボードを購入した。ようやく慣れてきた。。。
打ち心地はそこまで悪くないけど HHKB のほうが好きかな。Ultimate Hacking Keyboard も気になったけど値段で断念。いつか使ってみたい。

2022年のふりかえりと2023年にやりたいこと

例によって新年を迎えてしまったが今年も書く。

去年:

2022年中のふりかえり:

読んだもの

ちゃんと読んだ本はおそらくこの 2 冊だけだった。

また、仕事や技術関係ない本としては女の園の星を買った。めちゃくちゃよかった。

書いたもの

2022年に個人ブログに書いた記事は 18 件、Zenn に投稿した記事は 4 件だった。

仕事:Customer Reliability Engineer(CRE)という領域へのチャレンジ

仕事面では、これまでの Web アプリケーション開発を行うエンジニアから CRE というロールに転向したのが今年一番のチャレンジだった。
2022年の前半はプロダクト開発と兼任という形だったが、夏以降はこのロールに専念している。

CRE に関しては正直まだまだ「何をミッションとしたロールか?」とか「Reliability(信頼性)とは何に対するものか?」とかがきちんと言語化できてない部分もあり、何を為すべきか試行錯誤しながら進めている。それでも、今までより一層顧客の存在を強く意識しながら、エンジニアリングで解決できることを模索するのは非常に面白いテーマだと感じる。また、データ分析など技術的にも興味をそそられるトピックが転がっている。

また、業務に関するブログ執筆や勉強会登壇という形でアウトプットできたのも良かった。

(とはいえ、四半期に1記事ぐらいは活動内容をアウトプットしたいなと思ってたので、半分ぐらいしかできてないことになるが)

技術

技術面では、2022年これを新たに勉強した!と呼べるものがなかったように感じている。
だいたいが業務で関係しそうなフロントエンド系のトピックを素振りした、ぐらい。

学業:University of the People(UoPeople)

昨年9月から通い始めたオンラインの大学も気づけば1年経過していた。
とはいえ今年は転職したこともあって 2 term ほど休んでいるため、3 科目しか受講していない。
そのせいか、まだ入学してよかったと思えるような面白い科目にはめぐりあえてないなというのが正直なところ。

このあたりの感想は別途まとめたい。

プライベート

3人目の子供が産まれた。大変だけど楽しいです。
子供が3人になったことで今まで以上に自分のために使える時間が減ったのか?についてはまだよくわからない。時折夜泣きに悩まされる以外はそこまで劇的に変わった感じはしない。ただ洗濯など家事の負荷が全体的に少しずつ上がっているかもなという感覚はあり、家族でうまく分担したり金で解決できることは解決して省力化を図ったほうがいいかもしれない。

2023年にやりたいこと

1年という長期的なスパンで目標を立てるのがとても苦手で長続きしないので、基本的には毎月伸ばしたいことを棚卸ししてその都度自分が一番やりたい!と思ったことに投資していきたい。
CRE という仕事にやりがいを感じているしまだまだ全然できるようになっていないので引き続きそこを頑張っていきたいなと思いつつ、うまくいけばいくほど業務でプロダクトのコードを書く仕事からは離れることになると思うので
プライベートでコード書く習慣をいかに作れるか、が来年は大事になりそう。

また、特別技術的に学びたい領域はないものの、 Web フロントエンドの新しいライブラリだのなんだのの使い方をキャッチアップすることに対して若干の疲れというか虚無感(これを繰り返していても自分はエンジニアとして何も成長できないんじゃないか、という)みたいなものを最近は顕著に感じるので
来年はその割合を減らしつつ、もうちょっと流行り廃りに左右されないことを学びたい。大学に入学したモチベーションもそれなので。

先日、 Rust 界隈で有名な helloyuki さんが 2022年学んだ技術|helloyuki|note というブログ記事で

余談ですが今年は大学で使われるような教科書を買ってきて何分野か読むことにハマっていました。教科書は意外とコスパがよく情報も網羅的なので、特定のトピックを学びたいとなった際に何冊か読むのが好きです。

と書かれており、そうそう自分もそんなふうに1つのテーマに腰を据えて勉強したいんだったという気持ちを再確認した。

2022年11月のふりかえり

先月に続いて1ヶ月単位で書く。

前回:2022年10月のふりかえり - dackdive's blog

🚀 先月の伸ばしたいことリスト

11月も先月に続き「react-testing-library での良いテストの書き方を学ぶ」でした。
結果は、またしても進捗ほぼ0でした。

11月からまた大学の講義がスタートしたことと、月の中盤から後半にかけて Google タグマネージャー(GTM)を学びたい衝動に駆られてそちらを優先してしまったことなどが主な理由。
あと、伸ばしたいことリストに書いたときと比べてこれを学ばねばという緊急度や重要度が下がってしまい、それにつられてモチベーションも下がってしまったというのがありそう。

✨ やったこと

大学(UoPeople)の新学期が始まった

11/10 から大学の新学期がスタートした。今期は Programming 2 – CS 1103 を受講している。

以前受けた CS1102 と同じく、いわゆる普通のプログラミングの講義かつ言語は Java なのであまりモチベーションは高くない。
が、週によってはトピックが Stack や Queue といったデータ構造であったり Recursive Descent Parser というパーサーだったりするので、ちょっとだけコンピューターサイエンスを感じられて楽しい。

今期はなるべく課題に使う時間は抑えめにして、その分学びができるだけ大きくなるよう講義内容を自分なりにアレンジしたい。
たとえば教科書に書かれてるサンプルコードは全部 Kotlin で写経するとか。

Google タグマネージャーについて学んだ

本を一冊買って読んだ。

基本的なところはわかったがあまりまだ手を動かせてないので、reading-list のアクセス数を見られるようにする、などチャレンジしたい。

📝ブログ・登壇

ブログ1件のみという結果でした。

ブログ

💬 所感

1ヶ月はほんと一瞬。それでも強い気持ちを持たないと月初に立てた目標に全然手を付けられずその月が終わるということになりがち。

💪12月のテーマ

改めて興味ないものは一旦消して整理した。上位2件がいずれも新しいものになっている。
1つめの Linux のしくみは発売されたときから気になってたので、この機会に買ってみた。これを UoPeople と並行して少しでも読み進められれば万々歳って感じだと思う。

2つめのテクニカルライティングというか日本語スタイルガイドについては、以前 LINE のミートアップで知って買ったものの積ん読状態だった。が、最近社内でこれを有志で読もうという話をしていてモチベーションが再度高まったのでやっていくことにした。

💸 買ったもの

特になし。

「現場で使える Googleタグマネージャー実践入門」を読んだ

自分で作ったサイトのアクセス数分析ができるようになりたいなと思って Google アナリティクスとかを調べていたところ、Google タグマネージャー(以下 GTM)という存在を知ったので一冊本を買って読んでみた。

この本について

現場で使える Googleタグマネージャー実践入門 | マイナビブックス より引用。

■本書の特徴
Googleタグマネージャーの学習環境を構築できる
→ミスを恐れずにトライアンドエラーできるよう、本書では学習環境の構築から解説します。デモ環境で学習できるので、だれかに迷惑をかけることなく実践できます。
 
・逆引きとして、用途に合わせた項目がすぐ見つかる
→実際の現場でよく使われる事例を中心にまとめてあります。困りごとからすぐに事例を見つけられます。  
UAからGA4の移行にも対応できる →UAからGA4への移行にも対応できるよう、それぞれの設定方法を併記しています。新規設定だけでなく、移行にも利用いただけます。

発売日が2022年06月22日で GTM でググった中では新しく、また自分は手を動かしながら学べる系の本が好きなので良さそうな印象を受けこの本にした。

章の構成は以下。

Chapter1 Googleタグマネージャーとは
Chapter2 学習環境の構築
Chapter3 Googleタグマネージャーの導入
Chapter4 基本操作
Chapter5 現場で使える逆引きレシピ 基本編
Chapter6 現場で使える逆引きレシピ 応用編
Appendix 現場で役立つTips

感想

「GTM なんもわからん!」という状態でまず読む本としては良さそうに思った。
自分はある程度ネットの情報を調べた後にこの本を読んだのだが、GTM ってなんなの?GA との関係性は?とか、GTM の構成要素であるタグ・トリガー・変数の説明などは非常にわかりやすかった。

手を動かす系の本として、気軽に試せる環境を提供してくれてるのも良かった点。ただ1から順を追って学ぶハンズオンっぽい内容ではなく、後半(Chapter 5 & 6)によくあるユースケースをカバーしたレシピ集があるので気になったものをかいつまんで試す感じ。

レシピの一部を載せる。

# Chapter5 現場で使える逆引きレシピ 基本編

5-1 Googleアナリティクスの導入(UA, GA4)
5-2 外部リンククリック数の計測(UA, GA4)
5-3 メール送信(mailto)クリック数の計測(UA, GA4)
5-4 電話番号タップ数の計測(UA, GA4)
5-5 ボタンのクリック数の計測(UA, GA4)
5-6 SNSボタンのクリック数の計測(UA, GA4)
...

# Chapter6 現場で使える逆引きレシピ 応用編

6-1 オリジナルの変数作成
6-2 さまざまなファイルクリックの計測
6-3 仮想ページビュー数の計測
6-4 精読ページビューの計測
6-5 ブログの執筆者名・カテゴリー名の計測
...

書籍の内容とは関係ないが、最近本を読むときに「最初から最後まで全部読んですべてを理解しようとしない」を意識していて、それがやりやすい本でもあった。
実際 Chapter 4 の途中からはさっと目を通しただけだし、Chapter 5, 6 のレシピもとりあえず気になる Chapter 5 の一部だけやって、残りは必要になったときに読み返そう、という感じで 3, 4 時間程度で読了した。

環境は WordPress で、GTM もプラグインとしてインストールするため、開発者目線では React などで作ったアプリケーションにどう組み込むの?というのはイメージしにくいかも。ここについては Appendix 6 でコードスニペットを直接埋め込む方法も紹介されてはいる。

1つ残念だった点を挙げると、自分は GTM の中でも「データレイヤー」という機能が調べてもよくわからないな〜というのが本を買ったモチベーションだったのだが、データレイヤーについては説明もあっさりしていて、また手を動かして試すこともできなかった。(自分の理解では、データレイヤーは JavaScript を書いてデータを送信する必要があるのだが、WordPress でそれをやる方法がよくわからずだった)

学習メモ

Chapter 1 Google タグマネージャーとは

  • GTMはタグマネージメントツール=「さまざまなタグを一元管理できるツール」
  • Googleプロダクトとの親和性◎。GA4は測定IDを登録するだけで導入できる
  • マスタータグのみで複数のタグを一元管理できる:「ワンタグ」
    • 簡単にタグの追加・削除ができる
  • 1-2 Googleタグマネージャーの三大要素(タグ・トリガー・変数)
    • タグ
    • トリガー
      • 設定したタグを発動させるための「条件を設定する」こと
      • 例:サイト全ページのページビュー計測をGAで行う場合、「ページビュー」というトリガータイプを「全ページ」に発生させる
    • 変数
      • 例:「Page URL」というGTMの変数は現在のウェブページのURLを返す
      • あらかじめ用意された「組み込み変数」と、ユーザー側で新規に設定できる「ユーザー定義変数」の2種類

Chapter 4 基本操作

  • ゴール
    • プロダクト:GA(ユニバーサルアナリティクス)
    • 設定:対象サイトのすべてのページビューを計測できるようにする
  • 4-2 タグの種類について
    1. サポートされているタグ
      • Googleが公式にサポートしているタグ。GAやGoogle広告など
    2. コミュニティテンプレートギャラリー
    3. カスタムタグ
  • 4-9 データレイヤー変数
    • デフォルトでは取得できない独自データをGTMに渡すことで、GTM内でタグやトリガーとして活用できる仕組み

    サイト上でGTMのスニペットコードが読み込まれるごとに、データレイヤーの中にサイトで得たデータが送られ、その送られたデータを基にタグやトリガーが動作しています。つまり、GTMの機能としてさまざまな「タグ」や「トリガー」を利用できますが、それらはデータレイヤーの中に貯まっているデータを活用して動作しているという状況です

    • データレイヤー変数の作り方
      1. JavaScriptの実装
      2. データレイヤー変数の定義
      3. カスタムイベントの定義
      4. カスタムディメンションの作成

2022年10月のふりかえり

試験的に1ヶ月単位でやったことをふりかえってみる。

前回までは四半期おきだった:2022年7〜9月のふりかえり - dackdive's blog

🚀 先月の伸ばしたいことリスト

10月にやりたいと思ってたのは「react-testing-library での良いテストの書き方を学ぶ」でした。
こちらについてはほぼ進捗0という結果に。。。

こうなってしまった要因はいくつかあって、まず月の前半は個人開発で作ってた Google カレンダーの予定を色別に集計する君(生産性可視化おじさんと呼んでいる)をキリのいいところまで作り切る & ブログ書く、というのを優先していたこと。

そして月の後半はイベント登壇の準備で忙しかったこと。

極めつけに最終週は Zod が気になってついそっちを優先してしまったこと、が原因です。

後悔はしていない。が、ぐぬぬ。。。

✨ やったこと

↑でほとんど書いてしまったが、それ以外。

英語の勉強をはじめた

定期的にやってくる「英語勉強せねば」という感情がまたしても押し寄せてきて、同僚氏に薦められた「英語のハノン」という本を買った。

朝の散歩を始めた

運動不足という不安をずっと抱えつつも何も習慣化できてない状態が続いていたのだが、最近は朝のうちに30分ぐらい家の周りを散歩するようにしている。せめてこれぐらいは。。。という。
で、散歩中に何かすることないかな→英語のリスニング勉強にすれば一石二鳥では!ということで英語もスタートした、みたいなところもある。

📝ブログ・登壇

ブログは4件、イベント登壇が1件でした。

ブログ

イベント登壇

登壇資料

💬 所感

仕事面では、8月からはじまった四半期の切れ目ということで慌ただしかったものの一つの節目を迎えられた。今QはCREとしての業務がメインで、やることかなり絞ってフォーカスできたのはよかったと思う。

また、プライベート面では久しぶりに勉強会に登壇してLTしたというのが大きな出来事だった。LTの後のパネルディスカッションがメインコンテンツだったので、非常に考えさせられる質問をいただきながらもモデレーターや他の登壇者の方とわいわい話せたのはすごく楽しめた。

なんとか週内に感想をブログにできるといいな。

💪11月のテーマ

伸ばしたいことリストに動きがなかったので据え置きです!あと、11月から大学も新学期が開始するはずなのでしばらくはそちらで忙しくなりそう。

💸 買ったもの

子供の分も含めてパンを食べると食費もバカにならないなーと思って自家製パンをやってみることにした。まだ2回ぐらいしか稼働してないけどできたて美味い。

Total TypeScriptのZodチュートリアルでZodに入門した

はじめに

Zod というバリデーションライブラリが非常に流行っているようなので、素振りした。

www.totaltypescript.com

このチュートリアルはたしか Twitter で流れてきて知ったのだが
今見ると Zod の公式ドキュメントからも Resources として紹介されているので、そこそこ信頼していいコンテンツなのだと判断した。

チュートリアルについて

チュートリアルと名がついているが、内容は全 10 問のエクササイズを解くという構成。

あらかじめ型チェックのエラーまたはランタイムのエラーが発生するサンプルコードが問題として用意されており、そのコードを修正しながら Zod の基本的な使い方を学ぶ。 チュートリアルには Zod の使い方の説明は特にないので、チュートリアルの問題を解くために Zod の公式ドキュメントを読んで必要な箇所を理解する、という感じ。

Rust でいう rustlings に似てるなと思った。

Web エディタでも解けるし、 https://github.com/total-typescript/zod-tutorial にもコードが公開されており、git clone して手元で動かしながら問題を解くこともできる。
また、全 10 問といったがリポジトリには隠しステージっぽく 11〜14 問目まである。

各問で学べるのは(自分の理解では)以下。

  1. Runtime Type Checking with Zod
    • 基本。プリミティブな値 (number) に対するスキーマ定義および parse メソッドæ
  2. Verify Unknown APIs with an Object Schema
    • 基本。z.object({ … }) でオブジェクトのスキーマを定義する
    • parse 後はスキーマに定義したkeyのみが残る
  3. Create an Array of Custom Types
    • z.array による配列の定義方法
  4. Extract a Type from a Passer Object
    • z.infer<typeof スキーマ>スキーマから型の取り出し
  5. Make Schemas Optional
  6. Set a Default Value with Zod
  7. Be Specific with Allowed Types
  8. Complex Schema Validation
    • https://zod.dev/?id=strings
    • string は文字列長の min/max だけでなく、 emailurl の形式を強制する便利なメソッドがある
  9. Reduce Duplicated Code by Composing Schemas
    • .extend を利用したオブジェクトの拡張と、 .merge を使ったオブジェクトのマージ
  10. Transform Data from Within a Schema
    • .transform を使うとパース後のデータの変換ができる

終わった後に公式ドキュメントをざっと眺めて、たしかに主要なところはカバーしてるのかなと思った。

学び:Zod の基本

ここからはチュートリアルプラス公式ドキュメントも読んで学んだことをメモ。

Zod の特徴

Introduction に挙げられてるのは以下。

  • Zero dependencies
  • Node.js やすべてのモダンブラウザで動く
  • 小さい:minified + zipped で 8kb
  • イミュータブル
  • 簡潔でチェイン可能なインターフェース
  • 関数型アプローチ: parse, don’t validate (←これリンク先の記事まで見てないのでわからなかった)
  • プレーンなJSでも動く

基本的な使い方

const stringSchema = z.string() のようにプリミティブなスキーマも定義できるが、実際使うとなると多くがオブジェクト形式だと思うのでオブジェクトのスキーマ例を載せる。

import { z } from "zod";

const User = z.object({
  username: z.string(),
});

User.parse({ username: "Ludwig" });

// extract the inferred type
type User = z.infer<typeof User>;
// { username: string }

(コードは Basic usage より引用)

その他、 .shape でオブジェクトの特定のkeyのスキーマを取得できたり、

User.shape.name; // => string schema

.merge .pick .omit partial など TypeScript の型操作的な API は一通り提供されている。

.refine:カスタムバリデーション

独自のバリデーションロジックを実装したい場合は .refine メソッドを使う。

const myString = z.string().refine((val) => val.length <= 255, {
  message: "String can't be more than 255 characters",
});

(コードは公式ドキュメントより引用)

.transform:パースした値の変換

定義したスキーマに続けて .transform というメソッドを呼び出すと、パースした値を変換できる。

const StarWarsPerson = z
  .object({
    name: z.string(),
  })
  .transform((person) => ({
    name: person.name,
    nameAsArray: person.name.split(" "),
  }));


const person = {
  name: "Luke Skywalker",
};
const parsed = StarWarsPerson.parse(person);
console.log(parsed);
// { name: 'Luke Skywalker', nameAsArray: [ 'Luke', 'Skywalker' ] }

Yup との違いは?

現職ではフォームのバリデーションに Yup を使っているので、違いが気になる。
最初、スキーマ定義から型を推論できるのは Zod すごいなって思ったけどそれは Yup でもできるらしい(InferType)。知らなかった。。。

というわけでほとんど違いがわからずにいたが、公式ドキュメントの Comparison > Yup で比較されていた。何点か違いが列挙されているが、

  • Yup はオブジェクトのすべてのフィールドがデフォルトで optional(Zod は required が基本)
  • partial や deepPartial などのメソッドがない
  • promise スキーマがない
  • function スキーマがない
  • union や intersection スキーマがない

というわけで、スキーマの充実度では Zod に分があるよという主張のよう。

また、 Yup の方が型推論がいまいちだ、という比較記事も見かけた。
参考:Reactで使えるバリデーションライブラリを紹介! - bagelee(ベーグリー)

参考リンク

Vercel OG(@vercel/og)でOG画像を動的生成する

こちらの記事を読んで。

以前から https://reading-list.zaki-yama.dev/ という自分のサイトに OG 画像を設定したいな〜と思っていたところに @vercel/og なるライブラリが登場したので試してみた。

※ なお、今までずっと「OGP 画像」だと思ってたんだけど、記事中では OG image と表記されていたので、ここでも「OG 画像」と表記する。

@vercel/og の特徴

冒頭の記事を読む限り、今までは vercel/og-image というサービスが提供されていたが、これには以下のような問題があった。

  • 難しい: Serverless Function 内で Chromium を起動し、 Puppeteer でスクリーンショットを撮る、ということをやっていた。これらのツールのセットアップは実装が難しくしばしばエラーを引き起こしていた
  • 遅い:Chromium を Serverless Function 内で起動するため圧縮し、コールドブート中に解凍される必要があるため、遅い(平均4秒)。結果、ソーシャルカードの生成が遅くなったり壊れたりした

今回発表された @vercel/og はこれらの問題を解決したもので、具体的には以下の特徴がある。

  • 簡単 (Easy):ヘッドレスブラウザ不要。HTML と CSS から OG 画像を生成できる
  • 高速 (Fast): vercel.com/docs で試した結果 vercel/og-image より 5倍程度速かったとのこと

加えて @vercel/og を利用したコードは Next.js アプリケーションと共存でき、 vercel/og-image のように別のところにデプロイする必要がない というのもうれしい。

@vercel/og が使える条件

https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation#requirements を読む限り

  • Next.js のバージョンが v12.2.3 以降
  • runtime: 'experimental-edge' を有効にして Edge Runtime を使用する

を満たす必要がある。後者はデプロイ先が Vercel であれば問題にならないが、他だとどうなんだろ。やったことないのでわからない。

試してみる

というわけで自分で運用している Next.js アプリケーションの https://reading-list.zaki-yama.dev に @vercel/og を導入してみる。

ソースコードhttps://github.com/zaki-yama/reading-list

公式ドキュメントとしては以下を読めばよさそう。

簡単な OG 画像を表示する

まずは、ライブラリを導入して静的な OG 画像を表示する。
インストールは以下のコマンドで行う。

$ npm i @vercel/og

続いて、OG 画像生成用の API エンドポイントを用意する。
/pages/api/og.tsx というファイルを作る。

// /pages/api/og.tsx

import { ImageResponse } from '@vercel/og';

export const config = {
  runtime: 'experimental-edge',
};

export default function () {
  return new ImageResponse(
    (
      <div
        style={{
          fontSize: 128,
          background: 'white',
          width: '100%',
          height: '100%',
          display: 'flex',
          textAlign: 'center',
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        Hello world!
      </div>
    ),
    {
      width: 1200,
      height: 600,
    },
  );
}

(コードは https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation#getting-started を引用)

これで npm run dev して http://localhost:3000/api/og にアクセスすると Hello world! という画像が表示される。

最後に、これが OG 画像として表示されるようにする。それには <head> に以下のように meta タグを埋め込めばよい。
(自分は Layout コンポーネント内に定義した)

<meta
  property="og:image"
  content="https://reading-list.zaki-yama.dev/api/og"
/>

テキストを動的に設定する

基本的な使い方がわかったので、次は画像内のテキストを動的に設定してみる。
具体的には、現在開いているページのタイトルを OG 画像に埋め込むようにしたい。

OG Image Examples > Dynamic text generated as image にちゃんとサンプルが用意してある。

まず、 /pages/api/og.tsx 側は以下のように、クエリパラメータでタイトルを受け取るようにする。

// /pages/api/og.tsx

import { ImageResponse } from '@vercel/og';
import { NextRequest } from 'next/server';

export const config = {
  runtime: 'experimental-edge',
};

export default function handler(req: NextRequest) {
  try {
    const { searchParams } = new URL(req.url);

    // ?title=<title>
    const hasTitle = searchParams.has('title');
    const title = hasTitle
      ? searchParams.get('title')?.slice(0, 100)
      : 'My default title';

    return new ImageResponse(
      (
        <div>
            // ...略...
            {title}
        </div>
      ),
      {
        width: 1200,
        height: 630,
      },
    );
  } catch (e: any) {
    console.log(`${e.message}`);
    return new Response(`Failed to generate the image`, {
      status: 500,
    });
  }
}

(コードは https://vercel.com/docs/concepts/functions/edge-functions/og-image-examples#dynamic-text-generated-as-image から抜粋)

そして、使う側は

<meta
  property="og:image"
  content="https://reading-list.zaki-yama.dev/api/og?title=${postData.title}"
/>

というようにクエリパラメータをページごとに変えて設定してやる。

1点サンプルには載ってなかったこととして、自分は以下のように URLSearchParams をかませるようにした。

// /pages/posts/[id].tsx
export default function Post({
  postData,
}: {
  postData: {
    title: string;
    date: string;
    contentHtml: string;
  };
}) {
  const title = `${siteTitle} ${postData.title}`;
  const searchParams = new URLSearchParams(`title=${title}`);
  return (
    <Layout>
      <Head>
        <title>{title}</title>
        <meta
          property="og:image"
          content={`https://reading-list.zaki-yama.dev/api/og?${searchParams.toString()}`}
          key="og-image"
        />
        <meta property="og:title" content={postData.title} key="og-title" />
      </Head>
      ...

https://github.com/zaki-yama/reading-list/blob/main/pages/posts/%5Bid%5D.tsx#L17-L27

おそらくサイトや記事のタイトルに ' (スペース)が含まれていたせいで Open Graph Debugger で見たときにうまく表示されなかったため、これらの文字は URL エンコードするようにした。

結果

https://reading-list.zaki-yama.dev/posts/2022-09-13 という URL を Twitter や Slack に貼ったときに OG 画像が表示されるようになった。

デザイン性皆無なのはしょうがないが、一旦満足。