制作事例解説 React + Material-UI + スクレイピング

f:id:syonx:20160619124846p:plain

Chase

syonx.hatenablog.com

what for

React の基礎をチュートリアルや勉強会で学んで、その先に進めないでいたりしませんか? きちんと技術を身につけるには、自分の手で何かを実際に作ってみることが効果的です。 React の公式チュートリアルはとてもよくできていると思いますが、 そこからもう一歩先にトライするのに提案したいのが今回ご紹介する内容になります。

制作したアプリの形式は Web アプリで、あとで読むサービスの Pocket と連携します。 先の記事で示したようにモチベーションと目的が重要なのでややニッチな題材となりますが、 試しやすさと簡潔さの点において Twitter よりも扱いやすいと思います。

構成図

f:id:syonx:20160619153834p:plain

技術スタック

  • Gulp
    • Browserify
    • Babel (babelify)
    • watchify
    • minifyify

React

コンポーネント構造

React チュートリアルに出てきたコンポーネントはこちらです。

- CommentBox
  - CommentList
    - Comment
  - CommentForm

Chase は CommentItem に読み替えて、下の図のような構造になっています。 チュートリアルと同じなので、応用がしやすいのではないでしょうか。

f:id:syonx:20160619163805p:plain

また、途中で react-router を学んだりしてみましたが、あえて採用しませんでした。 階層が深くないというか、最初の接続とメインのリスト画面しかないので。また別の機会に使ってみたいと思います。

ESLint に従うことで作法を学ぶ

f:id:syonx:20160619165004p:plain

このように、お作法に合わないところは怒られます。学習中の ES2015 や JSX の話も絡んで、 何をどう解釈していいか曖昧なときに記述を案内してくれるところに安心を覚えました。 ESLint を入れてから開発の効率が格段に上がったので、面倒でもこれは活用すべきと思います。 以下の記事も参考になりました。

Ajax ライブラリの選択

jQuery でも十分だったのですが、Ajax のためだけに使うのはもったいないという思いがありました。 ファイルサイズも膨らむし、新しいことに挑戦してみたいので今どきなライブラリを検討しました。 axiosSuperAgent で迷いましたが、両方試した結果 axios にしました。 理由はよく覚えていませんが、記述の簡潔さだったような気がします。

Material-UI

f:id:syonx:20160619174820p:plain

2014年中頃に Google からマテリアルデザインが発表され、11月頃に初期リリースがされました。 それ以来継続して開発されており、つい先日 2016年5月6日 に v0.15.0 がリリースされ、大きく構造が変更されました。React v15.0 に追従したのでしょう。

Chase は2016年2月頃から開発を始めていたため途中でアップデートするのに苦労しましたが、そろそろ落ち着いてきた感があります。

callemall/material-ui f:id:syonx:20160619174114p:plain

この Material-UI 、ビルド後のJSファイルサイズが 3 MB 級になってしまう問題がありました。 以下の情報を参考に軽量化を図った結果 614 KB まで下げられました。 それでも大きい方なのかもしれませんが、やらないよりは明らかに快適になりました。

フロントエンド開発フロー

最近の JS 開発でいちばん大変なのがコレではないでしょうか。 この仕組を追いかけるのは本質ではないので「まずはやってみる」の段階では すでに出来上がっている仕組みの上に乗っかる ことが余計なつまづきを防ぐ策だと思います。 なので、同じことを試してみたいということであればぜひ本アプリのソースを参考にしてくださいね。

最近では webpack が流行していますが、Material-UI 周りにあった Example では Web サーバと結合しており、 今回の開発で使っている Sinatra サーバと競合したため採用を諦めました。次のアプリ開発でまた挑戦したいと思います。

Sinatra・Pocket API

アプリ開発は Pocket API を扱うライブラリの調査から始まりました。 Ruby Gem 'pocket-ruby' があったので、扱いに慣れていた Sinatraミドルウェアに選びました。

開発が進み、コードを整理していき Sinatra 部分が薄くなったのを見てふと「間に挟む必要性あるんだっけ?」と思いましたが、 Pocket にアプリ登録した際に受け取っている consumer_key の存在によりサーバが必要なことに気づきました。 Pocket API については以下の記事がとても丁寧で参考になりました。

スクレイピング

Chase では、サムネイルの取得にスクレイピングを行っています。 Pocket に送った記事の URL から OGP イメージを取得して JPEG に変換し、リサイズして Amazon S3 に送っています。

初めて知ったのですが、画像表示の失敗イベントって拾えるんですね。記事リスト表示時にとりあえず S3 に要求し、失敗したら サーバにサムネイル作成要求を出します。非同期で返ってきた返事をもって再度要求し画像を表示する、といった流れで実現しています。

Amazon Web Services (AWS) を使うのも初めてでした。これまでは Heroku も含めすべて無料の範囲でやってきましたが、 ここで初めてクレジットカードが関わる従量課金制サービスの出現です。実際に使ってみると Amazon S3 は本当に安いことに驚きました。

f:id:syonx:20160619183347p:plain

そして、ちょうど6月頭に参加した AWS Summit で取り上げられていた Lambda を知って、もしかしてこれ使えるんじゃ? と思いましたが、あれもこれもやっていては開発がいつまで経っても終わらないので今回は我慢です!

おまけ:Yaku Han JP

そして、つい先日公開された「Yaku Han JP」も使わせていただいています。 ダサい全角カッコや句読点の隙間とおさらばできる素敵アイデアの Web フォントです。 何が嬉しいかというと、この画像を見ていただければ一目瞭然です。

f:id:syonx:20160619202653p:plain

この例だと「、?【】」が変わっています。どうやら記事タイトルというものはプロダクト名やキーワード、カテゴリが出現する性質上カッコを使う場合が多いようですね。 Chase では一覧性を高めるためにできるだけ複数行にならないよう配慮する必要がありました。字詰めも少し施していますが、コイツの効果は絶大です。 font-family: "YakuHanJP", "ヒラギノ角ゴ …… のように先頭に指定しています。作者様に感謝!

開発を一通り終えての感想

クライアント側とサーバ側で明確に分け、Web API (JSON) でやりとりする方式がとても快適でした。 問題が発生したり新しい機能を考えるときに、どこで実装すべきなのか・影響箇所はどこなのかが頭の中で整理しやすいのです。

これは趣味プロジェクトなので全部 1 人でやりましたが、もし 2 人いたらクライアント側とサーバ側で役割分担がしやすいと思えました。 狭間にある view (erb) にロジックを書く必要がなく、ファイルレベルで別のロールの人と編集が競合しにくいと感じました。 そして JS でコンポーネントごとに管理するのはビューテンプレートよりもメンテナンス性に優れているように見えます。

これから新しいアイデアを実現するときも、サーバ側の責務とクライアント側の責務を分断して考えることで疎結合し、効率的に進めていこうと考えています。

ソースコード

ソースコードGitHub で公開しています。実際のコードがどうなっているかはこの先でご確認ください。

Enjoy!