という Chrome 拡張を作っているのだが、先日ようやく Manifest V3 に移行したのでそのときにやったことのメモ。
該当の PR はこれ。
また、作業中は Zenn のスクラップにメモを取りながら進めていた。
自作Chrome拡張をManifest v3に対応させる
モチベーション
Manifest V3 移行へのモチベーションはそこまで高くなかったが、vite を触ってみるため webpack からの移行を試してみたいなと思っていた。
そんな折
という記事を拝見して、自分もこのとおりにやって乗り換えようと思った。が、どうやら @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
orpage_action
property in manifest.json? - Are you using the
chrome.browserAction
orchrome.pageAction
JavaScript API?
やったこと1: browserAction を action に移行
V3 では browser action と page action という区別がなくなり、action で統一されるらしい。
そのため manifest.json 内の xxx_action
という記述およびソースコード内の chrome.xxxAction
を action に変換する。
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 化する
V3 からは background page という概念はなくなり、 Service Worker になる。
ここで少々困ったのが、元々ポップアップとは別のショートカットキーでもページのタイトルとURLをクリックできるよう、 background page を使用していた。(コピー時のフォーマットとして、ポップアップ起動時とは別のフォーマットをオプションで設定できる)
そのしくみとして、background page の HTML 内にダミーの textarea 要素を置き、そこに値をセットして select してから document.execCommand("copy")
を呼ぶという方法を取っていた。しかし、V3 では HTML がなくなったためこの方法は使えない。
createElement
すればいいかと思っていたが、冒頭の
を書いた方が公開している拡張のソースコードを見て、なるほどそんなやり方もあるのかと知ったためそ方法を真似させていただいた。
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.executeScript
の API ドキュメントはここ:
https://developer.chrome.com/docs/extensions/reference/scripting/#method-executeScript
func
に呼び出したい関数を渡すことができる。ただし、
This function will be serialized, and then deserialized for injection.
ということで関数はシリアライズされるので、関数内でまた別の関数を呼ぼうとするとエラーになる。
その他ハマったポイント
ローカル開発中、ポップアップ起動のショートカットキー( _execute_action
)の変更がなかなか反映されない、という謎の挙動に遭遇した。
重い腰を上げて自作Chrome拡張をManifest V3に上げようとしてるんだけど、ポップアップを表示するショートカットキーどうやっても効かなくない...? _execute_actionには変更したんだが...
— Shingo Yamazaki (@zaki___yama) 2022年5月27日
何度か拡張の読み込みを試したり、 Chrome ごと再起動したら反映された。詳しい再現手順はわからず。