【初心者】chrome拡張をTypeScriptで開発するときのWebpackの設定

私はchrome拡張、TypeScript初心者です。間違いなどありましたら教えていただけるとありがたいです。

# chrome-extension-typescript-starter

[chrome-extension-typescript-starter](https://github.com/chibat/chrome-extension-typescript-starter)こちらで簡単に始められるようでした。

こちらのwebpackの設定がかなり参考になりました。

# (たぶん)最小構成

開いているページのリンクをリスト表示するだけの拡張機能を作ってみます。

私が最終的に作成したコードはこちらです

- https://github.com/okumurakengo/webpack-ts-chromeext

```bash
yarn add -D webpack webpack-cli copy-webpack-plugin typescript ts-loader @types/webpack @types/chrome
```

```sh:フォルダ構成
.
├── package.json
├── public
│   ├── icon.png
│   ├── manifest.json
│   └── popup.html
├── src
│   ├── content.ts
│   └── popup.ts
├── tsconfig.json
├── webpack.config.js
└── yarn.lock
```

```webpack.config.js
const CopyPlugin = require("copy-webpack-plugin");

/**
 * @type import("webpack").Configuration
 */
module.exports = {
    mode: process.env.NODE_ENV || "development",
    devtool: "inline-source-map",
    entry: {
        popup: `${__dirname}/src/popup.ts`,
        content: `${__dirname}/src/content.ts`,
    },
    module: {
        rules: [
            {
                test: /\.ts$/,
                use: "ts-loader",
                exclude: /node_modules/
            },
        ],
    },
    resolve: {
        extensions: [".ts", ".js"]
    },
    plugins: [
        // publicフォルダに、manifest.jsonやicon.pngを置いたので、
        // それが一緒に./distフォルダに吐き出されるようにする
        new CopyPlugin([
            { from: "./public", to: "./" }
        ]),
    ]
}
```

```tsconfig.json
{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es6",
        "strict": true,
        "rootDir": "src",
        "allowJs": true,
        "esModuleInterop": true
    }
}
```

1. popupを開いたときに、アクティブなタブにメッセージを送り、
1. ページ内で取得したURLをpopup.jsに送り返す

という動作にするため、`permissions`で`tabs`の権限をつけました

```public/manifest.json
{
    "manifest_version": 2,
    "name": "sample",
    "version": "1.0",

    "content_scripts": [
        {
            "matches": [
                "<all_urls>"
            ],
            "js": [
                "content.js"
            ]
        }
    ],

    "browser_action": {
        "default_icon": {
            "16": "icon.png"
        },
        "default_popup": "popup.html"
    },

    "permissions": [
        "tabs"
    ]
}
```

```public/popup.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>My Extension</title>
    <style>
        body {
            min-width: 300px;
        }
    </style>
</head>
<body>
    このページのリンクのリスト
    <ul id="lists"></ul>
    <script src="popup.js"></script>
</body>
</html>
```

```src/popup.ts
// popupが開かれたときに、content.jsへメッセージを通知
chrome.tabs.query({ currentWindow: true, active: true }, ([ tab ]: chrome.tabs.Tab[]) => {
    chrome.tabs.sendMessage(tab.id as number, {});
});

// content.jsから送信されてきたメッセージを取得
const lists: HTMLUListElement = <HTMLUListElement>document.getElementById("lists")
chrome.runtime.onMessage.addListener(({ urlList }) => {
    lists.innerHTML = urlList.map((url: string) => `<li>${url}</li>`).join("");
})
```

```src/content.ts
const links: HTMLCollectionOf<HTMLAnchorElement> = document.getElementsByTagName("a")

// popup.jsからメッセージを受け取って、ページ内で取得したデータを送り返す
chrome.runtime.onMessage.addListener(() => {
    chrome.runtime.sendMessage({ urlList: [...links].map((a: HTMLAnchorElement) => a.href)});
});
```

この状態で `yarn webpack` とすると、`./dist` ディレクトリに全てのファイルが設置されます

`./dist`を指定して、`chrome://extensions/` から読み込むと作成した拡張機能が使えます。

<img width="671" alt="Screen Shot 2019-09-16 at 19.34.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142910/6506fe08-47d7-d5db-eb91-7d1fea5c08eb.png">

開いているページ内の全てのリンクをみれる拡張機能をTypeScriptで作成することができました。

<img width="1131" alt="Screen Shot 2019-09-16 at 19.37.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142910/32ce286a-1143-926f-19f4-f84bd2e36e1a.png">

---

最後まで読んでいただいてありがとうございました。m(_ _)m