Chatwork Creator's Note

ビジネスチャット「Chatwork」のエンジニアとデザイナーのブログです。

ビジネスチャット「Chatwork」のエンジニアとデザイナーのブログです。

読者になる

簡単!Chrome拡張でオレオレChatwork!

自己紹介

こんにちは。竹川です。@tttyya
2020年4月1日より新卒としてChatworkに入らせていただきました。
サーバーサイド開発部(Scala)にて、やらせてもらってます。

Chrome拡張作り始めたキッカケ

同じScalaチームの先輩と、
「Chatworkに新機能が付くならどんな機能が欲しい?」という雑談をしていました。

とある機能の話になったとき、
「この機能、軽くChrome拡張で実装してみたことあるんですけど」
と涼しい顔で画面共有しながら自慢してきました。
「軽く!!!????Chrome拡張で機能を追加!!!??」とビックリ仰天。
それは、機能としてしっかり動作していて、こんな立派なものが軽く作れるの???Chrome拡張スゲーーーー!!!と思いました。

何を隠そう、わたくし竹川、フロントエンドは知識も経験もほぼ一切ないのです。
どれくらいの工数で、どれくらいの苦労で実装されたのか。そう軽く作れるものなのか。
わからない…わからないならやってみよう。
さぁ竹川も軽くChrome拡張を作ってみよう。というのがキッカケです。

目次

何を作ろうか

Chatwork株式会社では、Chatworkを使用して連絡をとっています。
Chatworkを使用しているうちに、竹川が欲しいと思った機能はこちらです。

  • To一覧を開くショートカットキー
  • グルーピングして、まとめてToする機能

それぞれの説明をいたします。

To一覧を開くショートカットキー

f:id:agoetc:20201125173053p:plain
To一覧とは、これです

キーボードから極力手を離したくない。マウスを使いたくない。
エンジニアなら誰しもがお思いでしょう(思わない人もいると思います)

現在、Toの一覧を開くショートカットキーがありません。
ショートカットキーでTo一覧が表示できれば、ハッピーになれますね。

グルーピングして、まとめてToする機能

Chatworkの社員数が150人を超えました。
社員数が増えるたび、比例してチャットの人数は増えていっています。
そして、社内には様々なチャットは存在しています。

社員全員が参加する共有チャットや、
Scalaチーム、PHPチーム、SREチームが参加する開発チャットなど。

開発チャットでは、ScalaチームにだけToしたい。という機会が多々あります。
検索機能があるとはいえ、数十人の中から、数人を選ぶ作業は、ちょっと大変です。
一気にドカンと、Scalaチーム全員をToできたらハッピーですね

結論

どっちも欲しいのでどっちも作りましょう。

技術選定

jQueryを検討しましたが、
jQuery使ってるとか(笑)みたいなノリをインターネット上で多く見受けられました。
なのでjQueryは使いません

軽く実装するだけなので、生のJavaScriptでいいんじゃないか?
逆に生のJavaScriptで書くほうがカッコいいんじゃないか?

という厳正なる審査の結果、生のJavaScriptで書くことにしました

Chrome拡張作成準備

今回のプロジェクト名はchatwork-to-extensionとします。
ChatworkのToの拡張だからです。

必要なモノ用意

  • /chatwork-to-extension
    • content.js (これは好きな名前でいい)
    • manifest.json

content.js

読み込むJavaScriptファイルです。
とりあえず中身は空でOK。

manifest.json

Chrome拡張の設定ファイルです。
これを用意することで、Chrome拡張としてChromeに読み込ませることができます。

{
  "manifest_version": 2,
  "name": "Chatwork To Extension",
  "short_name": "CTE",
  "version": "1",
  "content_scripts": [
    {
      "matches": [
        "https://www.chatwork.com/"
      ],
      "js": [
        "content.js"
      ]
    }
  ]
}

それぞれのパラメータについての説明は以下です。

  • manifest_version
    • 2じゃないとダメらしいです
  • name
    • 作るChrome拡張の名前。好きにしていい
  • short_name
    • 作るChrome拡張の名前の省略形。好きにしていい
  • version
    • 作るChrome拡張のversion。とりあえず1でいい
  • content_scripts.matches
    • JavaScriptを適用したいサイト
    • 今回はChatworkでのみ拡張を適用したいのでChatworkのURLを指定
  • content_scripts.js
    • 適用したいJavaScriptを指定
    • matchesで指定したURLに適用される

↓ 詳しい設定方法は下記に載っています。

developer.mozilla.org

Chromeで読み込む

chrome://extensions/ をChromeのURLにコピペするか、
右上の三点リーダから、[その他のツール] -> [拡張機能]と開きましょう f:id:agoetc:20201124004146p:plain

