何を作ったか?
-
Threads for Google Chats という Google Chat のための拡張機能を作りました
- 拡張をインストールして Google Chat のルームを開くと、スレッドをリストにして表示してくれます
- スレッドのタイトルを押すことでそのスレッドまでリンクさせることができます
**2021-07-04 追記**
-
Google Chat のアップデートによりチャットのコンテンツが
<iframe/>
で提供されるようになり、Chrome 拡張機能からスレッド情報を参照できなくなったため上記の拡張機能を非公開にしました.
**2021-10-23 追記**
- 前職の同期が拡張機能を直してくれた ので再度公開しました
- 持つべきものは友です.
Google Chat ユーザーの方はぜひ一度使ってみてください!
どう作ったか?
- 拡張機能の表示領域については、Vue.js 3.0 を使ってみました!
- Google Chat 上の DOM 要素の取得などは普通の JavaScript で書いています
GitHub のリポジトリを載せておくので、よければ参考にしてください。
Vue.js 3.0 で chrome 拡張を作る方法
この記事の本題です。
- 前提として、VueCLI でアプリケーションを作ったことがあるくらいのレベルを想定しています
- chrome 拡張の基本的な作成方法について体系的な説明はしていません
よく分かっていないので- chrome 拡張自体からキャッチアップしたい方は、Chrome の拡張機能を自作する - 虎の穴開発室ブログ などを参考にしてください
Link
Vue.js × chrome拡張
では、以下の記事が大変参考になりました。
この記事では Vue 2.x で実装されていますが、基本的な書き方はほとんど変わらなかったです。
プロジェクトの作り方
-
VueCLI でプロジェクトを作って、作成時のオプションで Vue 3 を選択しました
- VueCLI v4.5 以降でないと Vue 3 プロジェクトを作成できない ので、注意してください
Vue.js を chrome 拡張でどう動かすか
manifest.json
の定義
chrome 拡張では manifest.json
というファイルに定義された JS / CSS ファイルが動作する という仕組みになっています。
今回の拡張では、以下のような指定をしました。
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 で解決しています。
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
にしておきます。
vue.config.js
module.exports = {
filenameHashing: false,
productionSourceMap: false,
};
main.js
の定義
Vue インスタンスを作成するための main.js
についても簡単に説明しておきます。
画面の DOM 要素を取得して <div>
タグを挿入し、挿入したタグに Vue をマウントしています。
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 と同じように書くことが可能です
※ただし、元サイトの DOM は Vue で管理されていないので document.querySelectorAll
などを利用して要素を取得する必要があります。
終わりに
上記の手順は多少面倒でしたが、慣れている Vue で拡張を作れるのは実装しやすかった & 作っていて楽しかったです!
今回のものは小規模ですが、もう少し大規模になってくると Vue のコンポーネント分割の恩恵も受けられると思います。
もしより良い導入方法/実装方法などがあればコメント等で教えていただけると嬉しいです