The future starts today

Webとか英語とか育児とかに関する雑記

仕事中に閲覧できるTwitterクライアント「Worc」を作った

この記事は Electron Advent Calendar 2016 の9日目の記事です。

作ったもの

f:id:shibe97:20161123233256p:plain

github.com

GitHubで公開しています。Releaseページから最新バージョンの「worc-darwin-x64.zip」というリンクからダウンロード可能です。

以下のランディングページからダウンロードできます。(追記:2017/2/17)

shibe97.github.io

※未署名のため、ダウンロード後は「右クリック」→「開く」という手順で開く必要があります。

動機

Twitterは情報収集のツールとして非常に優秀だと思っていて、特にTech系の情報はTwitter経由が一番速くつかみやすいです。 界隈で強い方々はよくTwitter使って発信しているイメージがあります。

世の中には非常に多くのTwitterクライアントが存在しているのですが、個人的にしっくりくる物がないんですよね。。

これはあくまで僕個人の話ですが、会社内でTwitterを見て情報収集したいという願望があります。
しかし、SNSは娯楽系のイメージが強いため、会社内で堂々と閲覧しているのは憚れます。。

「よし、会社内で普通に見れるようなTwitterクライアントを自作しよう!」

と思ったわけです。

加えて、普段から気になっている技術や、試してみたい構成を突っ込んでみる良い機会ということで作り始めました。

どんなものを作ったか

Twitterが娯楽っぽく見えてしまう要因を考えてみたところ、個人アイコンがずらっと並んでいる感じがそれを助長しているのではないかと考えました。
そこで、できる限りテキストベースにし、派手さをなくした物を作りました。

f:id:shibe97:20161127222012p:plain

意外とアイコンなしでも人を判別できるものです。
しかし時たま、これ誰だっけ…というときのためにハンドル名クリックでアイコンは表示されるようにしました。

f:id:shibe97:20161127222450p:plain

基本的にはデスクトップの左端、または右端においてコーディング横目に閲覧するようなイメージです。
黒い画面の隣だと若干目を引きますが、他のアプリケーションと同時に使うことも想定し、無難な白基調のものにしました。

f:id:shibe97:20161127230808p:plain

とりあえず、ストリーム形式のホームタイムラインと、リストタイムラインは必須だと思い、導入しています。

ハッシュタグの検索結果のストリーム版もエンジニアにとっては欲しい機能かな〜と思ったのですが、勉強会とかに参加していない時はそこまでハッシュタグ追わないかなと考え、後回し中です。(昼のイベントに参加できず、会社でハッシュタグを追うというのはたまにありそうですが)

フリーで落とせるのでぜひ気になる方は使ってみてください! Star、Issue、プルリクも大歓迎です!

ダウンロード

今後の展望

  • メニューからデザインを自由に変更できるようにしたい(背景色など)
  • ストリームAPIの接続が切れた際に自動でつなぎ直したい(やり方がよくわからない)
  • ハッシュタグにリンクをつける
  • リプライ先にリンクをつける
  • 自動アップデート機能(Apple Developer Programへの登録が必要)

などなど、やりたいことはたくさんあります。
地道にアップデートを重ねていく所存です。

名前の由来

ちなみに由来は、仕事という意味を表す「Work」です。
そして、やはりTwitterクライアントということで鳥に関するサービス名が良いと思い、今回は闇に溶け込んで集中を途切れさせない的な意味を込めて、カラスあたりが適役かなと思いました。
カラスは英語で「Crow」です。

勘の良い方はお気づきになったかもしれませんが、「Worc」を逆から読むと「Crow」となります。
奇跡か!!と思いました。

構成

ここから先は技術の話となります。 今回は以下の構成で作りました。

  • Electron
  • React
  • Redux
  • Redux-saga
  • Webpack
  • CSS Modules
  • Jest
  • Enzyme
  • ESLint
  • Atomic Design
  • Travis CI

ズラッと並べると凄そうに見えますね。笑

コンポーネントの内訳

以前、「ReactコンポーネントCSSコンポーネントは1対1なのか問題について」という発表をReact Meetup #4で行ないました。

ReactコンポーネントとCSSコンポーネントは1対1なのか問題について // Speaker Deck

その時はまだ机上の空論感があったので実際に試してみました。
試してみた結果、やはり1対1の粒度で作っていくと綺麗に作れると感じました。

