SPAを開発する際の重要ポイント

最近、社内でReactを使ってシステムリプレイスと新規機能開発を行ったので、その知見をまとめたいと思います。

※ ここでのSPAとはすべてのViewをJavaScriptで書くWebアプリのことを指します。サーバーサイドMVCを主軸にViewの一部をJavaScriptで書くこともありますが、今回はそのケースではありません。


フレームワーク

昨今のJSのフレームワークはフレームワーク戦争と言われるほど多種多様なフレームワークが出ては消えを繰り返し今に至っています。

jQueryやprototype.jsなどのフレームワーク(ライブラリ)が出始めた2005年から比べるとフレームワークを使わないという選択肢はもう無いでしょう。丸腰のJSでDOMをいじっていた時代に比べると、かなり安定したフロントエンドの開発ができるようになりました。

人気フレームワークの台頭になっている

  • React(+Redux、Flux)
  • Vue(Nuxt)
  • Angular (2以降)

に関しては運用に乗せたのはReactのみになります。開発段階では選択肢に上がっていた同一のアプリケーション(プロトタイプ)を開発してみて感じたことは、コンポーネント指向、レンダリングの最適化、アーキテクチャなどの共通点があり、また開発環境においても各フレームワークにサポート用のCLIツールがあり、開発環境の構築に時間を要することなく開発初動が早いということです。

React

NUXT

Angular


開発環境

フレームワークでも触れましたが、公式が提供しているボイラープレートを使用するのがおすすめです。

Reactの時は、create-react-app

Vueの時は vue-cli

Angularの時は angular-cli

基本は yarn install yarn start


ルーティング

部分的にReactアプリやAngularアプリにする場合はルーティングは必要なく指定DOMに対してアサインしますが、ページ全てをSPAとする時はルーティングは必須です。

またルーティングはルーティングモジュールを使いましょう。

Reactの時は、react-router

Vueの時は、vue-router

Angularの時は、app.component.tsの@RouteConfig


CSS

Bootstrapなど多くのCSSフレームワークは一部の挙動がjQueryに依存しているため、そのまま導入すると結構バグります。CSSフレームワークに限らずですが、jQueryとVirtualDOMはまぜると危険です。

VirtualDOMとjQueryを混ぜる時は必ずレンダリングが完了したあとVirtialDomから生Domに変換した後に動作するようにコーディングしましょう。


JavaScriptライブラリ

前項でも解説しましたが、生Dom前提で構築させているJavaScriptライブラリを使うと使い方によっては結構バグります。

特にアニメーションライブラリや描画ライブラリ(svg、webGLなど)はreactやvueに最適化されているライブラリを使うようにしましょう。

セキュリティ

SPAの特徴であるフロントエンドとバックエンドの疎結合化。マイクロサービス化をすることができ、開発の並列分業やテストタブルなど得られる恩恵も多いですが当然デメリットもあります。

それがセキュリティ対策や認証処理。開発ツールなどが発達しフロントからの通信などは傍受される危険性もあり、特に注意しなければならない部分です。

例として認証処理のシーケンスを記載します。

ユーザー認証処理


ディレクトリ構成とアーキテクチャ

今回システムリプレイスに採用したアーキテクチャはFluxですがVueにもVuexというFluxアーキテクチャを提供するフレームワークがあります。ただし、ディレクトリ構成が決められているわけではありませんので規模に応じて柔軟に構成を変える必要があります。

自由な反面、設計次第では保守しにくくもなるのでしっかりと設計する必要があります。下記は今回システムリプレイスで開発したReactのディレクトリ構成です。FluxUtilsで実装しているので、ReduxやVue、Angularでのディレクトリ構成とは異なりますが、参考までに。

Reactのディレクトリ構成

上記の説明を簡単にすると

エントリーポイントApp/App.jsがビルドする際のエントリーポイントになり、ここにルーティングやDomへのアサインを行います。
コンテナcontainers/xxxContainer.jsがコンテナとなり、ストアの状態を監視し、ビュー(コンポーネント)に通知します。
ビューcomponents/xxxComponent.jsが各ビューとなります。
アクションクリエイターactions/xxxActionCreators.jsが各ストアがもつデータへのアクセス起点となります。アプリケーションの規模によっては直接ビューからディスパッチャに処理を行うこともありますが、データの前処理を行いたい場合は実装するとビューから汚れません。
ディスパッチャdispatcher/xxxDispacher.jsがディスパッチャとなり、各ストアでリッスンしているイベントをエミットします。
ストアstores/xxxStore.jsが各データを管理しています。ディスパッチャ経由でデータの更新がされ、更新後ビューにコンテナ経由で通知されます。
ヘルパー(独自追加)helpers/xxxHelper.jsが各データやオブジェクトに対して行う処理をまとめてビューとロジックを疎結合にします。
データマネージャー(独自追加)data_managers/xxxManager.jsfが非同期処理部分の実装を行います。
レコード(独自追加)records/xxx.jsが通信のレスポンス結果をオブジェクトモデルとして定義します。

ビルドとデプロイ

本番運用するためには、デプロイとビルドは同時に自動実行するよう仕組みを作っておくべきです。

ビルド後に生成するファイルは以下のようなものが一般的だと思います。(webpack利用の場合)

上記のファイルを、ビルドするコマンドを事前に準備しておき、npm-scriptのbuild などのコマンドに設定して出力できるようにしておきます。

例)

またデプロイ自動化には

  • CircleCIやTravisCIなどgithubと連動したCIサービスを使う。
  • gitのwebhook + ビルドとデプロイを実行するコマンドAPIを用意する。

などの方法があります。


まとめ

SPA開発は最近多くのサービスやプロダクトに採用されることも多く、フロントエンド開発においては積極的に採用できるまでに成長した開発スタイルです。

ReactやAngular、VueといったフレームワークライブラリはそのSPA開発を加速させる素晴らしいツールです。1つ学べば他のライブラリにも通ずる部分があるので一度試してみてはいかがでしょうか?