💅

自作Chrome拡張をManifest V3移行した記録

2022/05/14に公開約4,700字3件のコメント

Mouse Dictionaryという拡張をManifest V3移行した記録です。

前提

Manifest V3とは

既存のChrome拡張は2023年には動かなくなります。Manifest V3に移行しない限り。

Manifest V2 support timelineより

そもそもV3って何なの?という話は本題ではないので詳しくは公式ドキュメント先人の記事をご参照ください。


Mouse Dictionaryは2018年にリリースされた拡張で当然V2でつくられているため、遅かれ早かれV3への移行が必要でした。

(追記)
世間のV3移行状況が気になったので調べました。

https://zenn.dev/wtetsu/articles/a5a7b0e1294be7

クロスブラウザ問題

2022年5月時点ではFirefoxはManifest V3に未対応のため、Firefox版はV2を維持する必要があります。つまり、クロスブラウザな拡張機能はV2とV3への両対応が必要なため、なかなか面倒なことになります。

Mouse DictionaryではChrome版はV3に移行しつつFirefox対応も維持してみたので、似たような境遇の方はぜひご参考ください。

実際の移行

公式移行ガイドがあります。

https://developer.chrome.com/docs/extensions/mv3/intro/mv3-migration/

以下は実際の泥臭い移行の記録。

下準備1: evalの排除

Manifest V3では、eval()やnew Function()への制約が強くなります。

Mouse DictionaryはMustacheエンジンとしてHogan.jsを使用していたのですが、これが内部的にnew Function()を使っていたため、上記Manifest V3の制約にひっかかることになりました。

そこで、Hogan.jsからmustache.jsに移行することでnew Function()を排除しました。

なお、もともとMustacheエンジンとしてHogan.js、mustache.js、Handlebarsを候補としており、(Mouse Dictionaryの用途において)最も高速だったHogan.jsを採用したという背景がありました。mustache.jsも十分高速で互換性も高く問題なく移行できました。

下準備2: ブラウザごとのビルド

Chrome版をV3移行しつつFirefox版も維持したい場合は、全ブラウザ対応用のmanifest.jsonひとつ用意しておく、という方法が不可能になります。Mouse Dictionaryの場合はこんな感じにして、ビルド時に適切なmanifest.jsonがパッケージに含まれるようにしています。

コードや設定の変更

GitHub上で変更点を見る

コード

chrome.browserAction -> chrome.action

V3ではchrome.browserActionをchrome.actionに変更する必要があるのですが、逆にV2(Firefox)ではchrome.actionが無くchrome.browserActionを使う必要があるので、クロスブラウザにするにはなんらかの工夫が必要になります。

いろいろ方法はあると思いますが、クロスブラウザ対応する必要があるのはここ一箇所だけだったので、単純にwebpackの定数で分岐するようにしました。あまり大げさな仕組みを入れてもV2がこの世から消えたら無駄になるので、こんな感じで十分でしょう。

if (BROWSER === "CHROME") {
  chrome.action.onClicked.addListener((tab) => {
    chrome.scripting.executeScript({
      target: { tabId: tab.id },
      files: ["main.js"],
    });
  });
} else {
  chrome.browserAction.onClicked.addListener(() => {
    chrome.tabs.executeScript({
      file: "./main.js",
    });
  });
}

ちなみにこんな感じにしてもクロスブラウザで動きます。

if (chrome.action) {
  chrome.action.onClicked.addListener((tab) => {
    chrome.scripting.executeScript({
      target: { tabId: tab.id },
      files: ["main.js"],
    });
  });
} else {
  chrome.browserAction.onClicked.addListener(() => {
    chrome.tabs.executeScript({
      file: "./main.js",
    });
  });
}

不要な方の処理がビルド時に消え去るという点で、前者の方が少しお得です。

chrome.extension -> chrome.runtime

V2(Firefox)でもchrome.extensionとchrome.runtime両方動くようだったので、こちらは単純に差し替えました。

-  const url = chrome.extension.getURL(fname);
+  const url = chrome.runtime.getURL(fname);

manifest.json

permissions

-  "permissions": ["storage", "unlimitedStorage", "activeTab"],
+  "permissions": ["storage", "unlimitedStorage", "activeTab", "scripting"],

background

   "background": {
-    "scripts": ["background.js"],
-    "persistent": false
+    "service_worker": "background.js"
   },

commands

   "commands": {
-    "_execute_browser_action": {
+    "_execute_action": {
       "description": "Activate the extension"
     },

web_accessible_resources

-  "web_accessible_resources": ["data/*.json"]
+  "web_accessible_resources": [
+    {
+      "resources": ["data/rule.json", "data/dict*.json"],
+      "matches": ["<all_urls>"]
+    }
+  ]

解決できていない問題

ローカルファイルで動かない

Mouse DictionaryはローカルのHTMLをChromeで開いたやつに対しても使えたのですが、V3移行で使えなくなってしまいました。原因はわかっていて、file:///~ で開いているタブにweb_accessible_resourcesが効かないことなのですが、公式情報が見つからないので、これがV3での意図した変更なのか、Chromeのバグなのかわからず、様子見状態です。

類似現象。

ショートカットキー設定の挙動がおかしい

Mouse Dictionaryはショートカットキーを設定することができるのですが、V3移行後の挙動がいまいち不安定です。どうも、ショートカットキーを設定してもすぐには反映されず、Chromeを再起動したりすると反映されるようです。これも拡張開発者側でできることがなく、様子見状態です。

感想

あくまでMouse Dictionaryの場合ですが、変更したコード量は少なめでした。ただしWeb上にManifest V3移行の経験談的な情報がまだ少なく、どのように変更したらV2と同様に動くようになるかの調査・試行錯誤・検証が大変です。

Discussion

このバージョンアップ、実際、ほんとにやるんですかね。
Adblockとか、ScriptAutoRunnerとかが、
V2からV3で軒並み使えなくなりそうというか、
ユーザーにブラウザ上でスクリプトを動かせるような設定をさせないようになってきて

そういうのを締め付けるためにやっているような気もします。

セキュリティと利便性を天秤にかけて、利便性を捨ててセキュリティ側にふろうとしているというかなんというか。

ちょうど私もv3に移行して今審査待ち状態です。Googleアナリティクスもつかえなくなったしバージョンアップするメリットがありませんでした。 Googleが出してる拡張がv2ってのはひどいですね。。。

ログインするとコメントできます