LoginSignup
5
4

More than 1 year has passed since last update.

Vue3 で Threads for Google Chat という chrome 拡張を作ってみた!

Last updated at Posted at 2020-10-22

何を作ったか?

  • Threads for Google Chats という Google Chat のための拡張機能を作りました :laughing:
    • 拡張をインストールして Google Chat のルームを開くと、スレッドをリストにして表示してくれます
    • スレッドのタイトルを押すことでそのスレッドまでリンクさせることができます

2021-07-04 追記
  • :warning: Google Chat のアップデートによりチャットのコンテンツが <iframe/> で提供されるようになり、Chrome 拡張機能からスレッド情報を参照できなくなったため上記の拡張機能を非公開にしました.

2021-10-23 追記

extension.jpg

Google Chat ユーザーの方はぜひ一度使ってみてください!

どう作ったか?

  • 拡張機能の表示領域については、Vue.js 3.0 を使ってみました!
  • Google Chat 上の DOM 要素の取得などは普通の JavaScript で書いています

GitHub のリポジトリを載せておくので、よければ参考にしてください。

https://github.com/Nag729/chat-thread-extension

Vue.js 3.0 で chrome 拡張を作る方法

この記事の本題です。

  • 前提として、VueCLI でアプリケーションを作ったことがあるくらいのレベルを想定しています
  • chrome 拡張の基本的な作成方法について体系的な説明はしていません よく分かっていないので

:link: Link

Vue.js × chrome拡張 では、以下の記事が大変参考になりました。
この記事では Vue 2.x で実装されていますが、基本的な書き方はほとんど変わらなかったです。

:wrench: プロジェクトの作り方

:star: Vue.js を chrome 拡張でどう動かすか

manifest.json の定義

chrome 拡張では manifest.json というファイルに定義された JS / CSS ファイルが動作する という仕組みになっています。
今回の拡張では、以下のような指定をしました。

:star: manifest.json

{
  ...
  "content_scripts": [
    {
      "matches": ["https://chat.google.com/*"], // Google Chat のページで有効化
      "js": ["js/chunk-vendors.js", "js/app.js"], // ビルドされたJSファイルを指定
      "css": ["css/app.css"], // ビルドされたCSSファイルを指定
      "run_at": "document_end" // ページが読み込み完了したタイミングで拡張を動かす
    }
  ],
  ...
}

VueCLI でプロジェクトを作ったことがあれば何となく想像がつくと思いますが、
npm run build で出力されるファイルを読み込むように manifest.json を定義しています。

dist/ に動作する chrome 拡張フォルダを作るための方法

npm run build で出力されるのは Vue のソースだけなので、chrome 拡張として動作させるためにはいくつかのファイルのコピー・削除等が必要です。
その辺りの操作は、npm scripts で解決しています。

:star: package.json

...
"scripts": {
  "compile:content": "vue-cli-service build --no-clean src/main.js", // Vue build
  "compile": "run-s compile:content",
  "copy:image": "cpx src/assets/48.png dist/", // 拡張のiconをコピー
  "copy:manifest": "cpx src/manifest.json dist/", // manifest.jsonをコピー
  "copy": "run-p copy:manifest copy:image",
  "remove": "rimraf dist/index.html", // index.htmlは不要なので削除
  "build": "run-s compile copy remove" // 上記のscriptsをまとめて呼び出す
},
...

また、VueCLI はデフォルトだとファイル名にハッシュを付けるので、vue.config.js を編集します。
ついでに、sourceMap も不要なので false にしておきます。

:star: vue.config.js

module.exports = {
  filenameHashing: false,
  productionSourceMap: false,
};

main.js の定義

Vue インスタンスを作成するための main.js についても簡単に説明しておきます。
画面の DOM 要素を取得して <div> タグを挿入し、挿入したタグに Vue をマウントしています。

:star: main.js

import { FontAwesomeIcon } from "@/plugins/font-awesome";
import { createApp } from "vue";
import App from "./App.vue";

const extensionStart = () => {
  // DOM を更新
  const element = document.querySelector("body > div");

  // メインの div に Vue を読み込ませる用のタグを追加
  const createdDom = document.createElement("div");
  createdDom.id = "thread-extension";
  element.insertAdjacentElement("beforeend", createdDom);

  // Vue インスタンスの生成
  createApp(App).component("fa", FontAwesomeIcon).mount("#thread-extension");
};

extensionStart();

ここまで準備すれば、後は通常の Vue と同じように書くことが可能です :tada:
※ただし、元サイトの DOM は Vue で管理されていないので document.querySelectorAll などを利用して要素を取得する必要があります。


終わりに

上記の手順は多少面倒でしたが、慣れている Vue で拡張を作れるのは実装しやすかった & 作っていて楽しかったです!
今回のものは小規模ですが、もう少し大規模になってくると Vue のコンポーネント分割の恩恵も受けられると思います。

もしより良い導入方法/実装方法などがあればコメント等で教えていただけると嬉しいです :blush:

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