Chrome拡張機能をTypeScriptで作るためのテンプレートを作った

2021年6月9日

お仕事でChromeの拡張機能を作りました。
その時はJavaScriptで作ったんですが、以前からTypeScriptで何か作りたいなと思っていたので、とりあえずテンプレートでも準備しておこうと思った次第です。

もちろん、テンプレート用意しました。
こちらにあります。
よかったらスターお願いします!

あと、テンプレートを作るにあたってこちらのリポジトリを参考にさせていただきました。ありがとうございました。

今回のゴール

Chrome拡張機能をTypeScriptで快適に開発できる環境を整えるというのが今回の目標でした。
快適にという部分ですが、ホットリロード機能とTypeScriptのコードそのままでデバッグできるようにする。
これは個人的に絶対に必要な条件でした。

ホットリロードとデバッグ

ホットリロードがない時

①コード書きます。保存します。
②npm run devみたいな感じでビルド出します。
③chromeの拡張機能を更新。以下の更新ボタン

こんな手順を毎回踏まないといけないわけです。
開発中だと頻繁に修正とかしてデバッグするのでキツイ。

ホットリロードがある時

初回起動時に以下やっておく必要があります。

①npm run watchしとく
② chromeの拡張機能を更新ボタンを押しておく

次回以降

コード書きます。保存します。

これで終わり。
勝手にchrome拡張機能が再読み込みされ、開いているブラウザのページも再読み込みされる。

ただ、自分だけかわからないですが、ごく稀に変更が反映されていないことがあった。

そんな時は、一度ホットリロードがない時の手順をやってみる。
そうするとうまくいった。

TypeScriptのコードそのままでブレークポイント設定してデバッグする。

これをどうやったらいいのかチンプンカンプンでした。
しかし、頑張った結果うまくいきました。
ただ、Chromeの開発者ツールでデバッグする方法となります。

でも、開発自体はVisual Studio Codeでやっていました。

なので、可能ならDebugger for Chromeを使ってデバッグしたかったわけです。

ただ、説明を 読んでいると
Chromeの拡張機能はサポートしてへんで とある。

なのですぐに諦めた。

よってChromでデバッグすることにしました。

以下のようにブレークポイントをTypeScriptのコード上で設定することができます。

あと、これはChromeのデバッガの使い方よりの話になるんですが、目的のファイルをどうやって見つけるかというのが問題になります。

デバッガ上でCtrl + Oを押すと、ソース検索のダイアログが出てくる。
ここにファイル名を入力したら一発で出てきます。

これ知った時は衝撃でした。
それまではdebuggerとかを仕込んで、ブレークさせてファイルを見つけていました。。。

TypeScriptの環境構築について

環境構築、ほんとうに苦労しました。
というか、環境構築で苦労しなかった試しがほぼない。。。

何に苦労したかというと
tsconfigの設定
webpackの設定
デバッグのやり方調査

途中までbabelの設定が必要かと思ってましたが、なくてもいけました。
なので、テンプレートではbabel自体消してます。

package.json

以下2021/06/14時点のpackage.jsonです。
もしかしたら今後変更してブログの更新忘れるかもしれないので、念のため変更がないかGitHubのソースを確認して頂ければと思います。

{
  "name": "chrome-extension-template",
  "repository": "https://github.com/xiaotiantakumi/chrome-extension-template.git",
  "author": "takumi oda",
  "license": "MIT",
  "scripts": {
    "dev": "webpack --config webpack.dev.js",
    "watch": "webpack --config webpack.dev.js --watch",
    "prod": "webpack --config webpack.prod.js",
    "release": "node release $1"
  },
  "devDependencies": {
    "@types/chrome": "^0.0.144",
    "bestzip": "^2.1.7",
    "clean-webpack-plugin": "^3.0.0",
    "copy-webpack-plugin": "^6.1.0",
    "core-js": "^3.6.5",
    "css-loader": "^3.6.0",
    "jest": "^26.4.2",
    "mkdirp": "^1.0.4",
    "npm-run-all": "^4.1.5",
    "regenerator-runtime": "^0.13.7",
    "rimraf": "^3.0.2",
    "sass": "^1.26.10",
    "sass-loader": "^9.0.3",
    "style-loader": "^1.2.1",
    "ts-loader": "^8.2.0",
    "typescript": "^4.3.2",
    "webpack": "^4.44.1",
    "webpack-cli": "^3.3.12",
    "webpack-extension-reloader": "^1.1.4",
    "webpack-merge": "^5.1.4"
  },
  "dependencies": {
    "axios": "^0.21.1",
    "moment": "^2.27.0"
  }
}

スクリプトは参考にさせていただいたリポジトリのままとなっています。
使い方は簡単で、開発するときは
・npm run dev
・npm run watch
これら二つのどちらかを使うと思います。

ホットリローダーのおかげでnpm run watchのほうがよく使うと思いますが、なんか調子悪いなーとかなったらnpm run devしてください。

dependenciesには私もよく使うaxiosとmomentが入っていたのでそのままにしています。不要であればnpm uninstall axios moment なりしてもらえれば。

こちらをテンプレートにする場合
name
repository
author
を変えればOKです。
あと、manifestにもこのような情報があるので合わせて変更してください。

webpack.js

こちらの変更は
・Entryファイルをtsに変更する
・moduleのrulesにts-loaderの定義を追加
・ resolveにtsファイルを追加
となりました。

const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");

module.exports = {
  entry: {
    content: './src/content.ts',
    background: './src/background.ts',
    options: './src/options.ts',
  },
  plugins: [
    new CleanWebpackPlugin(),
    new CopyPlugin({
      patterns: [
        { from: 'src/manifest.json' },
        {
          from: 'src/assets',
          globOptions: {
            ignore: [
              '**/stylesheets/**',
            ],
          },
        },
        { from: 'src/options.html' },
      ]
    }),
  ],
  output: {
    path: `${__dirname}/dist`,
    filename: '[name].js',
  },
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        loader: 'ts-loader',
        exclude: /node_modules/
      },
      {
        test: /\.s[ac]ss$/i,
        use: [
          // Creates `style` nodes from JS strings
          'style-loader',
          // Translates CSS into CommonJS
          'css-loader',
          // Compiles Sass to CSS
          'sass-loader',
        ],
      },
    ],
  },
  watchOptions: {
    ignored: /node_modules/,
  },
  resolve: {
    extensions: [".js", ".ts"]
  },
};

tsconfig.json

こちらについては別段解説するほどの内容もなければ知識もないです。
一つだけ言うとすれば、デバッグするためにsourceMapをtrueにしないとね!
ということくらいでしょうか。

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": false,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "noEmit": false,
    "sourceMap": true,
  },
  "include": ["src"],
  "exclude": ["build", "node_modules","dist","**/*.spec.ts"]
}

他に実現したいこと

chrome manifest v3に対応させる

これ単純に対応するだけならそこまで難しくないんです。
でも今使っているホットリロードのライブラリが、v3対応に伴って使えなくなってしまう。

フォークされているリポジトリを見てみると、webpack5対応とかしてるのは見つけたんですが、v3対応みたいなのはない気がする。

ちなみに、イシューもあがっているので、もーしかしたら修正してもらえるかも。。?

ただ、見た感じ2年程更新途絶えているので・・・あ・・・

react用とかvue用のテンプレートも作りたい

reactはたぶん作ると思います。ただ海外のサイトだったりリポジトリ探してみると結構あった。
jsxで書いてというのがよさそうなので。