簡単なアウトプットした。Chrome Extensions(拡張機能)編

# 簡単なアウトプット:Chrome Extensions(拡張機能)編

## まえがき

早速ですが、Chrome Extensions(以下、拡張機能と記載)を作成してみました。

作成理由としては以下のとおりです。

- いままで作成してみよう、と思っていたのですが食わず嫌いで手をつけていませんでした。
この機会に調べて見たくなったから。

- 非常に手軽に、かつ無料でアウトプットできるので、初学者含めて万人に参考になりうる記事がかけるとと思ったから。

- 実際に地味に困ったことがあったので、解決したくなったから。

## 準備

拡張機能を作成するにあたり以下を準備する必要があります。

- GoogleChrome

## 作成

実際に作成していきます。
主な参考は、公式のサイトを見ていきます。

<https://developer.chrome.com/docs/extensions/get-started?hl=ja>

※２−３年前に拡張機能を作成しようとした際は、公式ドキュメント含めて記事がほとんどなかった記憶です。
この数年に充実しました。

基本的に`manifest.json`を用意すれば、最低限のものは作成可能です。
しかしそれだと何もできないです。

例えば、hello worldをポップアップで表示するには、以下の様に用意します。
※公式サイト引用

- `manifest.json`
- `hello.html`

中身はそれぞれ、

```json
{
  "manifest_version": 3,
  "name": "Hello Extensions",
  "description": "Base Level Extension",
  "version": "1.0",
  "action": {
    "default_popup": "hello.html",
    "default_icon": "hello_extensions.png"
  }
}
```

```html
<html>
  <body>
    <h1>Hello Extensions</h1>
  </body>
</html>
```

拡張機能のアクション アイコン（ツールバー アイコン）をクリックすると、ポップアップが表示されるようになります。

## 自分のほしい機能を作成する

さて今回、この拡張機能を作成し、自分の欲しい物を作ります。

それは、AWSの「リージョンわかるくん」です。

AWSを利用するにあたり、意識しなければいけないことにリージョン（＝地域）というものがあります。
ざっくりいうと、AWSは各サービス（S3とかLambdaとか）を利用するときに、どのリージョンのものを利用するかと
設定しなければなりません。

例えば、TokyoのLambdaを設定しはじめた場合
OhioのLambdaを開いても何も表示されません。

この様にリージョンは大事なものです。

しかし、AWSを触っているうちにいつの間にかTokyoのリージョンにしていたつもりが
Oregonになっていたという経験がしばしばあります。

※みなさんはこういう経験がないかもしれませんが、私にはあります。

ということで、特定のリージョンを選択しているときに背景色を変えて
今どのリージョンを触っているかをわかるようにしました。

![スクリーンショット 2023-12-18 22.40.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307585/3f4a8477-8e9e-a680-96d1-a6386f14b227.png)


### 構成

- `manifest.json`
- `popup.html`
  - `css/styles.css`
- `js/content.js`
- `js/popup.js`

### 動きの解説

ファイルの中身は以下に提示しますが、まずはどのファイルがどの様に動いているかを提示します。

- `popup.html`にて、各リージョンに設定したい色を決めます。例えば、Tokyoは赤とか。すると、それを`popup.js`が取得して、`chrome.storage.local.`に保存します。
- `content.js`は、ブラウザ上のリージョンが記載されている部分からリージョン名を取得して、先程設定した色をブラウザ上に設定します。

各コードはコチラ。

- `manifest.json`

```json
{
  "name": "watch_region!!",
  "version": "1.0.0",
  "manifest_version": 3,
  "author": "nu0640042@gmail.com",

  "description": "FOR JAPANESE ONLY. AWSのリージョンを監視する拡張機能です",
  "permissions": ["storage"],
  "action": {
    "default_popup": "popup.html"
  },
  "content_scripts": [
    {
      "matches": ["https://*.aws.amazon.com/*"],
      "js": ["js/content.js"],
      "run_at": "document_end",
      "all_frames": true
    }
  ]
}
```

- `popup.html`

```html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="css/styles.css" />
    <title>Watch Region</title>
  </head>
  <body>
    <h1>好きな色を選ぶんじゃ!!</h1>
    <form>
      <div class="input-container">
        <label for="colorPickerTokyo">東京(TOKYO):</label>
        <input type="color" id="colorPickerTokyo" name="TOKYO_color" />
        <button class="clear-btn" data-target="colorPickerTokyo">クリア</button>
      </div>

      <div class="input-container">
        <label for="colorPickerUSEast1">バージニア北部(us-east-1):</label>
        <input type="color" id="colorPickerUSEast1" name="us-east-1_color" />
        <button class="clear-btn" data-target="colorPickerUSEast1">
          クリア
        </button>
      </div>

      <div class="input-container">
        <label for="colorPickerUSEast2">オハイオ(us-east-2):</label>
        <input type="color" id="colorPickerUSEast2" name="us-east-2_color" />
        <button class="clear-btn" data-target="colorPickerUSEast2">
          クリア
        </button>
      </div>

      <div class="input-container">
        <label for="colorPickerUSWest1">北カリフォルニア(us-west-1):</label>
        <input type="color" id="colorPickerUSWest1" name="us-west-1_color" />
        <button class="clear-btn" data-target="colorPickerUSWest1">
          クリア
        </button>
      </div>

      <div class="input-container">
        <label for="colorPickerUSWest2">オレゴン(us-west-2):</label>
        <input type="color" id="colorPickerUSWest2" name="us-west-2_color" />
        <button class="clear-btn" data-target="colorPickerUSWest2">
          クリア
        </button>
      </div>

      <button type="submit">保存</button>
      <div class="note">※保存するとブラウザが更新されます</div>
    </form>
    <script src="js/popup.js"></script>
  </body>
</html>

```

