Chrome Extensions をMV3に移行しなくちゃ、ね。

# はじめに
####MV3で何が変わるの、か？

Chromeオフィシャルサイトによると大まかには以下が変更点という、ことらしい。

> 機能の概要

https://developer.chrome.com/docs/extensions/mv3/intro/mv3-overview/#feature-summary

+ サービスワーカーによるバックグラウンドページの置き換え。
+ ネットワークリクエストの変更は、declarativeNetRequestAPIで処理される。
+ リモートでホストされたコードは許可されず、パッケージに含まれているJavaScriptのみを実行可能。
+ 多くのメソッドにPromiseのサポートを追加。

<br>
えーっと、、とりあえずわかったふりをしつつ、、。


# やってみよう

今回MV3に移行するExtensionsでは、バックグラウンド処理としてはコンテキストメニューのみ。ただ、formをDOM生成してPOST送信している。だが、DOMは扱えない、んだ。

####どうするのか？
> 解決策としては2つ。

1. 個人情報は扱ってなく、受信側もPOST・GET両方に対応させてるので、GET送信に変更。
2. 新しくTabページを開いてPOST送信。

<br>
> まずは、<code>manifest.json</code>の更新

https://developer.chrome.com/docs/extensions/mv3/intro/mv3-migration/#updating-manifest-dot-json

```diff_javascript:manifest.json
{
-	"manifest_version": 2,
+	"manifest_version": 3,
	...
-	"browser_action": {
+	"action": {
		"default_icon": {
			"16": "img/icon16.png",
			"32": "img/icon32.png",
			"48": "img/icon48.png",
			"128": "img/icon128.png"
		},
		"default_title": "__TITLE__",
		"default_popup": "popup.html"
	},
-	"content_scripts": [
-		{
-			"matches": [ "http://*/*", "https://*/*" ],
-			"js": [ "js/jquery-3.6.0.min.js", ... ]
-		}
-	],
	"permissions" : [
		"activeTab",
-		"contextMenus",
+		"contextMenus"
-		"http://*/*",
-		"https://*/*"
	],
+	"host_permissions": [
+		"http://*/*",
+		"https://*/*"
+	],
	"background": {
-		"scripts": [ "background.js" ],
-		"persistent": false
+		"service_worker": "background.js"
	}
}
```

:::note warn
<code>content_scripts</code>の理解が出来てなく、パッケージ内で使用してる<code>js</code>を全て書いていたので削除しました。
:::

<br>
> バックグラウンド処理

######<code><strong>GETで送信</strong></code> に変更する場合

```diff_javascript:background.js
chrome.contextMenus.removeAll(function() {
	chrome.contextMenus.create({
		id: '__ID__',
		title: '__TITLE__',
		contexts: ['image', 'video'],
		type: 'normal'
	});
});
chrome.contextMenus.onClicked.addListener(function(info, tab) {
	if (info.menuItemId == '__ID__') {
-		var frm = document.createElement('form');
-		frm.setAttribute('method', 'POST');
-		frm.setAttribute('target', '_blank');
-		frm.setAttribute('action', '__URL__');
-		var req = document.createElement('input');
-		req.setAttribute('type', 'hidden');
-		req.setAttribute('name', 'img_url');
-		req.setAttribute('value', info.srcUrl);
-		frm.appendChild(req);
-		document.body.appendChild(frm);
-		frm.submit();
+		chrome.tabs.create({ url: '__URL__?img_url=' + info.srcUrl });
	}
});
```
:::note warn
GETメソッドで扱えるデータに上限があるので、今回はPOSTを選択。
:::

######<code><strong>POSTで送信</strong></code> する場合

```diff_javascript:background.js
chrome.contextMenus.removeAll(function() {
	...
});
chrome.contextMenus.onClicked.addListener(function(info, tab) {
	if (info.menuItemId == '__ID__') {
-		...
+		postForm('__URL__', {'img_url': info.srcUrl});
+
+		function postForm(url, data) {
+			chrome.tabs.create(
+				{ url: chrome.runtime.getURL('postform.html') },
+				function(tab) {
+					var handler = function(tabId, changeInfo) {
+						if(tabId == tab.id && changeInfo.status == "complete"){
+							chrome.tabs.onUpdated.removeListener(handler);
+							chrome.tabs.sendMessage(tabId, {url: url, data: data});
+						}
+					}
+					chrome.tabs.onUpdated.addListener(handler);
+					chrome.tabs.sendMessage(tab.id, {url: url, data: data});
+				}
+			);  
+		}
	}
});
```

:::note info
新しくTabページを開き、ServiceWorkerとページ間でメッセージのやり取りが可能なので、開いたページ（<code>postform.html</code>）に<code>data</code>を渡します。
:::

```html:postform.html
<html><body><script src="js/postform.js"></script></body></html>
```

:::note warn
開いたページではDOM操作が可能だが、インラインJavaScriptは書くことが出来ないので注意が必要です。
:::

```js:postform.js
var onMessageHandler = function(message){
  chrome.runtime.onMessage.removeListener(onMessageHandler);
  var frm = document.createElement('form');
  frm.setAttribute('method', 'post');
  frm.setAttribute('action', message.url);
  for(var key in message.data) {
    var req = document.createElement('input');
    req.setAttribute('type', 'hidden');
    req.setAttribute('name', key);
    req.setAttribute('value', message.data[key]);
    frm.appendChild(req);
  }
  document.body.appendChild(frm);
  frm.submit();
}

chrome.runtime.onMessage.addListener(onMessageHandler);
```

:::note info
メッセージを受け取ったらformをDOM生成しPOST送信。
:::

# まとめ
バックグラウンドでDOMが扱えなくなった、んだ。どうにかDOMを扱うことは出来ないのか？、、fake-domのようなもので代替出来ないのか？、、、、試行錯誤し、、模索し、あきらめかけましたが、、新しく開いたページではDOM操作が可能という事だったので、MV2と同じ機能のままMV3に移行することが出来ました。

> 今回MV3に移行したChrome Extensions

https://chrome.google.com/webstore/detail/gruu-viewer-web-app/ijegoogljplbdojkjiiljhlgjgpblcfi?hl=ja