
Chrome拡張機能のv3からService Workerにする必要が出てきました。
Service Workerについて知りたい方を対象にしています。
v3でService Workerは使わないとだめ?
バックグランドページを使っている場合は、サービスワーカーに切り替える必要があります。
というか、使わないとマニフェストエラーとなってしまい読み込んでChrome拡張機能がエラーを吐いてしまいます。
どの部分がエラーになっているかというとマニフェストファイルの部分になります。
{
"manifest_version":3,
"name":"Chrome ex page action",
"version":"1",
"permissions":["declarativeContent"],
"background": {
"scripts": ["background.js"]
}
}
background > scriptの部分。
v3からこちらを、service_workerに変更する必要が出てきました。
変更方法、注意点に関しては後述します。
公式サイト見た方が早いって方はこちら(英語ですが。。)
Service Workerとは?
Web上に記述されたスクリプト(javaScript)を
インストールさせることで、
ページを離れた後や、ブラウザの再起動後でもスクリプトを実行できるようにする仕組みです。
(インストールさせるので、閲覧者の許可が必要です)
ServiceWokerは、バックグランド動作に特化した仕様となっているのもポイントです。
メリット
- オフライン状態でも利用可能
- ページ遷移後でも利用可能
- ブラウザの再起動後でも利用可能
- ページを表示していない時にサイト側と通信してキャッシュの更新が可能(バックグランド同期)
- サイト側から閲覧者に通知が可能(プッシュ通知)
デメリット
- DOM操作ができない(画面の操作や、値の取得)
- セキュリティ上の都合により、HTTP通信の禁止(ただし、HTTPS通信はOK)
バックグランドをChrome拡張機能のv3に対応させる
Service Workerのメリット・デメリットを見る限り今までのままの方がいいじゃんって個人的には思ってしまいます。。orz
DOM操作できないこともそうですが、いろいろ記事を拝見するにまだまだバージョンアップに伴い問題が出てきているようです。
可能な限りまとめていきたいと思います。
マニフェストファイルの修正
修正後のファイルです。
一番の注意点は、backgroundに指定できるスクリプトファイルが単一になっていることです!
(実際、自分が担当しているプロジェクトは配列で複数指定しているのでどうしようって感じです。
指定するスクリプトファイルから、さらに別スクリプトファイルを読み込ませればいけそうって記事を見かけたのですがまだ試せてません。。)
{
"manifest_version":3,
"name":"Chrome ex page action",
"version":"1",
"permissions":["alarms", "storage", "activeTab", "scripting"],
"background": {
"service_worker":"background.js"
},
"action": {
"default_title": "Click Me"
}
}
ポイント1: バックグランドページでは、グローバル変数非推奨
サービスワーカーが結構短命ですぐ接続が切れる可能性が高いため、グローバル変数に値を保持するのは非推奨だそうです。
ストレージAPIを使うことを推奨されていますので、面倒ではありますがこちらを使用するようにしましょう。
(ストレージAPIを使う場合は、マニフェストの”permissions”に”storage”を追記する必要があるので注意)
// TODO (1_NG)グローバル変数は非推奨
let savedName = undefined;
chrome.runtime.onInstalled.addListener(({}) => {
console.log('oninstalled')
// TODO (1_OK) ストレージを使うこと
chrome.storage.local.set({'key': "abcedfg"}, function () {});
savedName = "hijkelmn"
})
ポイント2:イベントリスナーの記載場所はトップに書く
こちらも同様でサービスワーカーが短命なため、トップレベルにイベントリスナーを登録してすぐ動作するようにする必要があります。
何かの処理の後などにイベントリスナーを登録しているとうまく動作しない可能性があるので注意です。
永続的にバックグランドサービスを起動させれば動いていた処理が、サービスワーカーに変えることで動かなくなる可能性があるので注意です。
サービスワーカーは、非同期かつバックグランドに特化した作りとなっており永続的にバックグランドを動かせる保証がされてません。
chrome.storage.local.get("key", function (value) {
console.log(value.key);
// TODO(2_NG) ここにイベントを書くのはダメ!!
// chrome.action.onClicked.addListener((tab) => {
// chrome.scripting.executeScript({
// target: {tabId: tab.id},
// files: ['content.js']
// });
// });
});
// TODO(2_OK)TOPレベルにイベントを記載すること
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: {tabId: tab.id},
files: ['content.js']
});
// ストレージに保存している方はエラーにならない
console.log('tabs.onupdated')
// タブタップ時にエラーとなる
console.log(savedName)
});
ポイント3:タイマーは非推奨。アラームAPIへ移行が必要
サービスが終了すると同時にスケジューラーがタイマーをキャンセルする可能性があります。
代わりに、AlarmsAPIを使う必要があります。
アラームのリスナーもトップレベルに記述が必要です。
// TODO (3_NG) 非推奨!!This worked in Manifest V2.
// const TIMEOUT = 3 * 60 * 1000; // 3 minutes in milliseconds
// setTimeout(() => {
// chrome.action.setIcon({
// path: getRandomIconPath(),
// });
// }, TIMEOUT);
// TODO (3_OK) AlarmsAPIを使うこと
// アラームを作成
chrome.alarms.create('NAME_OF_ALARM', { delayInMinutes : 1 });
// リスナーはトップレベルに記載が必要
chrome.alarms.onAlarm.addListener(function(alarm) {
if (alarm.name == 'NAME_OF_ALARM') {
console.log('nanika')
}
});
ポイント4:DOM操作、Javascriptのwindowなどが使えない
サービスワーカーは、バックグランドに特化した作りとなっておりかなり制限がかかっています。
特に、DOM操作だったり、window関連のメソッドなどが使えなくなっていますので注意です!
// TODO(4_ng) v2だと動くが、v3だとエラーになる。
// window.alert('HelloWorld');
回避方法は、
chrome.windows.create()
やchrome.tabs.create()
を使って別に新規でタブやwindowを作成する- ライブラリを使う(https://github.com/developit/undom、https://github.com/jsdom/jsdom)
udomやjsdomについては割愛します。
(バックグランドでゴリゴリとDOM操作されている方はかなり大変なことになりそうです。。)
その他注意点
オーディオやビデオの再生、またはキャンバスをバックグランドで使う場合も注意点があります。
詳細は、公式ページを参照。
まとめ

・バックグランドページを使っている場合、サービスワーカーへの切り替えが必要
・サービスワーカーは、バックグランドに特化した機能
・サービスワーカーに指定できるバックグランドページのファイルは単一
・DOM操作や、winodwメソッドは使えない
・短命のため、値の保持方法やイベントリスナの登録には注意が必要
仕事で、拡張機能使っておりv3へのバージョンアップが必須となり困ってます。
まだまだ、課題が山盛りなので気づいたことがあれば追記します。
今回調査でいろいろ試したソースコードはgitに上げてますので参考に。
[git]