2017年、新規にJavaScriptを書くならどんな設計をするか
この記事はJavaScript Advent Calendar 2016の記事です。
今回は、2017年、新規にJavaScriptを書くならどんな設計をするか
、というテーマで書いてみようと思います。2017年といっても、しばらくはこんな感じのアーキテクチャでやってきましたので、どんな構成でJavaScriptを設計してきたか
という方が正しいかもしれません。基本的にはSPAをベースとしています。
また、最新のイケてる技術バリバリ使ってやるぜ、というよりは、堅牢で、はやりが変わってもメンテができるということを意識してみました。
DOMのレンダリング
Virtual DOMを代表とした、DOMのレンダリングを行うライブラリをなにか採用します。特に理由がなければReactでいいと思います。Virtual DOMではありませんが、AngularでもDOM管理においてはさほど違いはありません。この2つ以外であれば、Vue.js、もしくは、preact(一例です)などの薄いライブラリがいいと思います。
また、ルーターライブラリもこれに合わせて選ぶのが自然かと考えますが、依存フリーなライブラリもあるので、そちらを採用するのでもいいかもしれません。
実装パターン
いまだとReduxが多く使われているイメージがありますが、シンプルなObserverパターンが実装できればなんでもいいと思います。ただし、DOMのライブラリと同じで、薄くて入れ替えが可能なものにするのがいいと思います。Reduxは比較的入れ替え可能な点もいいですね。
また、Angularであれば、特に何も入れなくても、RxJSとEventEmitterである程度はカバーできると思います。
静的型付け
開発効率がかなり変わってくるため、JavaScriptに静的型付けができるようにします。選択肢としてはTypeScriptかFlowで、機能性で言うならTypeScriptの方が勝っていると思います。ただ、既存のJSがある環境に後付けで導入する、もしくは、今後新しいツールに切り替えたりすることを考慮に入れたいのであれば、Flowを選ぶのが妥当でしょう。ただ普通にES2015で書くくらいなら、静的型付けを是非導入すべきと思います。
これに加えて、lintをリアルタイムでやってくれるツールをいれておくとよいです。僕は、TypeScriptならAtomのlinter、FlowならNuclideを使用していますが、同じようなことができればなんでもいいと思います。
テスト環境
コンポーネントをブラウザで描画しながらテストできるものと、ロジックだけのテストができるもの、2つを準備するといいと思います。どんな構成にも汎用的に用いることができるのは、Karma+Jasmine
とmocha(+chai)
のセットでしょうか。ここにアサーションライブラリや、モックライブラリが乗ってくる感じです。
モジュール管理/ビルド
現状、webpackがやむを得ず最も無難な選択肢だといえます。
タスクランナーに関しては特に必要なく、npmスクリプトで構築するのが????と思います。ただし、gulpを避けるのではなく、Streamを提供するライブラリとしては積極的に使用します。
スタイル
(怒られそうですが...)主要なプリプロセッサーを使えばなんでもいいと思います。PostCSSを使ってもいいのですが、劇的に開発効率があがるという感じではなかったのと、これまでのスタイル開発知見をそのまま活かせる方が、開発効率(開発速度やメンテナンスなど。また、実際のスタイル作成に加え、画像やフォントにも影響が及ぶ)があがると考えます。
また、どのツールであっても、BEMやSMACSSなどを元にした設計を、コンポーネント実装者、デザイナーが把握しながら組み立ててゆくことが大事だと思います。これをするもうひとつのメリットとして、最初にスタイルを作ってしまうと、一部デザインいらずで新規機能やページを開発できるようになることもあげられます。
ディレクトリ構成
上記を踏まえればだいたい自然と決まってくると思いますが、よくありがちなパターンを書いてみました。このあたりはだいたいのプロジェクトで共通しているかな?という感じです。
.
├── entries # ビルドのエントリーポイント
├── components # 使いまわすコンポーネント
├── views # 各ページの親となるコンポーネント
├── action/dispatcher/reducer # アプリケーション特有の設計的分類
├── services # 共通のビジネスロジック
├── values # 共通の静的なオブジェクト
├── style # スタイル
├── assets # アイコンフォントや画像
└── test # テスト。ヘルパーなどもこの中に。
その他
その他、設計とまでは行きませんが、細かなことを書いてみます。
API通信
リクエスト処理のライブラリは、request、superagent、axios、unirest-nodejsあたりでしょうか。fetchを使うのも????と思います。
非同期処理
Promise系のライブラリはなにかしらいれます。普通にbluebirdかqとかでしょうか。async/awaitを使ってもいいですね。
便利なライブラリ
よく使うライブラリです。
おまけ(Rails環境では?)
Rails環境だとまた若干変わって来ますが、基本的には同じ構成でつくっていくことが可能です。つまり、Rails側ではビルドしたJSを該当ページで読み込むだけで、フロントエンドはフロントエンド用のディレクトリをきって、その中で開発します。そうすれば、フロントエンドでは開発スタイルを変えることなく結果にコミットできます。
さらにいうと、Railsサーバーを立ち上げることなく、テスト環境内で開発を完了し、コンポーネントが出来上がったのを確認したら、最後に結合したものをRails環境で確認する、という流れが理想だと考えています。こうすることで、いちいち重たいページをリロードすることなく、かつ、小さな単位で効率的な開発をすることができるというのと、フロントエンドエンジニアが、ある程度サーバーサイドと分離をして作業ができるというメリットがあるからです。
部分的なSPA
アプリケーションによっては、非同期な遷移が必要な箇所もあると思いますが、ルーターを必要に応じて追加すれば、部分的なSPAを作ることも可能です。
DOMをフロントエンドで持てない実装
サーバーサイドアプリケーションの実装では、DOMをフロントエンドで持てない(そういった仕様、要望がある)実装に悩まされることがあると思います。つまり、そういった箇所には、バーチャルDOMが使用できず、RailsでレンダリングされたDOMにたいして処理を加える必要があります。
しかし、その場合も諦めずに、assets/javascripts
配下には触らず、フロントエンドディレクトリで完結させるようにします。その上で、場合によっては、jQueryのNode Moduleを呼び出して(require("jquery")
)DOM操作を行うのは、間違いではないと考えます。テストも工夫すればできるので、このへんの詳細はまた別の機会に書いてみようと思います。
レンダリングに関して、いい感じにSSR中間サーバーを作りJSに寄せた設計をするのもありだと思います。
まとめ
以上、2017年、新規にJavaScriptを書くならどんな設計をするか
を書いてみました。フロントエンドの人にとっては代わり映えしない地味なスタックかもしれませんが、もう一度意識したことを整理してみると、以下のような感じです。最新版はGitHubにまとめています。
- フレームワークロックインしない
- 流行りに流されない
- 尖りすぎていない(モダンすぎない)
- いろんなプロジェクトで使いまわせる
この設計をすれば綺麗なコードを書けるというわけでもないと思いますし、あまり"フレームワーク"に流されず、丁寧にプログラムを実装してゆきたいです。
おわり。