Skip to content

feat: PWA更新検知時のoverlay+自動reloadをmypace方式で実装#52

Merged
kako-jun merged 8 commits into
mainfrom
51-pwa-update-reload
Jul 14, 2026
Merged

feat: PWA更新検知時のoverlay+自動reloadをmypace方式で実装#52
kako-jun merged 8 commits into
mainfrom
51-pwa-update-reload

Conversation

@kako-jun

Copy link
Copy Markdown
Owner

関連 Issue

Refs #51(実機/build previewでの動作確認が完了するまでopenのまま)

変更内容

  • public/sw.jsskipWaiting をmessage駆動に変更(初回インストールは従来通り自動、更新時のみクライアント承認を待つ)
  • lib/appBusy.ts(新規)で作業中(撮影後の調整・比較・書き出し等)はreloadをdeferするゲートを追加
  • components/ServiceWorkerRegister.tsx を overlay→postMessage→controllerchange reload→fallback→cooldown のフローに書き換え
  • /en ルートでoverlay文言が正しく英語になるよう ServiceWorkerRegister の配置を修正
  • QAレビュー指摘を反映: applyUpdate 多重発火防止フラグを追加
  • テスト13件追加(既存24件+新規13件、37件全通過)

既知のギャップ

  • vitest.config.tsenvironment: 'node' 限定("Pure-logic helpers only")のため、ServiceWorkerRegister.tsx / ImageProcessor.tsx 本体(今回のQA修正=多重発火防止フラグを含む)はunitテスト化できていません。純粋ロジック(appBusy.ts, sw.js)はカバー済み
  • 実ブラウザでのoverlay→SW切替→reloadの一連の流れは未検証(CLAUDE.mdルール1により実機確認が必要)

kako-jun added 6 commits July 14, 2026 18:08
install時の無条件self.skipWaiting()を廃止し、SKIP_WAITINGメッセージ受信時のみ
skipWaitingするよう変更。既存タブが古いSWに制御されている「更新」ケースでのみ
影響し、初回インストールは制御元が無いため従来どおり即activateされる。
クライアント側が作業中でないか確認してから明示的に切り替えを許可できるようにする。
角調整・比較・GIF/動画生成・保存など、ImageProcessorのphaseがuploadでない間は
未保存の作業がある。lib/appBusy.tsのグローバルbusyフラグをImageProcessorが
更新し、SW更新ハンドラ側でwaitUntilIdle()により作業完了までreloadを遅延できる
ようにする。
ServiceWorkerRegisterでupdatefound→新workerのstatechangeで更新を検知し、
overlay表示→postMessage(SKIP_WAITING)→controllerchange待ちreload
(fallback 2秒)→sessionStorage cooldown(10秒)というmypaceと同等の流れを
実装。overlay文言はlib/i18n.tsxにpwaUpdateRestarting(ja/en)として追加。
useI18n()で言語判定するためServiceWorkerRegisterを両layout.tsxの
I18nProvider内に移動(/enの言語判定に必要)。
updatefound/statechangeが短時間に複数回発火すると、cooldownのsessionStorage
書き込みがwaitUntilIdle()のawait後にあるため、複数のapplyUpdate呼び出しが
cooldownチェックを素通りしてidle待機中に並走し得た。overlay二重生成・
SKIP_WAITING二重postMessage・controllerchangeリスナー二重登録・reloadタイマー
二重セットにつながる。

モジュールレベルのapplyingフラグを追加し、関数先頭で多重実行を防止。
cooldownチェック通過後にフラグを立て、reload成功パスでは戻さない
(reloadでモジュール状態ごと消える)が、cancelledによる中断パスでは
確実にリセットする。
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 14, 2026

Copy link
Copy Markdown

Deploying machigai-salad with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4f842e5
Status: ✅  Deploy successful!
Preview URL: https://c4b648f7.machigai-salad.pages.dev
Branch Preview URL: https://51-pwa-update-reload.machigai-salad.pages.dev

View logs

kako-jun added 2 commits July 14, 2026 21:26
独立レビュアーのmust指摘2件に対応(姉妹リポorberの同種修正を参考)。

must 1: mount時に既にwaiting/installingの新SWがある場合を検知できない
updatefoundは新規installingの開始時にのみ発火し、既にinstall完了して
waitingにいる、またはinstalling中のworkerには再発火しない。ブラウザは
ナビゲーション時に自前でSW更新チェックを行うため、React hydration→
useEffect実行より前にこの更新チェックが完了しているケースは通常の
デプロイ後リロードで十分起こり得、その場合更新が握りつぶされていた。
→ mount時にregistration.waiting/installingの両方を確認するように変更。

must 2: overlay表示〜reloadの間、再開した作業をチェックする手段が無い
「overlayが操作をブロックするから再チェック不要」という設計判断を撤回。
overlayはpointer操作は塞ぐがfocus/keyboard入力や既に走っている非同期
処理までは止めないため、pre-delay(1.5秒)+fallback(2秒)の間にbusy状態へ
戻り得る。
→ postMessage送信直前・controllerchangeハンドラ内・fallbackタイマー内で
isAppBusy()を再チェックし、busyならidle復帰を待って自動的に続行する
makeIdleGatedOnce()を導入。

テスト容易性のため、この2件の判定ロジックをServiceWorkerRegister.tsx
('use client'のDOM依存コンポーネント)からlib/swUpdateDetection.tsへ
純粋関数として切り出し(vitest.config.tsがnode環境・*.test.ts限定なため、
DOM/Reactコンポーネントは直接テストできない制約に対応)。
lib/swUpdateDetection.test.tsで両must項目の回帰テストを追加。
独立レビュアーの追加must指摘に対応。

ServiceWorkerRegisterの登録用useEffectが[t](useI18n()のcallback、
langが変わるたびに再生成される)に依存していた。/ をブラウザ言語が
日本語以外の訪問者が開くと、auto-detectでlangが'ja'→'en'に切り替わり
tの参照が変わってeffectが再実行される。cleanupはcancelled=trueを
セットするだけでregistration.removeEventListener('updatefound', ...)を
呼ばないため、同じregistrationに2つのupdatefoundリスナーが残る。
実update時に両方が同期的に発火し、モジュールレベルのapplyingフラグの
奪い合いにより、cancelled側が先にapplyingを取ってしまうケースで
どちらの経路も更新を完走させず、更新がサイレントにドロップされる
(前回must1/2で追加した機構を無効化する回帰)。

→ 登録・リスナー設定用のeffectをtに依存させず一度だけ実行するよう
修正。overlay文言用のtはuseRefで最新値を保持して参照する形に変更。

ServiceWorkerRegister.test.tsを追加。TypeScriptコンパイラAPIで
ソースを解析し、登録effectの依存配列が空であることと、tRef.current
経由で翻訳関数を参照していることを構造的に検証する回帰テスト
(DOM/RTL環境が無いため、コンポーネントの直接レンダリングではなく
ソース形状の静的検証)。修正前のコードに対して実行し、実際に
テストが失敗することを確認済み。

docs/architecture.mdのPWA更新方針節とdocs/changelog.mdを、mount時
検知・busyの3箇所再チェック・lib/swUpdateDetection.tsへの切り出し・
今回のeffect依存修正に追従させた。
@kako-jun
kako-jun merged commit cb95864 into main Jul 14, 2026
2 checks passed
@kako-jun
kako-jun deleted the 51-pwa-update-reload branch July 14, 2026 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant