0
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?

Chrome拡張機能でoptionページを使用する際の注意点

Last updated at Posted at 2025-07-02

かなりマイナーな記事です。

なぜこの記事を書いたのか

Chrome拡張機能の仕様には、独自の制約があり、つまずいた部分があったので記事にしました!

特にLPを作る間隔で拡張機能に静的ページを用意しようとしたとき、いろいろつまずきました。。

拡張機能のoptionページとは

Chrome拡張を使用する上で設定などを表示するページのことです。

image.png

拡張機能とは独立したファイルとして存在しています。

目的

拡張機能内でユーザーからの問い合わせサブスクリプションのアップグレードなどを気軽に完結させたいと考えました!

外部のWebサイト(LPなど)に処理を分けるのも一般的です。

しかい、ホスティングや運用コスト、メンテナンスの煩雑さを避けたいという理由から、できる限り拡張機能内で完結させる方針をとりました。

実装するなかで、特にOptionページで困ったりした点を記事にしていきます。

optionページの構造と制限:optionページは1ファイルしかない

拡張機能では、options_page もしくは options_ui に設定できるページは1つだけです。

たとえば chrome-extension://[id]/options/index.html という形のURLのみ。

そのため複数のページを持たせることはできず、ReactやVueなどのSPA構成で、状態管理によりページを切り替える形が一般的です。

その際、状態をURLに反映させるためには、クエリパラメータを使うのがシンプルで相性が良いです。

オプションページはコンテンツスクリプトから直接開けない

Chrome拡張機能で options.html を開くとき、コンテンツスクリプトから window.open() を使って chrome-extension:// URL に直接遷移することはできません。

これはセキュリティ上の制限で、ERR_BLOCKED_BY_CLIENT エラーになります。

呼び出し方法 可否 備考
window.open(chrome.runtime.getURL('options/index.html')) コンテンツスクリプトからはブロックされる
chrome.runtime.openOptionsPage() 拡張アイコンやポップアップからの利用に最適
chrome.tabs.create({ url: chrome.runtime.getURL('options/index.html') }) バックグラウンドスクリプト経由なら有効。唯一の正規手段

クエリ付きでオプションページを柔軟に開く方法

柔軟なページ切り替えには、chrome.runtime.sendMessage()chrome.tabs.create() の流れで、 バックグラウンドスクリプト経由でオプションページを開くのが現実的です。

// content script 側
chrome.runtime.sendMessage({ action: 'open-options', page: 'contact' });

// background script 側
chrome.runtime.onMessage.addListener((message) => {
  if (message.action === 'open-options') {
    const url = chrome.runtime.getURL(`options/index.html?page=${message.page}`);
    chrome.tabs.create({ url });
  }
});

SPAであれば、クエリパラメータに応じて表示を出し分ける実装が自然です。

chrome.runtime.openOptionsPage() は manifest に指定された固定ページしか開けません。 クエリを使いたい場合は chrome.tabs.create() を選びましょう。

外部JSを埋め込むことができない(Stripeなど)

Chrome拡張機能(Manifest V3)では、Content Security Policy(CSP)によって外部スクリプトの読み込みが制限されています。

とくに options ページのような拡張機能内のHTMLでは、CDNなど外部から提供されるJavaScriptファイルを `` で読み込むことができません

以下のようなCSPがデフォルトで適用されます:

{
  "content_security_policy": {
    "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
  }
}

この制約により、以下のようなケースでエラーになります:

  • Stripeの <stripe-pricing-table> コンポーネントの埋め込み
  • https://js.stripe.com/v3/ を使った Stripe.js の読み込み

なぜなら:

  • script-src'self' のみで外部CDNが含まれていない
  • eval() を使う外部スクリプトは Manifest V3 で完全に禁止されている

つまり、manifest.json の権限設定でどうにかなる問題ではありません。

詳細はChrome公式ドキュメントを参照。

じゃあどうすればいいの?

この制約を回避するには、決済など外部スクリプトを使いたい処理は、拡張機能外のWebページに分離して実装する必要があります。

たとえば、Firebase Hosting や独自ドメインでホストしたページに stripe.js を読み込んで処理を行い、必要があれば拡張機能とメッセージ通信で連携する構成が現実的です。

🔗 Stripe公式も明記

実際、Stripe公式ドキュメントでも、Chrome拡張ではStripe.jsが使えないことが明記されています。

"Stripe.js は Chrome 拡張機能など、特定の CSP ポリシーを持つ環境では動作しません。"

stripe_csp_warning

まとめ

  • options ページは1ページしか持てず、SPAで状態管理する必要がある
  • コンテンツスクリプトから直接開けないため、バックグラウンド経由で開く
  • 外部JSは読み込めないため、Stripe等の処理は外部ページに分離するしかない
  • Stripe.jsは公式にも拡張機能内では動作しないと明記されている

拡張機能だけで完結したい気持ちは強いが、CSPやセキュリティ制約を考えると、必要な処理は適切に外部へ逃す設計判断が重要だと感じました。

0
0
0

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
0
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?