Atomic Designを取り入れ、できるだけ細かい単位で分割し、今回は以下のものをコンポーネントとしてひとまとまりにしました。

Loadingの例を挙げると以下のような感じです。

  • Loading.js
import React from 'react'; 
import styles from './loading.css'; 

export default () => ( 
  <div className={styles.loading} />
); 
  • Loading.test.js
import React from 'react'; 
import { shallow, mount, render } from 'enzyme'; 
import Loading from './Loading'; 

describe('components/atoms/loading', function() { 
  it('should have a "loading" class', function() { 
    expect(shallow(<Loading />).hasClass('loading')).toEqual(true); 
  }); 
}); 
.loading { 
  height: 100%; 
  background: url('./loading.svg') no-repeat center center; 
  background-size: 40px 40px; 
} 

この4つを同一階層に配置します。
Loadingの表示に必要なものが全てまとまっているので、これぞコンポーネントだ!という感想を持ちました。

ちなみに、CSSの読み込みにはCSS Modulesを、ReactコンポーネントのテストにはEnzymeを利用しています。

こうなった経緯

最初からこの方式で作り始められれば良かったのですが、実は途中からリファクタリングで徐々に直していきました。
当初、普通にsassを使っていたのを途中からCSS Modules形式に変更しました。
同時にAtomic Designに基づいた形でコンポーネントを分割し直しました。

Atomic Designの話

今年は結構話題になることも多かったのでご存知の方も多いと思いますが、 Atomic Designとは、コンポーネントをそれ以上分割できない単位(原子)まで分割し、それらを組み合わせて徐々に大きな単位のコンポーネントを形作っていくという考え方です。

通常、以下の5つに分割するのがAtomic Designの考え方になります。

  • Atom(原子)
  • Molecule(分子)
  • Organism(有機体)
  • Template(テンプレート)
  • Page(ページ)

しかし、個人的にはTemplateとPageがあまりしっくり来なかったので、今回はtemplate以上の部分をModuleと名付けた以下の構成にしました。

  • Atoms
  • Molecules
  • Organisms
  • Modules

ページごとにディレクトリが分かれるのでは無く、コンポーネントの大きさ単位でディレクトリが分かれているので、より再利用性に富んだ形であると思います。

進めていくと、「あ〜あのコンポーネントはどこだっけな?」とわざわざ読み込み先からパスを見て探しに行くケースも出てきました。
なんとなくコンポーネントの粒度で当たりはつけられるのですが、そのあたりはちょっと慣れが必要そうです。

Electronはどうだったか

Electronはブラウザプロセスとレンダラプロセスで構成されています。

OSの機能を直接つかったりするのはブラウザプロセス側です。重い処理はブラウザプロセス側でやるのが推奨されていたりもします。プロセス間は通信の手段がいろいろあります。

今回はTwitterクライアントということで、基本的にはTwitterAPIをフルに利用したものなので、ほとんどの処理はレンダラプロセスのみでいけました。

レンダラプロセスに入ってしまえば、後は普通のWebアプリと一緒です。 出力したindex.htmlからバンドルされたJSを読み込み、Reactアプリケーションを構築します。

特有なのはブラウザプロセスだけなので、その部分さえ乗り越えてしまえば楽でした。

Electronのファイルサイズ

今回、136MBという馬鹿でかいサイズとなってしまいました。

当初はJSのバンドルは行なっていなかったのですが、バンドルした方が容量が小さくなるという記事を見つけ、Webpackで1つのファイルにしました。 実は最初はもっと重くて、162MBあったものが、Webpackを通すと135MBになりました。(それでもまぁ重いのですが・・・)

V8が搭載されているため、空の状態でもかなりの容量があるのでしょう。

アプリケーションのダウンロードに時間がかかってしまうのが難点です。
何か良い解決策がありましたら是非教えてください〜。

まとめ

Electron触ってみたいなぁ〜ということでちょうど欲しかったTwitterクライアント作りに挑戦してみました。
ほとんどWeb開発と同じ感覚で作れるのでやりやすかったです。

Chromeの最新版のみに対応すれば良いので、ブラウザ対応という面倒なことを考えなくて良いのが最高でした。

パッケージングやGitHubへのデプロイなど、今まであまりやったことがなかったため良い勉強になりました。