Chrome Extensionsをwepback + TypeScriptで開発する
Blog
Info
webpackの代わりにViteを使う方法は、次のページを参照のこと。
Chrome Extensions を Vite + TypeScript で開発する
Chrome Extensions(以下、Chrome拡張)をTypeScriptで開発するためのwebpackの設定やファイル構成について記載しています。
この記事では、Chrome拡張の作り方については説明しません。作成に必要なファイルや作成したChrome拡張の読み込み方は、Chrome Extension - Getting Started Tutorialを参照してください。
動作を確認した環境
- Node.js v12.14.0
- TypeScript v3.8.3
- webpack v4.42.1
- TypeScript v3.8.3
プロジェクト作成
Chrome拡張のプロジェクトを作成します。
mkdir chrome-extension-sample && cd $_ npm init -y
webpackやwebpackのプラグインをインストールします。
npm install --save-dev webpack webpack-cli copy-webpack-plugin
TypeScriptや、TypeScriptをwebpackで利用するための
ts-loader
をインストールします。npm install --save-dev typescript ts-loader
Chromeの型定義をインストールします。
npm install --save-dev @types/chrome
ファイル構成
次のファイル構成となるように、必要なファイルを作成します。
.
├── node_modules
├── public # Chrome拡張に必要なファイル
│ ├── image
│ │ └── icon128.png # Chrome拡張のアイコン
│ └── manifest.json # Chrome拡張の設定ファイル
├── src # トライスパイル対象のファイル
│ └── background.ts # ブラウザ起動時に読み込まれるファイル
├── package.json
├── package-lock.json
├── tsconfig.json # TypeScriptの設定
└── webpack.config.js # webpackの設定
tsconfig.json
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"strict": true,
"rootDir": "src",
"esModuleInterop": true,
"typeRoots": [ "node_modules/@types"]
},
"exclude": [
"node_modules"
]
}
webpack.config.js
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
mode: process.env.NODE_ENV || "development",
entry: {
background: path.join(__dirname, "src/background.ts"),
},
output: {
path: path.join(__dirname, "dist/js"),
filename: "[name].js",
},
module: {
rules: [
{
test: /\.ts$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [".ts", ".js"],
},
plugins: [
new CopyPlugin([{ from: ".", to: "../" }], { context: "public" })
],
};
- トランスパイル対象のファイルを
entry
で指定します。 - トランスパイル後のJavaScriptファイルを
dist/js
の下に出力します。 CopyPlugin
を使って、「public」ディレクトリに置いたアイコンファイルやmanifest.json
をコピーします。
background.ts
今回は、選択した文字列をGoogle検索するコンテキストメニュー(右クリックしたときに開くメニュー)を実装します。
const openTab = (query?: string) => {
if(query) {
chrome.tabs.create({ url: `https://www.google.com/search?q=${query}` });
}
}
chrome.runtime.onInstalled.addListener((): void => {
chrome.contextMenus.create({
id: "sample",
title: "選択した文字列を検索する",
contexts: ["selection"]
});
});
chrome.contextMenus.onClicked.addListener((info, tab): void => {
openTab(info.selectionText);
});
manifest.json
{
"manifest_version": 2,
"name": "chrome-extension-sample",
"description": "A sample Chrome Extension.",
"version": "0.0.1",
"icons": { "128": "image/icon128.png" },
"background": {
"scripts": ["js/background.js"],
},
"permissions": ["contextMenus", "tabs"]
}
manifest.json
はwebpack実行時に「dist」ディレクトリの下にコピーされるので、各ファイルのパスは、「dist」ディレクトリからの相対パスを指定します。
ビルド
productionモードでビルドします。
npx webpack --mode production
ビルド後のファイル構成は次のようになります。
.
├── dist
│ ├── image
│ │ └── icon128.png
│ ├── js
│ │ └── background.js
│ └── manifest.json
├── node_modules
├── public
│ └── ... 略 ...
├── src
│ └── ... 略 ...
├── package-lock.json
├── package.json
├── tsconfig.json
└── webpack.config.js
動作確認
Chrome Extension - Getting Started Tutorialの記載の手順で、Chrome拡張を読み込みます。 読み込みするディレクトリは「dist」です。
新しくタブを開きます(既存のタブの場合は、リロードしてください)。
Webページの文字を選択し、右クリックします。「選択した文字列を検索する」をクリックします。
選択した文字についてGoogle検索した結果が新しいタブで表示されます。