最近、moji 辞書のクリックで日本語の単語を検索するためのオープンソースプロジェクトに参加したいと思っています。公式のものよりも使いやすいです。使ってみると悪くはないですが、長年の放置が気になります。奇妙なことに、xlog の RSS は AI の要約と組み合わせることができません。これで文字数を稼がなければなりません。
- プロジェクトアドレス: https://github.com/Yukaii/mojidict-helper
- Chrome ストア: https://chrome.google.com/webstore/detail/mojidict-helper/eknkjedaohafedihakaobhjfaabelkem
本記事では、Vite/Webpack+React を Chrome ブラウザで使用する方法のみを示します:
Chrome ブラウザのアドレスバーにchrome://extensions/
と入力して、現在インストールされているすべての拡張機能を確認できます。
また、右上の開発者モードがオンになっていることを確認してください:
💻 開発環境#
一般#
IDE: Visual Studio Code
React: v18+
Vite: v3+
Vite: v4.2.0
Webpack: v5.76.2
私はpnpm
を使用してローカルのすべての依存関係を管理しています。もし持っていない場合や他のパッケージ管理ツールを使用している場合は、pnpm
を対応するコマンドに置き換えてください!
その他の推奨ツール#
- TailwindCSS
- TypeScript
📦 パッケージツール (Module Bundler)#
原生開発 (VanillaJS)#
公式が提供するこれらのデモを直接参考にしてください:
Webpack#
Vite (推奨)#
このライブラリをどう使うか?クローンした後、パッケージ依存関係をインストールしますpnpm install
、次に開発モードを起動します:
pnpm dev
: これは開発モードです
pnpm build
: これは生産モードです
上記のコマンドで生成されたコードはすべて build ディレクトリにあるため、chrome://extension
ディレクトリにこのディレクトリを読み込むだけで、開発しながら結果を見ることができます:
📑 公式文書#
https://developer.chrome.com/docs/extensions/
👟 前提準備#
ライフサイクル#
- onInstalled: インストール、更新、または拡張機能の再読み込みがトリガーされます
- onSuspend: 拡張機能が一時停止される直前にトリガーされます
- onSuspendCanceled: 拡張機能の一時停止がキャンセルされたときにトリガーされます
- onUpdateAvailable:拡張機能が更新可能なとき(ユーザーに通知するために使用できます)トリガーされます
- onStartup: Chrome が起動し、拡張機能を読み込むときにトリガーされます
- onConnect イベント:拡張機能が Chrome の別の部分(例えばコンテンツスクリプト)と接続を確立するとトリガーされます
- onConnectExternal:外部アプリケーション(例えばネイティブアプリケーション)からの接続が確立されたときにトリガーされます
- onMessage:Chrome の別の部分(例えばコンテンツスクリプト)からメッセージを受信したときに onMessage イベントがトリガーされます
コード内でどのように使用しますか?
chrome.runtime.XX
XX は上記のライフサイクル名の 1 つです、例えば:
chrome.runtime.onInstalled.addListener((details) => {
console.log('Extension installed:', details.reason);
});
プラグイン設定 manifest.json#
ここからは、manifest v2 バージョンとは非常に異なる点が多く、特に重要なのは、manifest v2 の直接的な DOM 操作メカニズムがサービスワーカーに置き換えられたことです。つまり、使用しないときはそのサービスワーカーが Chrome によって選択的に遮断されますが、他の方法で DOM を操作することは可能です。
詳細な説明: https://developer.chrome.com/docs/extensions/mv3/service_workers/
あまり複雑でない manifest 設定ファイルは次のようになります。
{
"manifest_version": 3,
"name": "Life Helper",
"version": "1.0.0",
"description": "私たちの生活で知っておくべきこと。",
"icons": {
"16": "icon.png",
"48": "icon.png",
"128": "icon.png"
},
"action": {
"default_popup": "popup.html",
"default_title": "ポップアップ"
},
"permissions": [
"scripting",
"bookmarks"
],
"background": {
"service_worker": "background.js"
},
"options_page": "options.html"
}
manifest.json
のフォーマットについては:https://developer.chrome.com/docs/extensions/mv3/manifest/
私たちが理解する必要があるのは次のことだけです。
-
permissions で有効にされた権限は、background.js で呼び出すことができる API に対応します。例えば、
bookmarks
は、chrome.runtimeの下のメソッドを使用できることを示します。 -
actions は主にポップアップウィンドウの位置や名前などを規定します。
- popup 拡張機能のアイコンをクリックしたときに表示されるページ
- popup 拡張機能のアイコンをクリックしたときに表示されるページ
-
background はサービスワーカーのホストオブジェクトに対応し、拡張機能のバックエンド / サーバーと理解できます。
-
contentScript はフロントエンドスクリプトの位置で、ここは直接 React のプログラムエントリ(app.tsx->index.tsx)に対応し、その後のすべてのロジックとスタイル(popup, options, newTab)は React の構成形式に従ってください。
開発プロセス#
各モジュールの役割は次のとおりです:
簡単に言えば、以前はバックエンドに任されていたすべての作業はbackground
が担当し、以前はフロントエンドに任されていたcontentScript
のoptions
, newTab
, popup
が担当します。
これは、状態管理を行いたい場合にも、原子性の原則に従って各自の状態(M)やスタイル(V)、タイプ(M)などを整理できることを意味します。
通信#
通信には明確な方向性はなく、ファイルやモジュールなどの制限もありません。必要に応じて使用します。
ただし、先に定義した各モジュールの大まかな作業範囲に基づいて、フロントエンドは通信時に各コンポーネントのスタイル、API 呼び出し、ユーザーイベントをコミュニケーションするのが最善であり、バックエンドは通信時にデータをより良く整理し、API を構築したり外部リクエストを実行したりすることを優先します。
基本的な形式は次のとおりです:
// メッセージを送信し、コールバック
chrome.runtime.sendMessage({greeting: "hello"})
.then(response => console.log(response.farewell))
.catch(error => console.error(error));
// メッセージを受信し、コールバック
chrome.runtime.onMessage.addListener(function(request, sender) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting == "hello") {
return Promise.resolve({farewell: "goodbye"});
}
});
メッセージの送信と受信はタブ ID をフィルタリングし、タイプを指定できます。例えば、popup から background にメッセージを送信し、現在のアクティブタブを指定したい場合:
グローバル状態管理とプラグインデータストレージ#
Redux Toolkit を使いましょう!
今日では、従来の Redux は推奨されておらず、新しい Redux Toolkit は、既存のモジュールをより良く統合するのに役立ち、pinia
のような使い方ができます:
私たちはまず全体を初期化し、先に述べた役割分担に基づいて、ここではバックエンド(つまり background モジュール)で初期化とサービスの構築を行うのが最善です。
//store.ts
import { configureStore } from '@reduxjs/toolkit';
import { slice1, slice2 } from './slices';
export default configureStore({
reducer: {
slice1: slice1.reducer,
slice2: slice2.reducer,
},
});
export default store;
それぞれの slice は次のように定義します:
import { createSlice } from '@reduxjs/toolkit';
// 初期値を定義
const initialState1 = {
value: 0,
};
// 最初のsliceを定義
export const slice1 = createSlice({
name: 'slice1',
initialState: initialState1,
reducers: {
increment1: state => {
state.value += 1;
},
decrement1: state => {
state.value -= 1;
},
},
});
export default slice1.reducer;
chrome.storage と組み合わせて状態を永続化#
ここでは、redux-persist-storage-chrome
とredux-persist
の 2 つのライブラリをインストールする必要があります。その後、次のように変更します:
store.ts
で次のように変更します:
import { configureStore } from '@reduxjs/toolkit'
import { chromeStorage } from 'redux-persist-storage-chrome';
import { persistReducer } from 'redux-persist';
import { slice1, slice2 } from './slices';
const persistConfig = {
key: 'chrome-extension-extended',
storage: chromeStorage,
}
export const store = configureStore({
reducer: {
slice1: persistReducer(persistConfig, slice1.reducer),
slice2: persistReducer(persistConfig, slice2.reducer),
},
})
export default store;
デバッグ#
HMR や他の形式のホットリロードを使用している場合、関心を持つべきことは background または contentScript 自体から発信されるメッセージだけです。
- background スクリプトを監視する方法:
chrome://extensions/
ページの拡張機能を直接クリックすると、サービスワーカーの単独デバッグウィンドウがポップアップします。
- options, popup または new tab などのページを監視する:
対応するページで右クリック->検査
を選択すると、単独のデバッグウィンドウがポップアップします。
まとめ#
この記事は、ブラウザ拡張機能に全く触れたことがない方々のための迅速なガイドです。実際、私もまだ始めたばかりですが、公式が多くのサンプルを提供してくれているおかげで、インターネット上にも多くの既存のチュートリアルやボイラープレートがあります。
予告#
次回は chrome-extension-boilerplate-react-vite プロジェクトの rollup と ws の組み合わせプロセスを研究する予定です。(これはもう拡張機能開発の範疇を超えています)
次回は他のブラウザの拡張機能と Vue3 での他のボイラープレートの使用を研究します。
(05/08 更新:)
antfu のブラウザ拡張テンプレートは非常に便利ですが、Firefox では動作しません。問題は web-ext で、Firefox ブラウザの manifestV3 のサポートはまだ不安定です。
(06/01 更新:)
コメント欄で Diy.God からブラウザ拡張専用の SDK(リソースの統合とパッケージ化を助けるエンジン)を推奨され、試してみたところ非常に使いやすかったです。plasmoは、上記で言及したすべてのボイラープレートテンプレートの機能をカバーできるので、おすすめです!
🧩 参考#
https://dev.to/anobjectisa/how-to-build-a-chrome-extension-new-manifest-v3-5edk