Chrome拡張開発の入門資料は世の中にたくさんありますが、結構昔に書かれたものが多く、イマドキ風(といってもそんなに新しくもないですが笑)にTypeScriptを使った場合の開発方法を記しました。
なお、初心者の方向けに、簡単ではありますがChrome拡張の仕組みから説明していきます。
Chormeの拡張の仕組み
以下の3つの登場人物を覚えればOKです。
Content Scripts
ページのDOMを操作(取得・追加・更新・削除)できるscript。(3つの登場人物の中では唯一)
ただし、アクセスできるChromeのAPIは一部に制限されている。
これを使って特定のページに独自のUIを埋め込んだりできる。
Browser Action(Page Action)
アドレスバー右に並んでいる拡張機能のアイコンをクリックしたときのアクション。
様々なChromeのAPIにアクセスできる。
Event Page(Background Page)
Chromeが動いている間に裏で動いているスクリプト。
Browser Action同様、様々なChromeのAPIにアクセスできる。
Background Pageは非推奨。
三者はそれぞれメッセージでやり取りできます。
最小労力で作るChrome拡張
外部に公開しないミニマムなchrome拡張機能を作るのは1時間も使わずにできる
を見て、後は公式ドキュメントを見てください、以上。。
ではありますが、今回はちょっぴりナウい環境にしてみます。
条件はこんな感じです。
- TypeScriptを使いたい
- Promiseを使いたい
TypeScriptでChrome拡張を開発する
- generator-chrome-extension-kickstart-typescript→あまりメンテされておらず不安
- chrome-extension-typescript-starter→jQueryとmomentはいらないかな、、
最終的にこれぐらいなら自分で作っちゃおうというノリになりました。
必要なパッケージをインストール
yarn add webextension-polyfill-ts # Chrome APIでPromiseを使えるpolyfill
yarn add -D typescript webpack webpack-cli copy-webpack-plugin ts-node ts-loader @types/webpack @types/copy-webpack-plugin
一通りinit
yarn init
yarn tsc --init
ディレクトリ構成
├── package.json
├── public
│ ├── icon_32.png
│ └── manifest.json
├── src
│ └── content_scripts.ts
├── tsconfig.json
├── webpack.config.ts
└── yarn.lock
ビルド設定
import { ConfigurationFactory } from 'webpack'
import path from 'path'
import CopyWebpackPlugin from 'copy-webpack-plugin'
const config: ConfigurationFactory = () => {
return {
entry: {
content_scripts: path.join(__dirname, 'src', 'content_scripts.ts')
},
output: {
// distディレクトリにcontent_scripts.jsを吐く
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /.ts$/,
use: 'ts-loader',
exclude: '/node_modules/'
}
]
},
resolve: {
extensions: ['.ts', '.js']
},
plugins: [
// publicディレクトリにあるファイルをdistディレクトリにコピーする
new CopyWebpackPlugin([
{ from: 'public', to: '.' }
])
]
}
}
export default config
データをstorageに読み書きするcontent_scriptsのサンプル
import { browser } from 'webextension-polyfill-ts'
const execute = async () => {
const value = await browser.storage.local.get('date')
console.log(value.date || '日時が記録されていません')
await browser.storage.local.set({ date: new Date().toString() })
console.log('現在の日時を記録しました')
}
execute()
あとはyarn webpack
してdistディレクトリをChromeで読み込むだけ!
【余談】chrome.storage APIについて
拡張機能でデータを永続化したい場合、ブラウザのlocalStorageを使うこともできますが、
localStorageのスコープの問題がありややこしいです。
chromeのAPIとしてstorageが用意されており、key-value形式のデータを保存することができます。
ちなみに保存されたデータは~/Library/Application Support/Google/Chrome/Default/Local Extension Settings/{ExtensionのID}
で見ることができます。
(余談の余談ですが、拡張機能のコードは~/Library/Application Support/Google/Chrome/Default/Extensions/{ExtensionのID}/{Extensionのversion}
から見れます)
├── 000003.log
├── CURRENT
├── LOCK
├── LOG
└── MANIFEST-000001
000003.logを見ればなんとなくデータが書き込まれているのが確認できます。(LevelDBという形式らしいですが、僕はよくわかりません、、)
また、chrome.storage.local
でローカルのファイルにデータを保存することもできますが、chrome.storage.sync
でデータを同期することもできちゃいます!
【余談】jQuery不要説
Chrome拡張機能といえば、jQueryが使って開発されている例が非常に多く見られるのですが、個人的に昨今はjQueryの必要性がどんどん薄れてきているのかなと感じています。ECMAScriptの仕様が新しくなって配列操作など便利な機能や構文がどんどん増えています。
DOMのLoadを待ってからスクリプトを実行するといったような実行タイミングの制御も、Content Scriptsのrun_at
というフィールドを設定すれば簡単にできます。詳しくは公式ドキュメントを御覧ください。