1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【個人開発】Next.js 15 の進化(という名の罠)にボコボコにされたけど、最高にエモい SNS シェア機能を実装した話 🥗

1
Posted at

はじめに

こんにちは!万年ダイエッターの Wakuqqa(ワクッカ) です。✌️
人生初の個人開発プロジェクトとして「LogEats(ログイーツ)」という AI 食事管理アプリを作っています!
右も左もわからない中、皆さんに使っていただけていて、私のモチベーションも爆上がりしております!🐨✨

(最近 𝕏 (@wakuqqa) でも、開発の裏側をつぶやき始めました!公式アカウント (@EatsLog88161) と合わせて、ぜひフォローしてやってください!🙏)

実は最近、LogEats の公式アカウントを運用するために 𝕏 を始めたばかりなのですが、始めてすぐに気がつきました。

「自分のダイエット成果をアップしようとするたびに、スクショを撮って、数値を手入力して、ハッシュタグを考えて…」ってやるのが、正直めちゃくちゃ面倒だということに!!(個人開発デビューしたての私には、アプリを動かすだけで手一杯なんや…!)

「この手間、ボタン一つにできたら自分も嬉しいし、ユーザーさんも楽しくシェアしてくれて、結果的にアプリをもっとたくさんの人に知ってもらえるんじゃね!?」という、初心者の不便さから生まれた(下心混じりの)純粋な思いつきから今回の開発がスタートしました。

今回は、そんな個人的な「めんどくさい」を解消するために SNS シェア機能を爆速強化したのですが、その裏で Next.js 15 の仕様 に完膚なきまでに叩きのめされた失敗談をお届けします。

もし「ローカル(自分のPC)では動いてるのに、デプロイした途端ビルドが通らなくて泣きそう…!」と震えている方がいたら、この記事を読んで勇気(と解決策)を受け取ってください!🚀


🛠 今回のアップデート内容(やりたかったこと)

「今日何食べたか、もっとオシャレに 𝕏 で自慢したい!」というバイブスに応えるべく、以下の機能を実装しました。

  1. 𝕏 (Twitter) 専用シェアボタン: ワンタップで、その食事のカロリーやマクロバランスが要約されたツイートを作成。
  2. 動的 OGP 画像生成: 共有された URL を貼ると、AI が解析した「本日の成果」が画像としてプレビューされます。
  3. 1日のまとめレポート: 単発の食事だけでなく、一日の合計摂取量と目標達成度を可視化したページを生成。
  4. 短縮 URL 対応: 𝕏 の文字制限に優しい、スッキリした /s/xxxx 形式のリダイレクト。

バックエンドも daily_shares テーブルを整備して、「あとはデプロイするだけ!完璧!」と確信していました。


絶望の第1ラウンド:params は Promise になったらしい

意気揚々と git push して Vercel のビルドを見守っていた私に、Next.js からの非情な宣告が届きます。

Type error: Route "src/app/s/[shortId]/route.ts" has an invalid "GET" export:
  Type "{ params: { shortId: string; }; }" is not a valid type for the function's second argument.

「え、昨日まで動いてたじゃん!?!?(絶望)」
image.png

調べてみると、Next.js 15 から paramssearchParams は、同期的ではなく「 Promise 」として扱うのがシン・お作法になったとのこと。

// ❌ 修正前(Next.js 14 までのバイブス)
export async function GET(request: Request, { params }: { params: { shortId: string } }) {
  const shortId = params.shortId;
  // ...
}

// ✅ 修正後(Next.js 15 のシン・お作法)
export async function GET(request: Request, { params }: { params: Promise<{ shortId: string }> }) {
  const { shortId } = await params; // ここで await が必要!
  // ...
}

「なるほどね、最新の進化に追いついていかなきゃね!」と大人な対応で修正。再度プッシュ!


追跡の第2ラウンド:TypeScript の厳しすぎる愛

「今度こそ通るはず…」とコーヒーを飲んでいたら、またしても赤いログが。

Type error: 'error' is of type 'unknown'.
22 | return NextResponse.json({ error: error.message }, { status: 500 });
                                       ^

今度は、デバッグ用に作っておいたチェック用 API の catch ブロックで怒られました。
Next.js 15(というか最近の TS 構成)だと、catch(error)error はデフォルトで unknown 型。error.message にアクセスするには、ちゃんと型ガードしてあげないといけません。

「もう!デバッグ用のファイルなんだからいいじゃんにゃー!」と叫びながら、そもそも本番には不要なファイルだったので、ディレクトリごと削除してやりました。これが一番のバイブス向上施策です。🗑️


復活の第3ラウンド:OGP 生成も非同期の海へ

これで終わりかと思いきや、動的 OGP 画像を生成している opengraph-image.tsx たちも、同じく paramsawait するように修正が必要でした。

  1. src/app/share/[id]/opengraph-image.tsx
  2. src/app/share/daily/[id]/opengraph-image.tsx

これらを全部直して、ようやく…ようやく 「Build Successful」 の文字が!!😭🙌


🎨 できあがった最高のシェア画像は是非Xでチェックしてね

Vercel Postgres からエッジでデータを取得して、next/og で生成した「デイリーレポート」は「背景に実際の食事写真を置き、その上に目標達成率のプログレスバーを重ねる」という、個人開発ならではのこだわりを詰め込みました。

  • ワクッカ個人の X: @wakuqqa (開発者の日常とダイエット)

さいごに

Next.js 15 へのアップデートを含めた機能をデプロイする時は、以下の 3 点を心に刻みましょう。

  • paramsawait せよ!(型定義も Promise に!)
  • TypeScript のエラー型は unknown だと思え!
  • 不要なデバッグファイルは即消去!

紆余曲折ありましたが、無事に超オシャレな SNS シェア機能がリリースされました!✌️
皆さんもぜひ、LogEats で自分の食事記録をシェアして「バイブス高めなダイエット生活」を楽しんでください!

参考になったら「LGTM」やフォローをいただけると、クオッカのような笑顔になります!🐨✨

また、最近始めたばかりの𝕏でも、開発の裏側やダイエットの進捗をつぶやいています。ぜひフォローして仲良くしてください!

  • ワクッカ個人の X: @wakuqqa (開発者の日常)
  • LogEats 公式 X: @EatsLog88161 (最新アプデ情報)

LogEats を使ってみる!
logeatsname_sml.jpeg

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?