左上にパッケージ化されていない拡張機能を読み込むというボタンがあるので、そちらをクリック

f:id:agoetc:20201124005011p:plain

あとは先程作成したフォルダを選択すると、拡張機能の一覧に自分の拡張機能が出てきます。

f:id:agoetc:20201124181329p:plain

これで、拡張機能として、Chromeに設定することができました。
manifest.jsonで設定したとおり、https://www.chatwork.com/ にアクセスしたとき、content.jsが読み込まれるようになります。

試しに、アクセスするとalertが出るコードを書いてみましょう。

alert('Chrome拡張だよ')

更新ボタンを押すと、コードが再読み込みされます。
コードを更新した際は、必ず押すようにしましょう。

f:id:agoetc:20201124181555p:plain

更新したならば、早速アクセスしちゃいましょう🎶
https://www.chatwork.com/ ←クリック

f:id:agoetc:20201124011324p:plain

アラートが出たら、読み込めてると言うことです。やったー。
これでChrome拡張を書く準備はできました

To一覧を開くショートカットキー

てなわけで作りました。

f:id:agoetc:20201125155507g:plain
Toの一覧をショートカットキーで開くデモ

その時点でのコードです

github.com

10行にも満たない、それはそれは小さなコードでした。

// DOM読み込むのを待つ(2000は適当な数値)
window.onload = () => setTimeout(listener, 2000);

function listener() {
    window.addEventListener('keydown', (e) => {
        if (e.ctrlKey && e.key === 't') document.getElementById("_to").click();
    })
}

コードの説明をします。

// DOM読み込むのを待つ(2000は適当な数値)
window.onload = () => setTimeout(listener, 2000);

こちらのコードでChatworkのDOMが生成されるのを待ちます。 わからないですけど、大体2000msも待てば大丈夫だろうというので2000を指定しています。 アクセスしてから、2000ms後に、listener関数が実行されます

function listener() {
    window.addEventListener('keydown', (e) => {
        if (e.ctrlKey && e.key === 't') document.getElementById("_to").click();
    })
}

こちらは、ctrlキーと、tキーが同時に入力された場合、_toというidがついた要素をクリックする、という動作になっています。

_toというidはどうやって調べたの?という話ですが、

f:id:agoetc:20201124191537p:plain (macでは)command + shift + cを押してから、要素をクリックすると、クリックした要素のhtmlを表示してくれます。 (便利〜〜〜)
To一覧を開くには、_toというidのついた要素を取得して、クリックすれば良いんだ。ということがわかります。

document.getElementById("_to").click(); // `_to`というidのついた要素を取得して、クリックしている

簡単ですね〜〜〜
Chrome拡張のイロハはこれで大丈夫です。
この知識を生かしてグルーピングして、まとめてToする機能もパパっと気楽に作っちゃいましょう。

グルーピングして、まとめてToする機能

てなわけで作りました。

f:id:agoetc:20201125161646g:plain
グルーピングして、まとめてToする機能デモ

github.com

すげーーーよChrome拡張。
たったの800行たったの2,3週間の休日を全て費やすだけで新しい機能ができちゃった。

説明できる行数ではないので、アーキテクチャだけ紹介します

f:id:agoetc:20201125102931p:plain
レイヤー関係図

矢印は依存の方向です

  • listener
    • さっき作ったlistener関数です
  • DOMApplier
    • DOMBuilderで作ったDOMを適用するヤツです
  • DOMBuilder
    • DOMの生成をするヤツです
  • BuildByDOM
    • DOMからModelを組み立てるところです
    • DOM操作部分は、どうしても汚くなってしまうので、こちらに集約しました
  • Model
    • ビジネスロジックを集約するためのヤツです
    • DBからの取得、保存もコイツがやります
  • chrome storage(DB)
    • 拡張機能用のデータを保存するストレージです
    • object形式で保存することが出来ます。
    • 詳しくは → chrome.storage - Google Chrome

DOM操作は副作用の塊なので、とてつもなく消耗しました(;_;)
(DOM操作するときの、オススメなアーキテクチャがあれば、ぜひご紹介いただきたいです。)

感想

このように、Chrome拡張でも作る機能によってはデカい工数がかかってしまいます(それはそう)

また、800行というドデカいJavaScriptファイルが出来てしまったので、
ファイル分割できるようライブラリを入れたりフレームワークを入れたりしたほうが多分幸せだと思います。
僕は生のJacaScriptでファイル分割が出来ないということを知らなかったです(;_;)

まとめ

このように、簡単に自分の好きなサイト好きなように拡張することが出来ます。
みなさんも自分の使っているサイトを、便利に拡張してみてはいかがでしょうか
僕は疲れたのでしばらくはいいです。