はじめに
最近ブラウザの拡張機能を作りたいと思うようになり、いい感じのツールないかな?と思って探したところPlasmoというツールが良さそうだったので記事にしました!
なお、筆者はフロントエンドフレームワーク・TypeScript初心者で、ReactとVueのチュートリアルをかじった程度の人間です笑
Plasmoとは
- 公式サイト:Supercharge your browser extension development – Plasmo
- Plasmoはブラウザの拡張機能を簡単に開発できるフレームワークで、TypeScriptをサポート
-
First-class support for React, Svelte, Vue
と書かれており、既存のフロントエンドフレームワークとの相性も良いらしい? - Plasmoで開発した拡張機能からWebページに何かUIコンポーネントを追加する場合、Shadow DOMによってCSSがWebページに漏れることがなく、CSSの影響範囲が拡張機能に閉じられることも魅力の1つ
- ディレクトリ構造・ファイル名のルール、CLIのオプションによってChrome向け、Firefox向けのmanifest.jsonを自動生成してくれる。これが大変ありがたい!
- ドキュメントも充実しており、サンプルコード集のリポジトリもあるので、やりたいことをどう実現できるかのヒントが見つけやすい
早速使ってみる
インストール
- 今回の開発環境
- Ubuntu 24.04 LTS(WSL2)
- pnpm(Plasmoが推奨)
まずはpnpmをインストール。インストール手順はpnpm公式のものを参照してください。
$ sudo apt update && sudo apt upgrade
$ curl -fsSL https://get.pnpm.io/install.sh | sh -
$ curl -fsSL https://get.pnpm.io/install.sh | sh -
==> Downloading pnpm binaries 9.15.0
WARN using --force I sure hope you know what you are doing
Copying pnpm CLI from /tmp/tmp.ABo2bh01ys/pnpm to /home/username/.local/share/pnpm/pnpm
Appended new lines to /home/username/.bashrc
Next configuration changes were made:
export PNPM_HOME="/home/username/.local/share/pnpm"
case ":$PATH:" in
*":$PNPM_HOME:"*) ;;
*) export PATH="$PNPM_HOME:$PATH" ;;
esac
To start using pnpm, run:
source /home/username/.bashrc
$ source ~/.bashrc
$ pnpm --version
9.15.0
$ pnpm env add --global lts
Fetching Node.js 22.12.0 ...
Node.js 22.12.0 was installed
/home/username/.local/share/pnpm/nodejs/22.12.0
All specified Node.js versions were installed
$ pnpm env use --global lts
Node.js 22.12.0 was installed
/home//.local/share/pnpm/nodejs/22.12.0
Node.js 22.12.0 was activated
/home/username/.local/share/pnpm/node -> /home/username/.local/share/pnpm/nodejs/22.12.0/bin/node
$ node --version
v22.12.0
pnpmとnodeのインストールは完了。
次はplasmoのプロジェクトを作成する。
$ pnpm create plasmo
🟣 Plasmo v0.89.4
🔴 The Browser Extension Framework
🟡 Extension name: sample-extension
🟡 Extension description: A sample extension.
🟡 Author name: username
🔵 INFO | Creating new project with popup
🔵 INFO | Installing dependencies...
...
dependencies:
+ plasmo 0.89.4
+ react 18.2.0 (19.0.0 is available)
+ react-dom 18.2.0 (19.0.0 is available)
devDependencies:
+ @ianvs/prettier-plugin-sort-imports 4.1.1 (4.4.0 is available)
+ @types/chrome 0.0.258 (0.0.287 is available)
+ @types/node 20.11.5 (22.10.2 is available)
+ @types/react 18.2.48 (19.0.1 is available)
+ @types/react-dom 18.2.18 (19.0.2 is available)
+ prettier 3.2.4 (3.4.2 is available)
+ typescript 5.3.3 (5.7.2 is available)
WARN Issues with peer dependencies found
.
└─┬ plasmo 0.89.4
└─┬ @plasmohq/parcel-config 0.41.1
└─┬ @parcel/config-default 2.9.3
└─┬ @parcel/optimizer-htmlnano 2.9.3
└─┬ htmlnano 2.1.1
└── ✕ unmet peer svgo@^3.0.2: found 2.8.0
Done in 17.6s
🔵 INFO | Initializing git project...
🟠 WARN | git commit -m Created a new Plasmo extension exited with non-zero code: 128
🟢 DONE | Your extension is ready in: /home/username/sample-extension
To start hacking, run:
cd sample-extension
pnpm dev
Visit https://docs.plasmo.com for documentation and more examples.
$ ls -al
drwxr-xr-x 6 username username 4096 Dec 16 07:47 sample-extension
コマンド1つ実行するだけでプロジェクトが作成されます
中身はこのような感じ
$ ls -al
total 252
drwxr-xr-x 6 username username 4096 Dec 16 07:47 .
drwxr-x--- 6 username username 4096 Dec 16 07:47 ..
drwxr-xr-x 7 username username 4096 Dec 16 07:47 .git
drwxr-xr-x 3 username username 4096 Dec 16 07:46 .github
-rw-r--r-- 1 username username 344 Dec 16 07:46 .gitignore
-rw-r--r-- 1 username username 558 Dec 16 07:46 .prettierrc.mjs
-rw-r--r-- 1 username username 1520 Dec 16 07:46 README.md
drwxr-xr-x 2 username username 4096 Dec 16 07:46 assets
drwxr-xr-x 6 username username 4096 Dec 16 07:47 node_modules
-rw-r--r-- 1 username username 691 Dec 16 07:47 package.json
-rw-r--r-- 1 username username 207117 Dec 16 07:47 pnpm-lock.yaml
-rw-r--r-- 1 username username 528 Dec 16 07:46 popup.tsx
-rw-r--r-- 1 username username 274 Dec 16 07:46 tsconfig.json
動作確認
$ pnpm dev
これを実行するとプロジェクト内のbuildディレクトリにビルド対象ごとのディレクトリが作成されます。
$ ls build
chrome-mv3-dev
デフォルトではChrome向けにビルドされるようなので、生成されたディレクトリをChromeで読み込みます。
すると、今回作成した拡張機能がChromeで識別されます。
ピン留めして拡張機能のアイコンをクリックすると・・・
表示された!
これはプロジェクトディレクトリ内に生成されたpopup.tsx
のおかげです。
$ cat popup.tsx
import { useState } from "react"
function IndexPopup() {
const [data, setData] = useState("")
return (
<div
style={{
padding: 16
}}>
<h2>
Welcome to your{" "}
<a href="https://www.plasmo.com" target="_blank">
Plasmo
</a>{" "}
Extension!
</h2>
<input onChange={(e) => setData(e.target.value)} value={data} />
<a href="https://docs.plasmo.com" target="_blank">
View Docs
</a>
</div>
)
}
export default IndexPopup
ちなみに生成されたmanifest.jsonはこんな感じ。
{"icons":{"16":"icon16.plasmo.9f44d99c.png","32":"icon32.plasmo.83dbbbab.png","48":"icon48.plasmo.a78c509e.png","64":"icon64.plasmo.15206795.png","128":"icon128.plasmo.c11f39af.png"},"manifest_version":3,"action":{"default_icon":{"16":"icon16.plasmo.9f44d99c.png","32":"icon32.plasmo.83dbbbab.png","48":"icon48.plasmo.a78c509e.png","64":"icon64.plasmo.15206795.png","128":"icon128.plasmo.c11f39af.png"},"default_popup":"popup.html"},"version":"0.0.1","author":"username","name":"DEV | Sample extension","description":"A sample extension","host_permissions":["https://*/*"],"background":{"service_worker":"plasmo-default-background.5fdd9bcb.js"},"content_security_policy":{"extension_pages":"script-src 'self' http://localhost;object-src 'self';"},"web_accessible_resources":[{"matches":["<all_urls>"],"resources":["__plasmo_hmr_proxy__"]}]}
プロジェクトを生成してビルドしただけなのにここまでやってくれる!
めちゃくちゃ簡単に作れますね!
おわりに
日常の作業をいい感じにできるといいですね!