ブラウザ拡張機能のフレームワークWXTを使ってPopup画面を作る方法と、実践的な例としてRouterの活用を紹介します。
WXTでは、Popup、Background、Content Scriptのような機能ごとにエントリーポイントを分けます。
エントリーポイントは次のようにディレクトリを切っても切らなくてもよいです。
entrypoints/popup/index.ts
entrypoints/popup.ts
ディレクトリを用意していない場合は作りましょう。フロントエンドのフレームワークを使うと、App.tsx
やApp.svelte
なども一緒に置いたり、コンポーネントを別ファイルに切り分けることが多いためです。
Popup – WXT
エントリーポイントとなるHTMLファイルには、通常どおりマークアップするだけで問題ありません。
一応、テンプレートで作成されるHTMLファイルも記載しておきます。script
の中でフレームワークのマウント処理をするmain.ts
を読み込みます。
titleタグの中の変更だけはやってきましょう。titleタグにしていした文字は、ツールバーでアイコンをホバーした時のツールチップになります。
次の画像では「URL Copy Helper」の部分がtitleタグで指定した文字列です。
ブラウザ拡張のpopupには、画面サイズに限りがあります。
たとえば、Chrome拡張機能であれば25x25から800x600ピクセルの間と決まっています。
そうなると必然的に要素の表示・非表示の切り替えが必要になります。この切り替えはルーティングを使うと実装しやすいです。
通常のルーティングでは末尾を/login
、/about
のように変化させます。しかし、popupのURLはchrome://xxxxx/yyy.html
であり、ルートが/
ではなくhtml
になり、ルーティングの設計・実装がしづらくなってしまいます。
解決策は次のいずれかです(括弧内はReact Routerの機能)。
リダイレクトなどを用いて回避する方法もありますが、コードが読みにくくなってしまうため賢明ではないでしょう。
React RouterのMemoryRouter
を使い、ログインありの例を載せておきます。
まずは実際にMemoryRouter
を使ってルーティングするコンポーネントです。
ざっくりとした全体の構成は次のとおりです。
<AuthUser>
はログイン中かどうか管理するContextを提供<Layout />
は共通のレイアウトを定義<PrivateRoute />
を使い、未ログインのとき/login
へリダイレクト
繰り返しになりますが、popupの画面サイズには限りがあるため、コンポーネントの実装には注意が必要です。
ContextとProviderによりログイン状態を全体で共有するためのコンポーネントです。
ちょっと長い!
しかしやっていることは単純です。それぞれコメントに記載しました。
login
は、「ログイン」「Reactの状態変化」「storageなどへの記録」をまとめて実行する関数です。logout
も同様です。
このコンポーネントで定義しておいて、実際にログイン・ログアウトするコンポーネントで呼び出します。
ヘッダーやフッターのような共通のレイアウトがある場合はこのコンポーネントに書いておきます。
<Outlet />
にはネストされた<Route>
にて指定したコンポーネントが置き換わります。
たとえば次のようなイメージです。
続いて、ログインしていない時にリダイレクトさせるコンポーネントです。
Contextからログイン状態を取得します。
ログイン済みであればネストされた<Route>
にて指定したコンポーネントを返します。
一方、ログインしていなければ/login
にリダイレクトさせます。
さきほどのルーティングで使われている部分を見てみましょう。
/
や/setting
に遷移した際、未ログインなら/
にリダイレクトされますが、ログイン済みならそのまま/
や/setting
にアクセスできます。
よく使われていそうなReact Hook Formを想定して簡略化したログインコンポーネントです。
<AuthUser>
で定義したログイン関数を使った例です。
ポイントは次の2つです。
- 取得したログイン情報に応じて
/
へリダイレクト - ボタンを押したらログインして
/
へリダイレクト
参考:Authentication with React Router v6: A complete guide - LogRocket Blog
以上、WXTを使ったpopup画面の作り方と、実践的な例でした。
popupの画面で何でもかんでもやるのではなく、必要に応じてオプションページやcontent scriptを使いましょう。