🥰

彼氏がかわいすぎる.com

2024/12/18に公開

この記事はクソアプリ Advent Calendar 2024の18日目の記事です。

はじめに

はじめまして!もひこ(@andmohiko)と申します。
個人開発がすきなエンジニアです。

作ったもの

今回は「彼氏がかわいすぎる人が彼氏のページを作れるアプリ」を作りました。

https://www.彼氏がかわいすぎる.com/

↓RTお願いします🙏

https://x.com/andmohiko/status/1869317003208790259

彼氏がかわいすぎる.comです。サービス名がそのままドメインにもなっています。

コードはこちらのリポジトリですべて公開しています。
https://github.com/andmohiko/kareshi-kawaisugiru

モチベーション

Xのbioに日本語のURLを設定できると知り、かわいいドメインを設定したくなったので作りました。

実際に設定してみるとこのような見え方になります。かわいい!

アプリの使い方

筆者は平成のBLオタクなので今でも彼氏はリボーンの雲雀恭弥です。今回は雲雀さんの画像を例にアプリの使い方を説明していきます。

彼氏の画像・名前を入力する

まずは彼氏のID・横向きの写真・縦向きの写真・普段呼んでいる名前などを入力します。

保存すると彼氏のページが作成されます。
このとき、API側でCanvasを使ってOGP画像を生成しているため、保存に時間がかかります。保存を待っている間はローディングアニメーションが表示されます。

彼氏のページを開く

作成した彼氏のページを開くと設定した彼氏の画像が画面いっぱいに表示されます。あらゆる画面サイズで常に彼氏を最大値で見たいため、画面幅によって表示される画像が切り替わります。

画面幅が狭いとき

画面幅が広いとき

SNSでシェアする

かわいい彼氏はもちろんSNSで自慢したいため、彼氏のページをSNSでシェアすると、彼氏がOGP画像として展開されます。ポストの本文には日本語ドメインがそのまま表示されます。OGP画像の右下にアプリのロゴが入っているのも地味におしゃれポイントです。

使った技術

Next.js+Vercel+Firebaseの組み合わせで作りました。

Next.js

筆者が使い慣れているのでReactのフレームワークを使いたかったのですが、OGP画像の設定しやすさを重視して今回はNext.jsを選びました。

Vercel

Next.jsのデプロイがしやすいので使用しました。VercelのEdge Functionsは使用していません。

Firebase

認証にはFirebase Authentication、データベースにはFirestore、サーバーサイドの処理にはCloud Functions for Firebase、オブジェクトストレージにはCloud Storage for Firebaseを使用しています。

その他

OGP画像はCanvasで生成しています。
ブラウザであればCanvasを利用できますが、Node.jsではそのようなAPIは生えていないため、node-canvasを使用することが多いでしょう。しかし、node-canvasはネイティブモジュールに依存しており、Cloud Functions上では少し開発しづらさがあります。
そこで、ネイティブモジュールに依存しておらず、同じくWeb Canvas API互換なAPIを実装した@napi-rs/canvasというライブラリを使用しました。
https://www.npmjs.com/package/@napi-rs/canvas

また、画像のリサイズにはsharpを使用しています。
https://www.npmjs.com/package/sharp

実装で工夫したところ

OGP情報の設定

NextSeoを使用してOGP情報を設定しています。
https://www.npmjs.com/package/next-seo

propsを渡していく形でOGPの設定を記述できることがわかりやすいです。

<NextSeo
  title={title}
  description={description}
  nofollow={false}
  canonical={process.env.NEXT_PUBLIC_APP_URL}
  openGraph={{
    title,
    description,
    url: kareshiUrl,
    type: 'website',
    images: [
      {
        url: ogpImageUrl,
        width: 800,
        height: 600,
        alt: '',
      },
    ],
  }}
  twitter={{
    cardType: 'summary_large_image',
  }}
/>

ここで、Firestoreから取得する情報をどうやってSSR時に渡すかという課題があります。
Firestoreは本来client側で動作するため、ページにリクエストが届いた時点ではデータを取得できません。
そこで、Next.js API Routesを使用し、サーバーサイドであらかじめデータをフェッチできるエンドポイントを生やしました。getStaticProps内でこのAPIを叩くことでページにリクエストが来た時点で必要な情報を取得できるようにしました。
具体的な実装はこちらから見ることができます。

画像のクロップ

具体的な実装は過去のエントリで解説しています。今年の自分のアウトプットを年末に使うのは1年間の集大成感があって楽しかったです。
https://zenn.dev/andmohiko/articles/d70d9264a6fbf7

Canvasを使用したOGP画像の生成

Canvasを使った開発はposition absolute芸に似たものがあり、わりとつらいです。
今回は

  1. Figmaでデザイン作成
  2. CSSでエクスポート
  3. ChatGPTでcanvasのコードに変換
    という流れで作業するとCanvasと向き合うつらさがかなり軽減できるということが発見でした。

今回のOGP画像の生成では

  • 彼氏の画像をOGP画像のサイズにリサイズする
  • テキストを表示する領域の背景に暗めのグラデーションを引く
  • 左下に彼氏の名前を配置する
  • 右下にロゴを配置する
    という操作を行なっております。

詳しい実装はこちらで公開しています。
https://github.com/andmohiko/kareshi-kawaisugiru/blob/main/functions/src/useCases/generateOgpImage.ts

ここまで読んでくれた方へ

以上、彼氏がかわいすぎる.comを作った話でした。

ここまで読んでくださりありがとうございます。

よかったらツイッター(@andmohiko)フォローしてください。

さいごに

明日はtomorrowです。

Discussion