sugiken のメモ帳

SBI証券のUIに不満があったので久々にChrome拡張作った

開発TypeScript

何を作ったか

SBI証券 クイックメニュー というのを作った

SBI 証券の画面上部に「クイックメニュー」ボタンを追加し、ホバーするとメニューが出てくる。
よく使うページをユーザーが設定することもできる。

なぜ作ったか

SBI 証券のサイト構造が複雑すぎる。
SBI と楽天でよく比較がされるが、大体楽天のほうがUIやサイトの使いやすさは良いと言われることが多いが、自分は SBI が好きなのでどうにかしたいと思った

どう作ったか

Chrome 拡張を作るのは久々だった。最後に作ったのは数年前で、jQuery で DOM をゴリゴリいじる感じで作っていた。手続き的な書き方でカオスになりがちだったので、今回は React を使うことにした。

使ったライブラリ

ざっと書くとこんな感じ

  • React
  • @extend-chrome/storage
  • typescript
  • webpack

構造

大きく分けると2つ。

manifest.json はこんな感じ

{
  "manifest_version": 3,
  "name": "SBI証券 クイックメニュー",
  "version": "1.6",
  "description": "SBI証券にクイックメニューを追加し、目的のページにより簡単に飛べるようになります",
  "icons": {
    "128": "icon.png"
  },
  "options_page": "options.html",
  "permissions": ["storage"],
  "content_scripts": [
    {
      "matches": ["https://*.sbisec.co.jp/*"],
      "css": ["assets/main.css"],
      "js": ["bundle.js"],
      "run_at": "document_idle"
    }
  ]
}

メイン

クイックメニューを表示する Component

SBI の DOM を id で指定して、 React.createRoot している

try {
  const headerLi = document.createElement("li");
  const headerContainer = document.getElementById("link02M");
  if (!headerContainer) throw new Error("Root element not found");
  const targetUl = headerContainer.querySelector("ul");

  // targetUl の最初の要素として headerLi を追加する
  if (!targetUl) throw new Error("Root element not found");
  targetUl.insertBefore(headerLi, targetUl.firstChild);

  const headerRoot = createRoot(headerLi);
  headerRoot.render(<HeaderMenu />);
} catch (error) {
  console.error(error);
}

SBI側の UI いじり

こんな感じの上書きをしている

#NAVIAREA02 {
  height: auto !important;;
}

#HEADER01 #link02 {
  width: 700px !important; /* デフォルトが590px */
  right: 0px !important;
  left: auto !important;
}

Chrome拡張では、cssファイルを読み込ませることができるが、style タグとして埋め込むとかではなく、 manifest.json で指定することになる。
この css の指定がそれ。

  "content_scripts": [
    {
      "matches": ["https://*.sbisec.co.jp/*"],
      "css": ["assets/main.css"],
      "js": ["bundle.js"],
      "run_at": "document_idle"
    }
  ]

オプション

メニュー項目をカスタマイズする画面

以下のファイルで構成

  • options.html
  • options.css
  • options.ts

カスタムメニューの作り方

chrome.storage を使って保存している

困ったこと

ts で書こうとしたが、 chrome をどうやったら手軽に型付けできるか分からなかった。

@extend-chrome/storage を使えば解決した。内部で頑張ってくれている。
エンジニアとしてはこのライブラリを読み解いて、 chrome の扱いについて勉強するべき・・。
そうでなくても chrome.storage のコードは煩雑になりがちなので、このライブラリは使った方がいい。

Webpack

上述の2種類に分かれるので、 entry は 2つ。

  entry: {
    bundle: "./src/index.tsx",
    options: "./src/options.tsx",
  },
  output: {
    path: `${__dirname}/dist`,
    filename: "[name].js",
  },

entry の key 名が、 output.filename[name] になるって初めて知った

また、 option.html のために options.js を使うが、 bundle.js は必要ないので以下のようにした

    new HtmlWebpackPlugin({
      filename: "options.html",
      template: "src/options.html",
      chunks: ["options"],
      excludeChunks: ["bundle"],
    }),

Chrome 拡張っていいよね

  • いろんな事ができる
  • 既存のサイトも魔改造できる
  • 手軽に作れる
  • 長いものに巻かれたプロダクトを作れる(今回は SBI に巻かれている)
  • 審査が早い(数分。一度審査クリアすると0秒で終わる)
  • 維持費が安い

おすすめ