Electron + Vue + flowtypeで最高の画像を収集するためのTwitterクライアントを作った


Electron + Vue2 + Vuex + Flow + BootStrap4 + AWS RekognitionのスタックでTwitterクライアント書きました。

本アプリは[【Electron + react + flowtype】TweetDeckライクなpixivクライアントPixivDeckをつくった - Qiita](http://qiita.com/akameco/items/fa80b9a325e3d1e8fd5b) に思想・設計共に大きく影響を受けて作りました。本当にありがとうございます。

![imeclletter_logo.png](https://qiita-image-store.s3.amazonaws.com/0/32836/4be54e88-a9df-29c8-f600-7bbf45470a9e.png "imeclletter_logo.png")


[Github - yuki-ycino/imecoletter: 最高の画像を集めるためのTwitterクライアント](https://github.com/yuki-ycino/imecoletter)

諸事情（というか実装の都合上AWSの請求が大変なことになるため）バイナリの配布はできません。
簡単にビルドできるようにはしてあるのでもし興味がある方がいれば使ってみてください。

## スクリーンショット

## TwitterのTLから画像ツイートのみを表示

### Twitterから画像ツイートだけを取り込んでタグ付け

![170426-0006.png](https://qiita-image-store.s3.amazonaws.com/0/32836/8453057f-e1ce-5186-0e06-616bd94af418.png "170426-0006.png")


### 画像のプレビュー

![170426-0002.png](https://qiita-image-store.s3.amazonaws.com/0/32836/3890e81c-e969-e76b-68a8-fdc6335962a1.png "170426-0002.png")

### 画像のタグによる絞り込み(or検索のみ)

![170426-0008.png](https://qiita-image-store.s3.amazonaws.com/0/32836/c67ad6de-692c-3a00-c851-0093951b4f07.png "170426-0008.png")


### レスポンシブ対応

![170426-0010のコピー.png](https://qiita-image-store.s3.amazonaws.com/0/32836/c09701fb-4502-a64b-e374-6ad796f73f8a.png "170426-0010のコピー.png")


![170426-0009.png](https://qiita-image-store.s3.amazonaws.com/0/32836/8133ec5f-fa95-153d-53e9-54ff24ae023e.png "170426-0009.png")


### 最高の画像たち

![170425-0005のコピー.png](https://qiita-image-store.s3.amazonaws.com/0/32836/17f4e900-6412-d710-ff41-d0459fb35c99.png "170425-0005のコピー.png")

###その他
- Retweet・Like
- ツイートの詳細表示(デフォルトではツイートテキストすら非表示)

などの機能が付いています。ダウンロードは個人的にはしてないのでまだ付けてないです。

## ビルド
macOSとWindowsで動作確認。

TwitterアプリのキーとAWSのRekognitionの使えるユーザのキーが必要なのでREADMEの通りにそれだけ入れて `npm run build` するとアプリができると思います。

具体的にはRekognitionの課金で財布事情がヤバいことになりそうなのでバイナリの配布はしてない状態です。

## 技術的なあれ
基本的にはvue-cliで作ったスケルトンを元に作っています。

## 構成
ライブラリにElectron + Vue + Vuex + BootStrap4 aplha6
WebサービスにTwitterとAWSの[Rekognition(深層学習に基づく画像認識サービス)](https://aws.amazon.com/jp/rekognition/)を使っています。

画像の解析をしてラベルを付けて返してくれる機能があるのですが、1000枚で1ドルらしいので余裕やろｗとか思って開発を始めたら開発段階で50000枚超。まだ1-2日しか回してないですが1日に流れてくる画像ツイートの数が思ったより遙かに多くて死亡しました。

## Vue + Vuex + flowtype
これについてはReactほどは恩恵を受けれない感じでした。
テンプレートで使う部分、Vuexにdispatch・commitする時点でどうしても型情報が失われるためそのあたりを頑張るのは辛い感じです。

既存ライブラリについてもflow-typedで定義されてるものについてはあまり期待はできない感じでした。

ただ、flowtypeは部分的に取り入れることが出来るのでドメイン部分を実装する際には非常に役に立ってくれましたし潜在的なバグを警告で何度も防いでくれました。ある程度の規模のアプリケーションを作る場合は自分の場合今後も必須になっていくと思っています。

## CSS
本アプリは主にJSを書くエンジニアとデザイナ兼CSSを書くエンジニアの2人で開発しました。Vue Componentで変更が衝突することが少しありましたが、コンポーネントの設計だけ割と細かい粒度で最初にちゃんとしておいたのでそんなに困ることはありませんでした。

実装としてはBootStrap4を元にresponsive, modal, cardあたりの恩恵を受けつつ、Vue Componentのscoped CSS + SCSSで必要な部分をガンガン雑に書き換えていきました。
scopedのおかげでめちゃくちゃ雑に書き換えても何とかなったのでVue ComponentのおかげでCSSの設計を殆ど考えずに書くことができました。

## AWS Rekognition
画像を `await axios({ method: 'get', url, responseType: 'arraybuffer' })` という感じで取得してそのまま `rekognition.detectLabels(params).promise()` という感じでPromiseでラベルの一覧を受けることができます。
それぞれ作ったImage型にLabel型の配列を持たせてそこに突っ込んでViewで表示してます。

結構精度が高くて色々な情報が返ってくるしデモサイトも用意されているので試すだけで割と面白いです。

## エディタ
[VimでALEを使ってvueファイルにeslintとstylelintを使う - Qiita](http://qiita.com/tigberd/items/62dcc63ae70edb663c80) に関わるんですが [GitHub - Chiel92/vim-autoformat: Provide easy code formatting in Vim by integrating existing code formatters.](https://github.com/Chiel92/vim-autoformat) を使って

```
let g:formatdef_vuefmt = '"cat > vuefmt-temp.vue; ruby -e ''File.read(\"vuefmt-temp.vue\").gsub(%r{<template(.*?)>(.*)</template>}m) { |_| File.write(\"vuefmt-temp-template.xml\", \"<template#{$1}>#{$2}</template>\"); `touch \"vuefmt-temp-template.xml\"` unless File.exist?(\"vuefmt-temp-template.xml\")}''; cat vuefmt-temp-template.xml | htmlbeautifier; echo \"\"; touch vuefmt-temp-js.js; ruby -e ''File.read(\"vuefmt-temp.vue\").gsub(%r{<script>\n(.*)</script>}m) { |_| File.write(\"vuefmt-temp-js.js\", \"#{$1}\"); }''; eslint --fix vuefmt-temp-js.js >/dev/null 2>&1; echo \"<script>\"; cat vuefmt-temp-js.js; echo \"</script>\"; echo \"\"; ruby -e ''style = File.read(\"vuefmt-temp.vue\").gsub(%r{<style(.*?)>(.*?)</style>}m).each { |tag| css = $2; puts \"<style#{$1}>\"; print `echo \"#{css}\" | stylefmt --stdin-filename tmp`.chomp; puts \"</style>\"; puts\"\" }''; rm -f vuefmt-temp-js.js; rm -f vuefmt-temp-template.xml; rm -f vuefmt-temp.vue;"'
```

という地獄のようなワンライナーでvueファイルに自動で

- htmlbeautifier
- eslint --fix
- stylefmt

をかけるようにしているのでvimで書きました。
flowtypeを使ってJSの開発するなら普通はAtomが良さそうに見えました。
上記スクリプトについては別途記事にしようかと思ったんですが微妙に不具合が残ったまま使っているので結局まだ書いていません。

## その他
Vuexについてなんですがスケルトンの中に `const files = require.context('.', false, /\.js$/)` という動的requireがあってマジかよという印象を受けました。
使う分には便利だったんですがこういうのって一般的に書かれてるんでしょうか、自分で書くには怖い感じがします。

## 終わりに
いけると思って開発を初めて自分1人分ですらコストを賄えるかとなってしまったあれなプロジェクトですがElectron + Vue + flowtypeでそこそこ動くアプリを作る事で様々な知見を得ることができました。

爆速で開発できるVue最高という感じです。

結局アプリの配布は目算が甘すぎてできなかったのですが、このまま捨てるのも勿体ないので、今後はRekognitionは諦めてちょっと別の方向で開発し直してウェブアプリとして公開していくことなども考えています。

もし自分でAWSに課金して使ってみたいという奇特な方がいれば是非使ってみてください。

[Github - yuki-ycino/imecoletter: 最高の画像を集めるためのTwitterクライアント](https://github.com/yuki-ycino/imecoletter)

## 追記
何も考えずに1000ツイート（分の画像）をメモリに展開して放置してたらWindowsですごいことになったので設定画面を作りました。
ガベコレがうまく動いてないとかそういうやつな気がするんで直したいですね・・・

![WS000028.png](https://qiita-image-store.s3.amazonaws.com/0/32836/d0a68890-b519-66d1-e425-86d4cd8ff179.png "WS000028.png")


![2017-04-27_13_31_452.png](https://qiita-image-store.s3.amazonaws.com/0/32836/2fcec44d-a474-f255-8a78-286ca37b6932.png "2017-04-27_13_31_452.png")