Webpackを使ってReactとTypeScriptをつかったChrome拡張機能の環境を作ってみたのでシェア。
webpackのバージョンは5系を使用。manifest.jsonのバージョンは3系。
成果物
なんの変哲もないどこにでもありふれたカウントアップの拡張機能です。これをReact(TS)からコンパイルして生成しています。
GitHubリポジトリ: https://github.com/yoshisansan/chrome-extension-react-ts-boiler
ファイル構成
src
assets
earth-32px.png
earth-48px.png
background
background.ts
components
popup
PopUp.tsx
styles
popup.css
App.tsx
popup.html
manifest.json
package.json
tsconfig.json
webpack.config.ts
今回は
webpack.config.ts
manifest.json
PopUp.tsx
background.ts
の中身だけを解説します。
他は リポジトリ をみてもらえれば。
ビルドを生成すると ChromeExtensionFile という名前で拡張機能のファイルが生成されます。
webpack.config.tsについて
import * as path from 'path'
import HtmlWebPackPlugin from 'html-webpack-plugin'
import CopyPlugin from 'copy-webpack-plugin'
import { Configuration as WebpackConfiguration } from "webpack"
import { Configuration as WebpackDevServerConfiguration } from "webpack-dev-server"
interface Configuration extends WebpackConfiguration {
devServer?: WebpackDevServerConfiguration;
}
const config: Configuration = {
mode: "development",
entry: {
popup: `${__dirname}/src/App.tsx`,
background: `${__dirname}/src/background/background.ts`,
},
devtool: "inline-source-map",
module: {
rules: [
{
test: /\.(tsx|ts)?$/,
use: {
loader: "ts-loader",
options: {
configFile: path.resolve(__dirname, 'tsconfig.json'),
},
},
exclude: /node_modules/,
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.css$/,
use: [
"style-loader",
{
loader: "css-loader",
options: { url: false }
}
]
},
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
},
],
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js", ".jsx"],
alias: {
"components*": path.resolve(__dirname, "src/components*"),
},
},
output: {
filename: "[name].js",
path: `${__dirname}/ChromeExtensionFile`,
},
plugins: [
new HtmlWebPackPlugin({
template: '/src/popup.html',
}),
new CopyPlugin({
patterns: [
{ from: "./src/assets/earth-48px.png", to: "./src/assets/" },
{ from: "./src/assets/earth-32px.png", to: "./src/assets/" },
{ from: "./manifest.json", to: "./" }
]
})
],
target: ["web", "es5"],
}
export default config;
entryポイントを複数作ってentrポイントごとにファイルを生成してChrome拡張機能のファイルに合わせました。
entry: {
popup: `${__dirname}/src/App.tsx`,
background: `${__dirname}/src/background/background.ts`,
},
省略
output: {
filename: "[name].js",
path: `${__dirname}/ChromeExtensionFile`,
},
コンパイルしたJSファイルと一緒になったHTMLファイルを出力したいので HtmlWebPackPlugin をつかって HTML もコンパイルします。(index.htmlという名前でファイルが生成される)
plugins: [
new HtmlWebPackPlugin({
template: '/src/popup.html',
}),
new CopyPlugin({
patterns: [
{ from: "./src/assets/earth-48px.png", to: "./src/assets/" },
{ from: "./src/assets/earth-32px.png", to: "./src/assets/" },
{ from: "./manifest.json", to: "./" }
]
})
],
manifest.jsonについて
{
"name": "Hello World",
"description" : "Chrome拡張機能のテストアプリ",
"version": "1.0.1",
"manifest_version": 3,
"background": {
"service_worker": "/background.js"
},
"permissions": ["storage", "activeTab", "scripting"],
"action": {
"default_popup": "/index.html",
"default_icon": {
"32": "/src/assets/earth-32px.png",
"48": "/src/assets/earth-48px.png"
}
},
"icons": {
"32": "/src/assets/earth-32px.png",
"48": "/src/assets/earth-48px.png"
}
}
backgroundファイルもpopupファイルもビルド後のファイル構成に合わせたファイル名で設定しておきました。
"background": {
"service_worker": "/background.js"
},
"action": {
"default_popup": "/index.html",
"default_icon": {
"32": "/src/assets/earth-32px.png",
"48": "/src/assets/earth-48px.png"
}
},
components/popup/PopUp.tsxについて
import React, {VFC, useState} from 'react'
const PopUp: VFC = () => {
const [plus, setPlus] = useState<number>(0);
return (
<div>
<h1>ReactTS Boilerplate</h1>
<h2>カウンター</h2>
<button onClick={() => setPlus(plus + 1)}>{plus}</button>
</div>
)
}
export default PopUp;
特に珍しくもないuseStateをつかったカウントアップです。これをApp.tsxで読み込んでレンダリングさせています。
background.tsについて
chrome.runtime.onInstalled.addListener(async () => {
const url = chrome.runtime.getURL("index.html");
const tab = await chrome.tabs.create({ url });
console.log(`タブのID:${tab.id}`);
});
background.tsの動作確認として拡張機能をアップロードしたら新しいタブが開かれて index.html ファイルが読み込まれるようにしています。
yarn add -D @types/chrome
によりchromeオブジェクトの型ファイルもインストールしています。
ビルドしてみよう
yarn build
することによって ChromeExtensionFile が生成されました。
ChromeExtensionをChrome拡張機能ページでアップロード
アップロードすると background 側のスプリクトでインストール直後にタブを開いて index.html を表示させるようにしています。
GitHubリポジトリ: https://github.com/yoshisansan/chrome-extension-react-ts-boiler