※この記事は、Claude Codeで1人開発しているSNS運用SaaS「ThreadPost」の開発日記です。
SNS運用を自動化しませんか?
ThreadPostなら、投稿作成・画像生成・スケジュール管理まで全てAIにお任せ。
PWA対応はなぜ地獄なのか
Webアプリをスマホアプリのように使えるPWA化は、本来なら数日で終わる作業だ。しかし、僕の環境では総コミット32件を費やす泥沼と化した。原因はNext.jsのApp Routerと古いPWAライブラリの相性、そしてSafariのUI仕様変更だ。結論として、既存のライブラリに頼らず、ブラウザごとの挙動を泥臭く吸収する実装が必要だった。

楽観的すぎたService Worker導入
PWA対応はライブラリを入れてmanifest.jsonを置くだけだと思っていた。まずは定番の「next-pwa」を導入した。Claude Codeに任せれば数分で終わるはずだった。ブラウザのコンソールを開くと、赤いエラーメッセージが画面を埋め尽くしていた。
Service Workerの登録に失敗している。「next-pwa」は開発が止まっており、最新のReactエコシステムとは相性が悪い。設定を削れば削るほど機能も失われる。僕は「next-pwa」を削除した。ライブラリを消すことでエラーを直す。見事な解決策だ。
しんたろー:
12回コミットして元の状態に戻った。Claudeの提案を鵜呑みにした僕の負け。ライブラリの最終更新日を確認しないと数時間をドブに捨てる。
気を取り直して、モダンな後継ライブラリ「Serwist」に乗り換えた。今度は一発で動いた。Service Workerが正常に登録され、インストールバナーが表示された。しかし、UIの崩壊が待っていた。PWAのstandaloneモードでは、Z-indexの基準が親要素に依存する。ダイアログが画面の裏側に潜り込んだ。
「Apply Portal to all dialogs for PWA compatibility」を実行した。ReactのPortalを使って、すべてのダイアログをDOMの最上位にレンダリングする。これでZ-indexの呪縛から解放された。PWA対応は、UIアーキテクチャの全面改修を要求してくる。
しんたろー:
Z-indexを9999にすれば直ると思ってた。PWAのstandaloneモードはCSSの常識が通用しない。Portal化で5つのダイアログを全部書き直した。
Safariの気まぐれとUI崩壊
iOS SafariはPWAのインストール手順が異常に分かりにくい。ツールバーの共有ボタンを押してホーム画面に追加するよう案内する必要がある。画面下部の中央に矢印を出し、「ここを押してね」と表示した。実機で確認すると、矢印が何もない空間を指している。
Safariのバージョンによって共有ボタンの位置が違うのだ。中央にある人もいれば、右下のメニューの中にある人もいる。僕は中央と右下、両方のパターンを並列で説明する狂気のUIを実装した。absolute positioningで、ピクセル単位で矢印の位置を固定する。泥臭いハードコーディングだ。環境依存を排除するにはこれしか方法がなかった。
しんたろー:
SafariのUI変更のたびに僕のコードが壊れる。Appleの気まぐれに付き合わされるWeb開発者の末路。矢印の座標調整だけで2時間消えた。
ここまで読んだあなたに
今なら無料で全機能をお試しいただけます。設定後は完全放置でプロ品質の投稿を毎日生成。
落とし穴
PWAのインストールバナーを全画面に出そうとした。ユーザーの目につくところに置けばインストール率が上がると信じていた。しかし、LINEやInstagramのアプリ内ブラウザはPWAのインストール機能を持たない。ユーザーを「絶対にインストールできない場所」へ誘導する無意味なバナーを量産した。インストールボタンは、OS標準のブラウザで開いている時だけ表示する条件分岐が必須だ。
今日の数字
- 総コミット数: 32件
- 新機能: 1件
- バグ修正: 2件
- 開発期間: 3ヶ月(本来は1日の予定)
- 企業なら数週間かかる作業を、僕は3ヶ月の試行錯誤で強行突破した。
FAQ
Q1: なぜ「next-pwa」から「Serwist」へ移行したのか。
A: 「next-pwa」はApp Router環境で致命的なビルドエラーを吐くからだ。メンテナンスが停止しており、最新のNext.jsと共存できない。Serwistは型安全性が高く、App Routerにも完全対応している。
Q2: PWAのインストールバナーが出ない原因は何か。
A: manifest.jsonの記述ミスか、HTTPS環境の不備がほとんどだ。特にアイコンのサイズ指定が一つでも欠けるとブラウザは無視する。検証にはChromeのDevToolsにあるApplicationタブが一番早い。
Q3: なぜPortalを使ってダイアログを修正したのか。
A: PWAのstandaloneモードでは、CSSのスタッキングコンテキストが親要素の影響を強く受けるからだ。通常のブラウザでは問題ないZ-indexも、PWAでは親要素のoverflow設定で遮断される。PortalでDOMの最上位に逃がすのが唯一の解決策だ。
ThreadPostは今日も進化した。PWA対応でスマホアプリのような操作性を手に入れた。詳細はThreadPostで確認してほしい。

この記事が参考になったら、ThreadPostを試してみませんか?
投稿作成・画像生成・スケジュール管理まで、全てAIにお任せできます。
ThreadPostをもっと知る