ブラウザの名前空間への移行

Chrome 148 以降では、既存の chrome 名前空間に加えて、すべての Chrome 拡張機能 API が browser 名前空間で使用できるようになりました。たとえば、browser.tabs.create({})chrome.tabs.create({}) は同等です。

この名前空間は、コンテンツ スクリプト、サービス ワーカー、オフスクリーン ドキュメントなど、拡張機能 API を呼び出すことができる場所であればどこでも使用できます。chrome と同じ API オブジェクト(chrome.tabs === browser.tabs)を指します。

browser 名前空間は、WebExtensions Community Group(WECG)の作業から生まれました。これは、ブラウザ ベンダーが共有拡張機能の標準で連携する W3C コミュニティ グループです。chrome Namespace は削除されません。両方の Namespace が引き続き機能します。

ブラウザ名前空間を採用するかどうかを決定する

webextension-polyfill を使用している場合は、他の変更を行う前にポリフィルを使用している場合の注意点に進んでください。回答が異なります。

新しい拡張機能を構築する場合は、minimum_chrome_version"148" に設定し、browser を無条件で使用します。ここで読み進めるのを止めてもかまいません。このセクションの残りの部分は、採用方法を決定する既存の拡張機能向けです。

ユーザーが使用している Chrome のバージョンを確認する

既存の拡張機能がある場合は、切り替える前に、ユーザーが実行している Chrome のバージョンを確認してください。Chrome は自動更新されますが、更新を無効にしているユーザーもいれば、最新バージョンを実行できない古いデバイスを使用しているユーザーもいます。ご自身の分析データで確認してください。アナリティクスをまだ設定していない場合は、Google アナリティクス 4 で拡張機能のパフォーマンスをモニタリングするをご覧ください。

ここから、次のいずれかの方法を選択します。

無条件で採用する

マニフェストで minimum_chrome_version を設定し、browser を無条件で使用します。ランタイム ガードは不要です。

{
  "minimum_chrome_version": "148"
}

minimum_chrome_version を増やす場合は、段階的な公開を使用します。問題が発生した場合は、Chrome ウェブストアで拡張機能をロールバックできます。

ランタイム ガードを使用する

拡張機能の起動コードの早い段階で、次のスニペットを追加します。browser を他の場所で参照する前に追加してください。

if (!globalThis.browser) {
  globalThis.browser = chrome;
  // Consider firing an analytics event here to measure how often
  // your users hit this fallback path.
}

これにより、以前のバージョンでは browserchrome のエイリアスになるため、コードの残りの部分では browser を無条件で使用できます。

ポリフィル ユーザー向けの注記

拡張機能で webextension-polyfill を使用している場合、Chrome 148 以降では no-op になります。ポリフィルは、browser がすでに定義されている場合、ホストブラウザがすでに API を提供していると想定して、ラッピングをスキップしていました。

Chrome 136 で Namespace をリリースしようとした試みは、この理由でロールバックされました。browser が新たに定義されたことで、ポリフィルはラップを停止しましたが、Chrome の browser.runtime.onMessage は、ポリフィルが提供していた Promise を返すリスナーをまだサポートしていませんでした。そのパターンに依存する拡張機能は動作しなくなりました。Chrome 148 では、このギャップを回避するため、名前空間とネイティブの Promise を返す onMessage リスナーが同時に提供されます。

ユーザーベースが Chrome 148 に移行したら、ポリフィル依存関係を削除できます。

その他の機能

runtime.sendMessage の非同期レスポンス

Chrome 148 では、runtime.onMessage リスナーが Promise を直接返して非同期レスポンスを送信できるようになりました。これは、chrome.* または browser.* を使用して呼び出すかどうかにかかわらず機能します。

以前は、非同期で応答する唯一の方法は、リスナーからリテラル true を返し、後で sendResponse を呼び出すことでした。

// Old pattern - requires returning true to keep the channel open
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  fetch('https://example.com')
    .then(response => sendResponse({ statusCode: response.status }));

  return true; // keeps the message channel open for the async response
});

これで、Promise を直接返す(または async 関数を使用する)ことができます。

// New pattern - return a promise or use async/await
browser.runtime.onMessage.addListener(async (message, sender) => {
  const response = await fetch('https://example.com');
  return { statusCode: response.status };
});

return true パターンは引き続き機能するため、既存のコードを変更する必要はありません。