Inside "dotby.jp 2015"

弊社 [dot by dot inc. のコーポレートサイト](http://dotby.jp/)をリニューアルしたときのいろいろをメモ。見た目シンプルなわりにいろいろあったのでね :satisfied: 

# どんな仕組みでつくる？

日々増えるニュースを簡単に更新できるようなブログ形式、[前バージョン](http://dotby.jp/2014/)の背景エフェクトもってくる（かつページ遷移においてリロードしない＝エフェクトを途切れさせない）という前提で検討した結果、[WordPress](https://wordpress.org/) を CMS に使いつつ [WP REST API](http://wp-api.org/) で JSON ひっぱってきて [React](http://facebook.github.io/react/) でごにょごにょやるんがいーかなーと。

# React

ちょうどどうやってつくろっかなーと考えてる時に、[VirtualDom - なぜ仮想DOMという概念が俺達の魂を震えさせるのか - Qiita](http://qiita.com/mizchi/items/4d25bc26def1719d52e6) を読んで、どうやらこれ流行りそう今っぽいーということでフロントのフレームワークを [React](http://facebook.github.io/react/) に決定。ちょうど [IntelliJ IDEA 14](https://www.jetbrains.com/idea/) が [JSX](http://facebook.github.io/jsx/) の syntax をサポートしたってのもある。（わたし IDE のコードアシストないと不安なひと）

React いわゆる View だけっぽいフレームワークでシンプルなので、[公式のチュートリアル](http://facebook.github.io/react/docs/tutorial.html)やればだいたい理解できる。ぎゃくにいうとそれ以外の部分は自分でがんばらないといけない。ま、WordPress から JSON でデータひっぱってくるだけなのでそんなに複雑なことはないけど。

[一人React.js Advent Calendar 2014](http://qiita.com/advent-calendar/2014/reactjs) もよくまとまっててわかりやすい。


## JSX

React の Component を書くのはふつうの JS でだらだら書くのでもできるんだけど、やっぱ [JSX](http://facebook.github.io/react/docs/jsx-in-depth.html) で書いたほうが効率いいし見通しもいい。で、これまで HTML5 系のサイトをいくつか作ったときは [CoffeeScript ](http://coffeescript.org/)だったので [coffee-react](https://github.com/jsdf/coffee-react) つかってみよーと思ったものの、IDEA が cjsx の syntax 理解してくれなかったので plain な JSX で書いた。括弧が多いとか行末コロン忘れがちとかいろいろあるものの、JSX は JavaScript にコンパイルするときに [ECMAScript 6 の文法](https://github.com/lukehoban/es6features)（[全部じゃない](https://github.com/facebook/react/blob/master/vendor/fbtransform/visitors.js#L30-L37)けど）が使えるオプションがあって、ES6 で書けば素の JavaScript で書くよりはストレスすくない。[arrow](https://github.com/lukehoban/es6features#arrows) とか [template strings](https://github.com/lukehoban/es6features#template-strings) とか [destructuring](https://github.com/lukehoban/es6features#destructuring) らへんは特に CoffeeScript っぽくて使いやすい。

## React Router

[React Router](https://github.com/rackt/react-router) は URL に応じて React の Component を自動的にとっかえてくれる Component。URL と Component の対応付けも JSX で宣言的にかける、わかりやすい。[Express の Router](http://expressjs.com/4x/api.html#router.param) みたくパラメータ受け取ったりもできる。Express ほど柔軟じゃないけど。

同一ドメイン内のリンクは [Link コンポーネント](https://github.com/rackt/react-router/blob/master/docs/api/components/Link.md)か [Navigation mixin の transitionTo メソッド](https://github.com/rackt/react-router/blob/master/docs/api/mixins/Navigation.md#transitiontoroutenameorpath-params-query)つかう。デフォルトだと昔 Flash で Progression でやってたみたいな URL hash で URL 書き換えるんだけど、[オプションつける](https://github.com/rackt/react-router/blob/master/docs/api/run.md#location-optional)と HTML5 の History API つかってくれるようになる。

今回、英語版の URL を [mqTranslate](https://wordpress.org/plugins/mqtranslate/) のデフォルト設定、/en/ を前につけるっていうのを採用したんだけど、そこのルーティングが現状の React Router では[いい感じに書けなくて、ちょっと冗長になってる](https://github.com/dot-by-dot-inc/dotby.jp-2015/blob/master/src/main.jsx#L37-58)のが残念。ま、動いてるので OK。

/tag/hogehoge とか /page/123 とか、WordPress 側ではちゃんとページでるやつが React 側で未実装で Not found になってるやつがあるので、どっかのタイミングで実装しないといけないかな・・ :sweat_smile: 

## Transition

別ページへのトランジション、特にメンバー一覧から詳細への動きをシームレスにしたかったんだけど、タイムアウトにより断念。いちおう React にはそのへんできそうな[仕組み](http://facebook.github.io/react/docs/animation.html)あるので次回やるときもうちょい研究する。かも。

## Google Analytics

React Router が Component 切り替えるタイミングでふつうに [GA の API](https://developers.google.com/analytics/devguides/collection/analyticsjs/pages) を[呼ぶ](https://github.com/dot-by-dot-inc/dotby.jp-2015/blob/master/src/main.jsx#L70)。以上。

# WordPress

## REST API

WordPress のデータを JSON で取得できるようにするプラグイン、[WP REST API](http://wp-api.org/) を導入。以前、[螢光 TOKYO](http://keikotokyo.com/) のサイトをつくったときは [JSON API](https://wordpress.org/plugins/json-api/) のほうを使ってたんだけど、もうメンテされてないのと WP REST API は WordPress 本体に組み込まれそうなのでこっち採用。使い勝手は JSON API のほうがよい気はするけど。

React からはページを表示する Component が body に append されたタイミング、[componentDidMount](http://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount) が呼ばれたタイミングで API をコール。API からデータ返ってきたときには Component が削除されてる可能性があるから [isMounted()](http://facebook.github.io/react/docs/component-api.html#ismounted) でチェックしろってどっかで読んだけどいまコード見たらチェックしてないなー :fearful: 

## i18n

WordPress に [mqTranslate](https://wordpress.org/plugins/mqtranslate/) をいれて普通に多言語対応。REST API よぶときに現在の言語をオプションにつけて [?lang=en とかして呼べば](https://github.com/dot-by-dot-inc/dotby.jp-2015/blob/master/src/components/Page.jsx#L31)指定した言語のデータが返ってくる。現在の言語を取得するために自分で mixin 書いてみたんだけど、はたしてこれが正しいやりかたなのかは不明 :sweat: 

## Advanced Custom Field

[WORK](http://dotby.jp/category/work/) の CREDIT ぶぶんとかは、フリーで入力するとレイアウトがばらばらになったりするので、[Advanced Custom Field プラグイン](https://wordpress.org/plugins/advanced-custom-fields/)をつかって専用のカスタムフィールドに入力するようにしてる。カスタムフィールドに入れたデータはそのままでは REST API で返ってこないので、[返してくれるようにする別のプラグイン](https://github.com/PanManAms/WP-JSON-API-ACF)をさらに追加。

## SEO

JS で JSON よんできてクライアントサイドでページつくる仕組みの WordPress テーマなので、ふつうにそのまま検索エンジンに同じのを出すとうまくインデックスされないかも？（Google は JS 実行してくれるっていう話ですけども）なので、検索エンジン向けにはふつうの WordPress のテンプレートで出力するようにする。[Multi Device Switcher](https://wordpress.org/plugins/multi-device-switcher/) っていうプラグインをいれて、検索エンジンであろう User agent に対してだけふつうのテンプレート（Twenty Fifteen）を出すようにすればできあがり。React 使ってるんだったら Server side rendering の仕組みをつかってちゃんとユーザーが見てるのと同じ HTML を返すのがただしいのかなー、WordPress と共存させるのがむずそうだけど。。

# Dot Pattern

背景のドットパターン（前景？:sweat_smile:）は前バージョンのものをベースに表示部分を最適化した。前バージョンは SVG で全部描画してたのだけどシンプルな見た目のわりに CPU 100% 使い切ったりですげえ重かったのを、WebGL (three.js) で書きなおした。WebGL 対応してない環境では SVG にフォールバックしてレンダリング。レンダラーを切り替えられるように、ドットの配置・動きを計算する部分とレンダリング部分をちゃんとわけた。

## Transition between patterns

各ドットパターン間のトランジションは、それぞれのドットが一番近いドットに移動するようにしてある。一定の距離よりも近い場所になければ消滅したり発生したり。いちばん近いドットを探すのは、総当りでやっちゃうと重いので [quad tree](http://ja.wikipedia.org/wiki/%E5%9B%9B%E5%88%86%E6%9C%A8) で。[実際のコードはこのへん](https://github.com/dot-by-dot-inc/dotby.jp-2015/blob/master/src/components/Dots/Main.coffee#L89-160)。JS の quad tree 実装はいろいろあるんだけど、いくつか試した感じだと[これ](https://github.com/silflow/quadtree-javascript)が今回の用途には使いやすかった。

## WebGL

円を描くだけなのでいつも使ってる [three.js](http://threejs.org/) じゃなくて、べつの 2D に特化してるやつにしてみようと [two.js](https://jonobr1.github.io/two.js/) を試してみたら意外とすごく重くて（[この Example](https://jonobr1.github.io/two.js/examples/particle-sandbox.html?type=webgl&amp;shapes=circle&amp;operations=translation,scale&amp;count=100)、100 個しか円描いてないのにめちゃ重、、）、結局 three.js でごりごり書くことに。

ふつうに WebGL できれいな円を描こうとすると、ポリゴン数がたいへんなことになっちゃう。

![32poly2.png](https://qiita-image-store.s3.amazonaws.com/0/2595/d8b2a50c-33e4-985f-9956-08fa6d54733b.png)

これは 32 ポリゴン、大きいドット描くときはもっとポリゴン数おおくしないとカクカクしてるのがバレる。ので、ポリゴンで描くんじゃなくて fragment shader で描くことにした。fragment shader 内で四角ポリゴン中心からの距離を計算して、一定距離以下だけ描く、それいがいは discard する。そのままだとジャギるので antialias かける。antialias ちゅーか、境界をぼかすんだけど。そのへんは[この記事](https://rubendv.be/opengl/drawing-antialiased-circles-in-opengl/)を参考に。実際は四角ポリゴンだと discard する領域が多くて重くなるので 8 角形にしてる。

![8poly2.png](https://qiita-image-store.s3.amazonaws.com/0/2595/e56e3468-71a3-182a-dedc-b47534bcaa98.png)

three.js の実装てきには、あらかじめ 1024 個のドット（最大でそんぐらいでる）を描くのに必要なバッファを用意しておいて、描くタイミングで座標全部つめこんで drawcall 1 回で全部描く。CPU 側の処理はドットの位置計算だけになったのでかなり軽くなったけど、シェーダー負荷があがったので GPU がしょぼいと重いかも、、、？ :sweat_smile: 

## SVG

SVG renderer のほうはすごくシンプル。すべてのドットには個別の id がふってあるので、未知の id が追加されたら SVG 側にもcircle 要素追加、すでに追加されてたら移動、なくなってたら削除。これらの操作には前バージョンとおなじく [Snap.svg](http://snapsvg.io/) を利用、らくちん。

# Web Font

本文のフォントには [Noto Sans Japanese](https://www.google.com/get/noto/#/family/noto-sans-jpan) を使ってる。自分で Web font 化しないといけないかなーと思いつつぐぐったら Google Fonts が [Early Access](http://www.google.com/fonts/earlyaccess) として Noto Sans Japanese を用意してくれてたのでそれを採用。

# Favicon

メニューの現在地をしめすドットのカラーは背景パターンの色と同期することにしてたので、じゃあ、favicon も一緒に変えてみよーということで実装。favicon を指定している link タグの href 属性を、canvas の toDataURL() で書き換えればいいだけ。[コードこのへん](https://github.com/dot-by-dot-inc/dotby.jp-2015/blob/master/src/FaviconAnimator.jsx)。ただしブラウザによってできるできないがあって、Chrome は 2-3 fps ぐらいだけどちゃんとアニメする、Firefox は fps はやすぎるとついてけなくてチラチラするけど表示はできる、Safari はアニメ不可 & そもそも設定できたりできなかったり。

# Google Maps

Google Maps にはっつけるアイコンも favicon みたく背景同期したかったので、[SVG アイコン](https://developers.google.com/maps/documentation/javascript/symbols)として実装。SVG アイコンのみ動的にカラーが変更できるっぽい。指定カラーがパス全体に反映されちゃうので、当初のデザインが再現できなかったんだけどじゃがーさん OK でたのでよし。

# Build System

上記さまざまな仕組みは、いつもどおり [Grunt](http://gruntjs.com/) + [Browserify](http://browserify.org/) でビルド。React の JSX も [reactify](https://www.npmjs.com/package/reactify) かませば普通に require できる。本番サーバーへの deploy も [grunt-rsync](https://github.com/jedrichards/grunt-rsync) で。

公開してから[指摘されて](https://twitter.com/novogrammer/status/552009669342814208)気づいたんだけど、browserify のデフォルトだと？ require したモジュールの絶対パスがそのままソースに含まれちゃうので、browserifyOptions の fullPaths を false にしといたほうがよさげ。ファイルサイズもちょっと小さくできる。

# Conclusion

WordPress + REST API + React (+ Server side rendering) って組み合わせはもっと流行ってもいいんじゃないかなー。重くなりがちな WordPress も JSON ひっぱってきてクライアントサイドで画面つくればけっこういい感じに軽いサイト作れる。今回の[ソース一式公開しておいた](https://github.com/dot-by-dot-inc/dotby.jp-2015)のでだれかもっと汎用的な仕組みつくってくんろ。[僕のブログ](http://saqoo.sh/a)もこの仕組でリニューアルしたい。

で、
最後までちゃんと読んで、ふんふん、おもろい、なんかわからんけど、おもろい、わたしもこんな感じで仕事してみたい！ と思った、そこの 20 代のあなた。わたくし Saqoosha は dot by dot inc. にてちょうど弟子を募集していますので、いますぐ GitHub のアカウントを書いて info@dotby.jp までご連絡を。わたしがこういうかんじでモノ作ってるのを隣で観察することができますよー:smiley: 

http://saqoo.sh/a/2508