Chrome拡張でコンポーネント間の値の共有と一時的な状態保持のためにSessionStorage
を使ったところ、意図せずバグを仕込んでしまった体験と、その解決策を紹介します。
背景:なぜSessionStorageを使ったのか?
Chrome拡張では、window.sessionStorage などの ブラウザが提供するStorage API に加えて、chrome.storage.local や chrome.storage.session といった 拡張機能専用のストレージ も利用できます。
それぞれ使える場所やスコープが異なるため、用途に応じた使い分けが重要です
今回は、下記の理由で使いたくない場面がありました。
ストレージ | 問題点 |
---|---|
chrome.storage.local |
全タブで共有されてしまい、ページごとに独立して保持したい状態には不向き |
chrome.storage.session |
Manifest V3かつServiceWorker限定。backgroundからしか使えず、content scriptからの直接操作不可 |
そのため、ページ単位で状態が保持され、タブごとに独立して使えるSessionStorage
をcontent scriptで採用しました。
問題
うまく行ったと思ったのですが、結合テストをするとき何回かに1回、意図しないデータ参照が発生していることに気が付きました。
APIのリクエストパラメータがひとつ遷移する前ページの内容を引き継いでいることに
問題の詳細
対象のWebサイトは以下のような構成:
商品Aのページ
https://example.com/item?id=ti-kawa
商品Bのページ
https://example.com/item?id=hachiware
このようにクエリパラメータでコンテンツ(商品ページ)が切り替わる設計です。
ところが SessionStorage
は「オリジン単位+タブ単位」でデータを保持するため、別の商品ページでも同じSessionStorageが共有されてしまうのです。
Amazon.co.jpの例
起きた不具合
前のページで保存された状態が、新しいページでそのまま参照されてしまい、整合性のないAPIリクエストが飛んでしまうという事態に。
なぜこうなるのか?SessionStorageの特性
sessionStorage
は「タブごとに1つのストレージ空間」を持ちます
URLが異なっても、オリジンが同じなら共有される(クエリパラメータやパスは区別されない)仕様になっております。
つまり「別商品」であっても「同一sessionStorage」として扱われてしまうため、エラーが起こっていました。
解決策:URLをキーに含めることで分離管理
対策1:URL別にキーを分ける
const key = `page-state:${location.pathname}?${location.search}`;
sessionStorage.setItem(key, JSON.stringify(state));
- クエリやパス込みでキーを構成すれば、商品ごとに独立した保存が可能に
- 読み取りも同様に現在のURLに応じて参照
const currentKey = `page-state:${location.pathname}?${location.search}`;
const saved = sessionStorage.getItem(currentKey);
対策2:初期データは毎回APIから取得する
SessionStorageに依存しすぎず、ページ遷移時は毎回データ取得する設計に変更。
SessionStorageは「中間入力の保持」や「直近のUI状態保存」などに用途を限定。
その他の補足
sessionStorageの代替:chrome.storageは?
ユーザーのログイン状態など、拡張全体で一貫した状態管理をしたい場合には、chrome.storage.local
を使うのが適しています。
ただしこれは全タブで共有されるため、今回のように 「ページ単位で切り離したい一時的な状態」 を扱うには工夫が必要です。
また、拡張機能専用の chrome.storage.session
もありますが、ServiceWorker(background)限定でしか使えず、popup や content script からはアクセスできません。
そのため、ユーザーの目に見える画面単位でのセッション状態を管理したい場合、window.sessionStorage
(DOM API)を使わざるを得ないケースも残ります。
まとめ
-
sessionStorage
は便利だが、URL単位では分離されないことに注意 - 特に「クエリパラメータでページを識別している」サイトでは注意が必要
- 対策としては、URLをキーに含める or 毎回取得設計にする
SessionStorageは手軽に使える反面、思わぬ「つまずきポイント」が潜んでいます。
特にChrome拡張の開発においては、chrome.storage.session(Extensionのセッションストレージ)はbackgroundスクリプト専用であり、popupやcontent scriptからは参照できないという制約があります。
そのため、画面ごとの一時的な状態管理には実質的にwindow.sessionStorageを使うしかない場面も多く、選択肢が限られているのが実情です。
とはいえ、設計やキーの工夫次第で、こうした制約下でも安全かつ意図した挙動を実現できます。
同じような課題に悩む方の一助となれば幸いです。