- `css/styles.css`

```css
body {
    font-family: 'Arial', sans-serif;
    padding: 10px;
    background-color: #f5f5f5;
}

form {
    background-color: #fff;
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    max-width: 300px;
    margin: auto;
}

.input-container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 10px;
}

label {
    flex: 1;
    margin-right: 10px;
    font-size: 14px;
    font-weight: bold;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

input[type="color"] {
    flex: 0 0 40px;
}

button {
    display: block;
    width: 100%;
    padding: 10px;
    background-color: #4285f4;
    color: #fff;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    transition: background-color 0.3s;
}

button:hover {
    background-color: #357abf;
}

.clear-btn {
    width: auto;
    background-color: #4285F4;
    /* Googleのブルー */
    color: white;
    border: none;
    border-radius: 4px;
    padding: 5px 10px;
    cursor: pointer;
    margin-left: 10px;
}

.clear-btn:hover {
    background-color: #357ABD;
    /* 暗いブルー */
}
.note {
    font-size: 10px;
    color: #ff0000;
    margin-top: 10px;
    border-radius: 4px;
}
```

- `js/content.js`

```javascript
const REGIONS = {
  TOKYO: "ap-northeast-1",
  VIRGINIA: "us-east-1",
  OHIO: "us-east-2",
  CALIFORNIA: "us-west-1",
  OREGON: "us-west-2",
};


function findMatchingRegion(url) {
    for (let regionName in REGIONS) {
        if (url.includes(REGIONS[regionName])) {
            return regionName;
        }
    }
    return false;
}

const currentURL = window.location.href;
const matchedRegion = findMatchingRegion(currentURL);

chrome.storage.local.get(
  [
    "TOKYO_COLOR",
    "VIRGINIA_COLOR",
    "OHIO_COLOR",
    "CALIFORNIA_COLOR",
    "OREGON_COLOR",
  ],
  function (result) {
    if (matchedRegion) {
      let colorKey = `${matchedRegion}_color`.toUpperCase();
      if (result[colorKey]) {
        const container = document.getElementById("h");
        const newDiv = document.createElement("div");

        newDiv.style.height = "5px";
        newDiv.style.backgroundColor = result[colorKey];
        container.parentNode.insertBefore(newDiv, container);
      }
    }
  }
);

```

- `js/popup.js`

```javascript
const DEFAULT_COLOR = "#F2F3F3";

// ページが読み込まれたときに実行
document.addEventListener("DOMContentLoaded", function () {
  // カラー情報をストレージから取得
  chrome.storage.local.get(
    [
      "TOKYO_COLOR",
      "VIRGINIA_COLOR",
      "OHIO_COLOR",
      "CALIFORNIA_COLOR",
      "OREGON_COLOR",
    ],
    function (result) {
      document.getElementById("colorPickerTokyo").value =
        result.TOKYO_COLOR || DEFAULT_COLOR;
      document.getElementById("colorPickerUSEast1").value =
        result.VIRGINIA_COLOR || DEFAULT_COLOR;
      document.getElementById("colorPickerUSEast2").value =
        result.OHIO_COLOR || DEFAULT_COLOR;
      document.getElementById("colorPickerUSWest1").value =
        result.CALIFORNIA_COLOR || DEFAULT_COLOR;
      document.getElementById("colorPickerUSWest2").value =
        result.OREGON_COLOR || DEFAULT_COLOR;
    }
  );
});

document.querySelector("form").addEventListener("submit", function (event) {
  event.preventDefault(); // フォームのデフォルトの送信動作を防ぐ

  // 各カラーピッカーの値を取得
  let tokyoColor = document.getElementById("colorPickerTokyo").value;
  let useast1Color = document.getElementById("colorPickerUSEast1").value;
  let useast2Color = document.getElementById("colorPickerUSEast2").value;
  let uswest1Color = document.getElementById("colorPickerUSWest1").value;
  let uswest2Color = document.getElementById("colorPickerUSWest2").value;

  // 値をchrome.storage.localに保存
  chrome.storage.local.set({
    TOKYO_COLOR: tokyoColor,
    VIRGINIA_COLOR: useast1Color,
    OHIO_COLOR: useast2Color,
    CALIFORNIA_COLOR: uswest1Color,
    OREGON_COLOR: uswest2Color,
  });

  chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
    let currentTab = tabs[0];
    // アクティブなタブをリロード
    chrome.tabs.reload(currentTab.id);
  });
});

```

## ローカル環境での設定の仕方

- `chrome://extensions/`をchromeのURLの部分に貼り付けエンター
- 右上の`デベロッパーモード`を有効化
- `パッケージ化されていない拡張機能を読み込む`で作成したファイルを選択

もうちょっとコード少なくできると思いますが、それでもこれだけの量で設定することができました。
取り合えず、htmlとJavaScript、CSSかけばいい感じにできそうです。

サクッと作成できて面白いので、今後もいろいろと作成してみようと思います。