203
157

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TypeScriptで作るイマドキChrome拡張機能開発入門

Last updated at Posted at 2020-02-21

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拡張機能の構造のーとより

三者はそれぞれメッセージでやり取りできます。

最小労力で作るChrome拡張

外部に公開しないミニマムなchrome拡張機能を作るのは1時間も使わずにできる

を見て、後は公式ドキュメントを見てください、以上。。
ではありますが、今回はちょっぴりナウい環境にしてみます。
条件はこんな感じです。

  • TypeScriptを使いたい
  • Promiseを使いたい

TypeScriptでChrome拡張を開発する

最終的にこれぐらいなら自分で作っちゃおうというノリになりました。

必要なパッケージをインストール

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のサンプル

content_scripts.ts
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形式のデータを保存することができます。

chrome.storage

ちなみに保存されたデータは~/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というフィールドを設定すれば簡単にできます。詳しくは公式ドキュメントを御覧ください。

203
157
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
203
157

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?