Chrome拡張機能(Manifest v3)で module を利用する方法

以前私が作成したマウスジェスチャのChrome拡張機能 "Our Mouse Gesture"のManifestファイルをv2→v3に変更した記事を書きましたが、後日談に書いたとおり動作が不安定になり v2 へ戻しました。
今回リベンジで再びManifestファイルのv2→v3変更を行いました。 その際に、最近勉強したJavaScriptのmodule化にもチャレンジしたのですが、一筋縄ではいかず色々うまくいかないことが多かったので、ここに方法を備忘録として残そうと思います。 どなたかのお役になりましたら幸いです。

1. background scriptのmodule化

1.1. Manifestファイル記載方法

Manifest v3の場合、backgroud scriptのmodule化は簡単です。
Manifestファイルでbackgroud scriptの設定で「"type" : "module"」と設定するだけです。

{
    "background":{
        "service_worker": "js/event.js",
        "type": "module"
    },
}

※以前の記事で、backgroud scriptのJavaScriptファイルはManifestファイルと同一階層に配置する必要があると書きましたが、Chromeバージョンが上がって別階層に配置しても問題なくなったようです。

1.2. event.jsでmoduleをimport

event.jsの最初で、必要なモジュールをimportして使うことができます。

  • [event.js]
// 外部JSファイルのmoduleをimport
import { default_settings } from "./common/defaultsettings.js"
import { MyLoggerClass } from "./common/MyLoggerClass.js"
import { MouseGesturesActionClass } from "./MouseGesturesActionClass.js"

※以前の記事では、ここを「importScripts(xxxx.js);」と書いていました。これは古い書き方だって後から知り、恥ずかしい思いをしました(゚o゚;)

当然ここで import されるJavaScript側では、必要なモジュールをexportしておく必要があります!
- 例:MouseGesturesActionClass.js

export class MouseGesturesActionClass {
 :
}

2. content scriptのmodule化

こっちはネットをかなり色々と検索したのですが、全然情報が無くて困りました。。。
最初に参考にしたのはこちらの記事でした。
var.blog.jp 確かにこの方法を行えば、content script内でmoduleを利用する事ができたのですが、chrome.runtime, chrome.storage などのChrome拡張機能のAPIが使えないという大問題があり、断念しました。

最終的に採用した実装方法は、以下のStackOverflowに投稿されていた質問に対する1つめのAnswerでした。正直コードの意味は全然理解していません。。。(^_^;)
この方法だと、content script内でimportもでき、chrome.runtime, chrome.storage などのChrome拡張機能のAPIも使うことができました!

stackoverflow.com

2.1. content scriptとしてロードするJavaScriptファイルの作成

Manifestファイルで読み込むcontent scriptを以下のように記載します。 このコードではcontent scriptの本来のロジックが書かれた "content.js" のimportだけをします。

  • [loader.js]
(async() => {
    const src = chrome.runtime.getURL("js/content.js");
    const contentMain = await import(src);
})()

2.2. Manifestファイルの記載

次にManifestファイルを以下のように記載します。

  • 先ほど作成した "loader.js" を "content_scripts"として設定します。
  • "loader.js"内でimportしたcontent scriptの本来のロジックが書かれた "content.js"は、 "web_accessible_resources"として記載します。
  • content.js内でimportするファイル群も同様に "web_accessible_resources"として記載します。
    "content_scripts": [{
        "matches": [ "<all_urls>" ],
        "js": [
            "js/loader.js"
        ]
    }],
    "web_accessible_resources": [
        {
            "resources": [
                "js/content.js",
                "js/MouseGesturesActionClass.js",
                "js/common/defaultsettings.js",
                "js/MyCanvasClass.js",
                "js/MyMouseClass.js",
                "js/common/common.js",
                "js/common/MyLoggerClass.js"
            ],
            "matches": ["<all_urls>"]
        }
    ],

2.3. content scriptの本来のロジックが書かれた "content.js"でmoduleをimport

content.jsの最初で、必要なモジュールをimportして使うことができます。

  • [content.js]
// 外部JSファイルのmoduleをimport
import { MouseGesturesActionClass } from "./MouseGesturesActionClass.js";
import { default_settings } from "./common/defaultsettings.js";
import { MyCanvasClass } from "./MyCanvasClass.js";
import { MyMouseClass } from "./MyMouseClass.js";
import { PageScroll } from "./common/common.js";
import { MyLoggerClass } from "./common/MyLoggerClass.js"


当然event.jsの時と同様に、ここで import されるJavaScript側では、必要なモジュールをexportしておく必要があります!

  • 例:MyCanvasClass.js
export class MyCanvasClass {
 :
}

3. option ui 内のJavaScriptで moduleをimport

こちらは全然情報を見つけられなかったのですが、普通にoption uiで使用したhtmlから、JavaScriptを読み込む際に、moduleとして読み込めば問題ありませんでした!

3.1. option uiのHTMLでJavaScriptをmoduleとして読み込み

以下の通りです。

<!DOCTYPE html>
<html>
<head>
 :
</head>
<body>
 :
  <script src="js/options.js" type="module"></script>
 :
</body>
</html>

後書き

以前書いた以下の記事を見て下さる人が最近急増しています。 GoogleとYahooから来られる人の7割以上がこの記事を見ていました!

blog.holyblue.jp

Chrome拡張機能のManifest v2の終了期限が近づいてきているので、みなさんManifest v3対応を頑張っておられるのだなとすごい感じました。それもあって今回私が作ったChrome拡張機能も頑張ってManifest v3に対応しました。 少しの間、自分で使ってみて安定していそうであれば公開しようと考えています。
最後まで読んで頂きありがとうございました。