Open4

Vite + SvelteでChromeの拡張機能を作成する

BlueSchnauzerBlueSchnauzer

何番煎じだという感じですが、
Vite + SvelteでChromeの拡張機能を作成する環境を作ったので詰まったところなどをまとめます。
今回はいわゆるnpm init viteを実行して設定されるパッケージのみを使って環境を作りました。
(SvelteじゃなくてViteの説明がメインなので別のフレームワークでも使えるかも)

ゴールとしては設定ファイルであるmanifest.jsonを含めてファイルをビルドし、
出力先を指定することを拡張機能を利用できるようにします。
(+ HMRも利用できるようコマンド設定する)

この設定で作ろうと思ったきっかけなんですが、
拡張機能を作ろうと検索していたところ、
ヘルパーとしてCRXJSが有名なようで、ちょこちょこ色々な記事で名前を見ました。
https://github.com/crxjs/chrome-extension-tools

ですが、こちらは更新がかなり止まっており、
メンテナーがいなければ、アーカイブされちゃうよーとのことなので、
依存する部分少な目でいきたいなと思ったのが理由です。

BlueSchnauzerBlueSchnauzer

今回は使いませんが、
調べているうちに、拡張機能を作るに当たって、
役立ちそうなものがあったのでリンクを置いておきます。
(多機能過ぎるので今回は使いませんでした)

BlueSchnauzerBlueSchnauzer

Viteの初期設定

まずは任意のフォルダでnpm init viteを実行し、SvelteとTypescriptを選択します。
実行したらこんな感じになると思います。

|   .gitignore
|   index.html
|   package-lock.json
|   package.json
|   README.md
|   svelte.config.js
|   tsconfig.json
|   tsconfig.node.json
|   vite.config.ts
+---.vscode
|       extensions.json
+---public
|       vite.svg
\---src
    |   app.css
    |   App.svelte
    |   main.ts
    |   vite-env.d.ts
    +---assets
    |       svelte.svg
    \---lib
            Counter.svelte

Chrome拡張機能用ファイルの作成

次はChrome拡張用の設定ファイルを作成します。
※詳しい説明はこの辺りを参照。
https://developer.chrome.com/docs/extensions/get-started?hl=ja
今回はポップアップを作るとして設定します。
(拡張機能のアイコンを押すと小さいウィンドウが出るやつです)

manifest.jsonの作成

publicフォルダ内に、manifest.jsonを作成します。
ファイルの中身は以下の通りです。

manifest.json
{
	"manifest_version": 3,
	"name": "SampleExtension",
	"description": "Sample extension",
	"version": "1.0",
	"action": {
		"default_popup": "popup.html"
	}
}

publicフォルダの扱い

Viteで言うところのpublicフォルダは静的ファイルの配置場所なので、
npm run build(vite build)を実行すると、distフォルダにそのままコピーされます。
https://ja.vite.dev/guide/assets.html#the-public-directory

ですので、拡張機能アイコンを置く場合はここになると思います。
public/icons/sample.pngとかって配置した場合は、manifest.jsonで以下のように参照します。

manifest.json
{
	"manifest_version": 3,
	"name": "SampleExtension",
	"description": "Sample extension",
	"version": "1.0",
+	"icons": {
+		"16": "icons/sample_16.png",
+		"32": "icons/sample_32.png",
+		"48": "icons/sample_48.png",
+		"128": "icons/sample_128.png"
+	},
	"action": {
		"default_popup": "popup.html",
+		"default_icon": "icons/sample_48.png"
	}
}

popup.htmlの作成

動きとしてポップアップが出るのは定義できたので、ポップアップの中身になるhtmlを作ります。

ポップアップ用のhtmlはpopup.htmlという名前でないと認識されない?ようなので、
Svelteのコンポーネントを読み込める状態のhtmlを作って、
ビルド対象として読み取れるようにしたいと思います。

ここでは、デフォルト生成されたindex.htmlの名前をpopup.htmlにリネームします。

index.html/src/main.tsをscriptタグで読み込んでいますが、
この/src/main.tsがSvelteのエントリーポイントになっています。
(appというidのついた要素の操作を許可して、DOMをいじれるようにしていますね)

ただ、このままではpopup.htmlがビルド対象として認識されないので、
以下のようにvite.config.tsの設定を変更します。

vite.config.ts
import { defineConfig } from "vite";
import { svelte } from "@sveltejs/vite-plugin-svelte";

// https://vitejs.dev/config/
export default defineConfig({
	plugins: [svelte()],
+	build: {
+		rollupOptions: {
+			input: {
+				popup: "popup.html",
+			},
+		},
+	},
});

デフォルトではindex.htmlのみを読み取りますが、
rollupの設定を変更することでinputを変更することができます。

ここで設定することで、scriptタグで指定したtsファイルの依存関係をバンドルしてくれます。
(当初はこの辺り分からずpopup.htmlは静的なので、main.tsのみをトランスパイルしていたが、
動的に生成されたCSSファイルがhtmlに紐づかないのでスタイルが適用されなかった)

拡張機能の読み込み

この時点でフォルダ構成はこんな感じになってるかなと思います。

|   .gitignore
|   package-lock.json
|   package.json
|   popup.html
|   README.md
|   svelte.config.js
|   tsconfig.json
|   tsconfig.node.json
|   vite.config.ts
+---.vscode
|       extensions.json
+---dist
|   |   manifest.json
|   |   popup.html
|   |   vite.svg
|   \---assets
|           popup-1531a8fc.js
|           popup-9ea02431.css
|           svelte-a39f39b7.svg
+---public
|       manifest.json
|       vite.svg
\---src
    |   app.css
    |   App.svelte
    |   main.ts
    |   vite-env.d.ts
    +---assets
    |       svelte.svg
    \---lib
            Counter.svelte

npm run build(vite build)を実行すると、
distフォルダにビルド結果が出力されます。
Chromeから読み取る際はこのフォルダを指定すれば大丈夫です。

HMRの適用

ViteのHMRを活用したいため、ビルドコマンドの設定を変更します。
デフォルトのビルドコマンドはvite buildですが、
ファイルの変更を検知して再ビルドするためにvite build --watchをpackage.jsonに設定します。
(watchコマンドで設定して、npm run watchで呼べるようにします)

Viteの開発用サーバーを立ち上げて、それをmanifest.jsonで見たり、、とかもできるようですが、
手間がかかりそうなので一旦ここまでで。

BlueSchnauzerBlueSchnauzer

拡張機能作っていて気付いたけど、
manifest.jsonを修正した場合はChromeから再読み込みをしないと設定が反映されないですね。
htmlやjsを変更して再ビルドした場合は変更が検知されるけれど、
manifest.jsonの場合は再ビルドしてから再読み込みが必要でした。