dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

自作Chrome拡張をManifest V3に移行したメモ

という Chrome 拡張を作っているのだが、先日ようやく Manifest V3 に移行したのでそのときにやったことのメモ。

該当の PR はこれ。

また、作業中は Zenn のスクラップにメモを取りながら進めていた。
自作Chrome拡張をManifest v3に対応させる

モチベーション

Manifest V3 移行へのモチベーションはそこまで高くなかったが、vite を触ってみるため webpack からの移行を試してみたいなと思っていた。
そんな折

Chrome拡張 つくりかた 令和最新版

という記事を拝見して、自分もこのとおりにやって乗り換えようと思った。が、どうやら @crxjs/vite-plugin というプラグインは Manifest V3 にしか対応してないということがわかり、先に V3 移行を済ませるようにした、という経緯。

参考:いつまでに Manifest V3 に移行すべきか

The transition of Chrome extensions to Manifest V3 - Chrome Developers

によれば、 2022年1月からすでに新規の Chrome 拡張は Web ストアで公開することができず、既存のものについても 2023年1月以降は動作しなくなるらしい。

どう進めたか

最初に

Manifest V3 migration checklist - Chrome Developers

を見て自分があてはまる項目を確認し、あとはそこから参照されているリンクも読みつつ適宜移行を進めていった。

自分の Chrome 拡張はページのタイトルと URL をコピーするだけのシンプルな機能で、そんなに複雑な API を使っていない。チェックリストであてはまったのは以下:

  • Are you using background pages?
  • Are you using the browser_action or page_action property in manifest.json?
  • Are you using the chrome.browserAction or chrome.pageAction JavaScript API?

やったこと1: browserAction を action に移行

V3 では browser action と page action という区別がなくなり、action で統一されるらしい。
そのため manifest.json 内の xxx_action という記述およびソースコード内の chrome.xxxAction を action に変換する。

コミット:https://github.com/zaki-yama/copy-title-and-url-as-markdown/pull/221/commits/b259acbba3520727e2bc49a5260eff86740580c7?diff=unified&w=0

manifest.json

   "commands": {
-    "_execute_browser_action": {
+    "_execute_action": {
       "suggested_key": {
         "default": "Ctrl+Shift+C",
         "mac": "MacCtrl+Shift+C"
@@ -29,7 +29,7 @@
       "description": "Copy as optional format #2"
     }
   },
-  "browser_action": {
+  "action": {
     "default_icon": "icon.png",
     "default_popup": "popup.html"
   },

background.ts

-      chrome.browserAction.setBadgeText({ text: formatIndex });
+      chrome.action.setBadgeText({ text: formatIndex });

1つポイントとしては、manifest の commands でポップアップのショートカットキーを設定している場合、ここも _execute_action に変える必要がある。

やったこと2: background page を Service Worker 化する

コミット:https://github.com/zaki-yama/copy-title-and-url-as-markdown/pull/221/commits/c57581e1dfa03bafe320ca190698b4f112e28280

V3 からは background page という概念はなくなり、 Service Worker になる。

ここで少々困ったのが、元々ポップアップとは別のショートカットキーでもページのタイトルとURLをクリックできるよう、 background page を使用していた。(コピー時のフォーマットとして、ポップアップ起動時とは別のフォーマットをオプションで設定できる)

そのしくみとして、background page の HTML 内にダミーの textarea 要素を置き、そこに値をセットして select してから document.execCommand("copy") を呼ぶという方法を取っていた。しかし、V3 では HTML がなくなったためこの方法は使えない。

createElement すればいいかと思っていたが、冒頭の

Chrome拡張 つくりかた 令和最新版

を書いた方が公開している拡張のソースコードを見て、なるほどそんなやり方もあるのかと知ったためそ方法を真似させていただいた。

https://github.com/r7kamura/copy-rich-link/blob/main/src/main.ts#L3-L12

また別の問題として、Service Worker から直接は document などのオブジェクトは触れない。そのため、 Scripting API というものを使う。

// copyToClipboard の実装は↑で紹介したものとほぼ同じ
import { escapeBrackets, copyToClipboard } from "./util";

chrome.commands.onCommand.addListener((command) => {
  const queryInfo = {
    active: true,
    currentWindow: true,
  };

  chrome.tabs.query(queryInfo, function (tabs) {
      // (中略)

      chrome.scripting.executeScript({
        target: { tabId },
        func: copyToClipboard,
        args: [options[key], title, escapeBrackets(url)],
      });
   ...

chrome.scripting.executeScriptAPI ドキュメントはここ:
https://developer.chrome.com/docs/extensions/reference/scripting/#method-executeScript

func に呼び出したい関数を渡すことができる。ただし、

This function will be serialized, and then deserialized for injection.

ということで関数はシリアライズされるので、関数内でまた別の関数を呼ぼうとするとエラーになる。

その他ハマったポイント

ローカル開発中、ポップアップ起動のショートカットキー( _execute_action )の変更がなかなか反映されない、という謎の挙動に遭遇した。

何度か拡張の読み込みを試したり、 Chrome ごと再起動したら反映された。詳しい再現手順はわからず。

参考リンク