BASE開発チームブログ

Eコマースプラットフォーム「BASE」( https://thebase.in )の開発チームによるブログです。開発メンバー積極募集中! https://www.wantedly.com/companies/base/projects

次世代の管理画面を作るフロントエンドの取り組み

f:id:aiyoneda:20190205184206p:plain

フロントエンドエンジニアの松原(@simezi9)です。BASEでは現在ショップ向けの管理画面をリニューアルするプロジェクトが進んでいて、UI/UXの更新と同時に創業当時から継ぎ足して作ってきたフロントエンドの技術スタックを一新しようとしています。この記事では、具体的にそのフロントエンドの更新でどのようなことに取り組んでいるのかをいくつかご紹介したいと思います。

Vue + TypeScriptを利用したMPA(multi page application)化

HTMLの構築をPHP(サーバーサイド)からJS(クライアントサイド)へ移行する

従来の「BASE」の画面ではPHPでHTMLの構築を行っていましたが、HTMLの構築をすべてPHPのコードから分離させて、Vueによるクライアントサイドでのレンダリングにしています。また管理画面の特性上(1ページあたりの閲覧時間が長く相対的にローディングの時間が短くなる)、サーバーサイドレンダリングなどは特に行っていません。

クライアントサイドでのRoutingの導入

Routingに関しては管理画面の機能を大きな単位でいくつかに分割して機能間のRoutingはCakePHPで行い、機能内ではSPAのようにクライアントサイドで細かくRoutingを行っていく構成になっています。フロントエンドのRoutingはVue Routerを利用しています。

f:id:simezi9:20190205125100p:plain f:id:simezi9:20190205125115p:plain

大雑把に責務を整理すると以下のようになります。

  • PHPサーバの役割
    • 大きな機能単位でのRouting
    • RestAPIの提供
  • Javascript(Vue.js)の役割
    • 機能内でのRouting
    • 画面の描画

RestAPIの構築とAPI Blueprintによるカタログの作成

データの取得・操作は基本的に全てAPI経由で行えるように必要なだけのAPIを用意しています。作成したAPIはAPI Blueprintを利用してカタログ化されていてサーバサイドのエンジニアとフロントエンドのエンジニアが疎結合に作業を進めていけるようになっています。

f:id:simezi9:20190205125454p:plain

フロント側でも基本的にAPIの構成と1エンドポイントに対して1ファイルで対応するようにinfra層を構築しています

f:id:simezi9:20190205125511p:plain

なぜVue+TSか

もともとBASEではHTML/CSS/JSによるフロントの構築をすべてデザイナーが担っていてフロントエンドエンジニアというポジションはありませんでした。この次世代管理画面プロジェクトでのフレームワーク選定もデザイナー陣主導で行われました。そのなかでRiot.jsやReactなども試した上で、Vue.jsがもっとも技術導入がスムーズに出来そうだという結論となりVueを採用しました。 また、プロジェクトのサブテーマとして「次の5年を支える」というものがあり、TSが提供する型システムによる安定性がプロダクトのライフサイクルをサポートしてくれることを期待してTSを導入しています。

開発していて実際どうか?

現行のVue2.xとTSの組み合わせはReactなどと比べると劣る面があることは否めない(props周りなど、型が失われてしまう場所が多い)ですが、API通信などのVueが絡まない部分でのTSの型システムのサポートは非常に強力ですし、Vueの次期メジャーバージョンであるVue3.0ではコアがTSに移行し、サポートの強化も表明されており今後に向けた選択肢としてVue.js + TSの組み合わせは有力だと思っています。

Vue.js + TSで最も問題になるのは、公式のドキュメントがJSで書かれていることであり、TSの書き方と若干サンプルコードが異なる という点です。これに関してはVue.jsに馴染みのあるメンバーがいれば大した問題にはなりませんが、全員がVueを初めて触るような場合には、いきなりTSを導入することには慎重になったほうがいいかもしれません(TSとJSはファイル単位で共存できるので後から追加することは難しくない)。

Storeをどうしているか

Vue.jsではデータを一元管理するためのライブラリとしてVuexを使うのが一般的ですが、現状でのVuexはTSとの相性があまりよくなく、せっかくAPIレスポンスの型を定義したのにいざVueコンポーネントで取り出そうとすると型情報が失われてしまいます。そこでTSを活かすためにあえてVuexを採用せず、GlobalEventBusのような構造を拡張した独自のStoreを使っています。この独自実装に関してはそのメリット・デメリットは以下のように現状では一長一短に感じています

  • メリット
    • TSの型をVueコンポーネント内部で利用して堅牢なコードを書ける
    • シンプルな実装で可読性が高い
  • デメリット
    • 最低限の機能しか持たず、Vue.jsのエコシステムの流れからは外れる
    • Vue.js devtoolsのVuexサポートが利用できない

後者のdevtoolsが使えない点に関しては、公式の実装を参考にして、storeの内部状態のダンプなど最低限のデバッグは可能にしています。

f:id:simezi9:20190205125532p:plain

AtomicDesignに基づいた共通UIライブラリの構築

次世代管理画面プロジェクトと並行して社内のサービスで共通して利用するためのUIコンポーネントライブラリを構築しています。現在BASEではAtomic Designを採用したデザインシステムの構築を進めており、そのSketch上のデザインシステムと対応する形でStorybookを利用してコンポーネントライブラリを作っています。 storybook-addon-vue-info@storybook/addon-knobsを利用して、メンバーがStorybookを見るだけでアプリを構築していけるように整備を進めています。

f:id:simezi9:20190205125548p:plain f:id:simezi9:20190205125555p:plain

ブランチ単位での自動デプロイ

このライブラリのリポジトリではブランチを切ってPRを作るたびにブランチ単位でStorybookがビルドされるようになっており、デザイナーとエンジニアの確認が簡単に行えるようになっています。

f:id:simezi9:20190206120054p:plain

自前でUIライブラリを実装していく上での工夫・苦労

  • 最初にコンポーネントを全部用意しようと考えない
  • 一番小さいレイヤ(Atoms)のコンポーネントから作る
  • コンポーネントだけを作ろうとせず、実際に使いながらライブラリを育てる
    • 特にformを構成するコンポーネントなど
  • SketchのデータとStorybookのデータを一致させることにこだわりすぎない
    • 見た目だけではわからないデザインの意図を拾ってStorybookに反映することを心がける

汎用的なコンポーネントを作るのは見た目の単純さに反して考慮することが多く、一発で作ろうとしてもなかなか作りきれません。有名なVueのUIコンポーネントライブラリの一つとしてVuetifyがありますが、その実装を見てもbuttonのtsファイルが170行inputで300行あります。実際自分でコンポーネントを作っても、「あの機能がない」、「このカスタムができない」と問題が続々と出てきては一個ずつ対処する繰り返しになります。その状態で複雑なコンポーネントを用意しても、品質が上がらずコンポーネントの修正の足かせになりがちなので、小さなコンポーネントから我慢して作っていくことが必要だと感じました。

最後に

BASEの次世代フロントエンド環境はまだ開発がはじまったばかりで、実際にはまだまだ課題が山積みです。次世代の管理画面も、UIコンポーネントライブラリも、自分の力で構築していってみたいというエンジニアを募集しているので、興味がありましたらぜひ一声かけていただければと思います。

open.talentio.com