LoginSignup
4
3

More than 1 year has passed since last update.

Chrome拡張機能を React x TypeScript で作るための環境構築した

Posted at

Webpackを使ってReactとTypeScriptをつかったChrome拡張機能の環境を作ってみたのでシェア。

webpackのバージョンは5系を使用。manifest.jsonのバージョンは3系。

成果物

なんの変哲もないどこにでもありふれたカウントアップの拡張機能です。これをReact(TS)からコンパイルして生成しています。

countup.gif

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について

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拡張機能のファイルに合わせました。

webpack.config.ts
  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という名前でファイルが生成される)

webpack.config.ts
  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について

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ファイルもビルド後のファイル構成に合わせたファイル名で設定しておきました。

manifest.json
  "background": {
    "service_worker": "/background.js"
  },
manifest.json
  "action": {
    "default_popup": "/index.html",
    "default_icon": {
      "32": "/src/assets/earth-32px.png",
      "48": "/src/assets/earth-48px.png"
    }
  },

components/popup/PopUp.tsxについて

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について

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 が生成されました。

スクリーンショット 2021-11-10 14.49.20.png

ChromeExtensionをChrome拡張機能ページでアップロード

スクリーンショット 2021-11-10 14.48.03.png

アップロードすると background 側のスプリクトでインストール直後にタブを開いて index.html を表示させるようにしています。

スクリーンショット 2021-11-10 14.54.22.png

GitHubリポジトリ: https://github.com/yoshisansan/chrome-extension-react-ts-boiler

4
3
1

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
4
3