はじめに
Vue.js #4 Advent Calendar 2017 7日目の記事です。
ここ3年以上、WebフレームワークにRails4系を使ったお仕事を色々やってきてます。
フロントエンド側はそれぞれの現場で色々なものを使ってきたのですが、今年は色々タイミングが重なって、Rails4系の環境にVue.jsを使った開発をしてきたので、この1年の取り組みについて紹介しようと思います
何となく想定してる読み手の人のイメージ
- Rails4ベースのサービスの開発に関わってる
- しかもそのサービスは1,2年ほど運用しててそれなりの規模になってる
- 何らかのJavaScriptフレームワークを採用したいけど、色々選択肢があって結局先に進めない
という感じの人をイメージしながら書いてます。
ここでは書かないこと
Rails4+Vue.jsでのSPAの開発のTIPS的なモノには触れていません。(逆に自分が知りたいテーマなので今回のAdventCalendarで誰かそういうのを書いてもらえると嬉しい)
本題に入る前にちょっと前置き
本題の前に、関わってるサービスのRailsの規模について触れつつ、何故Vue.jsを選択したのか簡単に触れておこうと思います。
関わってるサービスのRailsについて
- サービス開始から3年以上運用中
- 当初はRails3で開発をはじめ、Rails4にアップグレードして、今に至っている
- Railsの規模はそれなりのもの
- サービスの成長にいたる過程で、各種機能開発を行ってきたみたい
- ModelとControllerがそれぞれ100を超えてる
- テストは自分がJOINした当初はあえて触れませんが、最近は、頑張って書いてる&サービス上重要な処理についてはかなり網羅出来てきてる
フロントエンド側のJavaScriptの問題点
今関わってるサービスのフロントエンド側について深掘りすると
- 特に明確な根拠もなく色々なjQueryプラグインが利用されている
- 自分たちで作ったものが色々混在しており、コーディング規約も特に無い
という感じになってます。
フリーランスになって色々な現場のお仕事を手伝ってきましたが、似たようなケースをいくつも見ていたので必ずしも今の現場だけではないのかなと思ってます。
とはいえ
- jQueryプラグインは 必ずしも定期的にメンテナンスされてるとは限らない のでそのままずっと利用するのはちょっとツラい
- どういう背景でそのプラグインが導入されてるのか、根拠となる情報がどこにもなかった
という点を考えると、本当に必要かどうかを考えて、その根拠についてしっかり言語化しておくのが大事かなと思いました。
現状の課題解決のために考えた事
フロントエンドJavaScriptにおける設計とテストで触れられてるような、JavaScript側のアプリケーション設計という思想がなかったために、このような状態になってるのかと判断しました。
あまりにも自由度が高いのも良くないと思ったので何らかのJavaScriptのフレームワークを導入して制約となるものを作ったほうが結果的には開発しやすくなるかなと思い、フレームワークの選定をしました。
そこでの選定ポイントはたしかこんな感じだったかと思います。
- 当時はフロントエンド専門にやる人がいない状況だったのでなるべく学習コストが低いものを採用したい
- TaskRunner/bundlerのようなツール類を導入しなくても使えるものにしたい
- ES5のスタイルでまずは試せるものにしたい
- 使ってみてうまくフィットしなかったら捨てても良いとカジュアルに思えるものにする
- RailsもフルスタックなものなのでフルスタックなJavaScriptのフレームワークは避ける
上記の選定ポイントを踏まえてVue.jsに決めた
Vue.jsは公式の日本語ドキュメントがわかりやすく、特に他のフレームワークとの比較を見ていて
「まずは試して、イマイチしっくり来ないようだったら最悪捨てても良いかな」
と気楽に考えることが出来たので、導入してみることにしました。
ちなみに他のフレームワークはこんな理由で採用を見送りました。
フレームワーク | 理由 |
---|---|
Angular |
|
React |
|
Riot | 公式ドキュメントなどを見つつサンプルアプリっぽいのを作ってみたけど、実際に利用していこうと思った時に参考になりそうな情報が見つけ出せず却下 |
ここから本題
前置き長くなりましたが、ここから本題の話をしていこうと思います。
結果的にはRailsの良さを活かしながら控えめにVue.jsを利用した
Rails側で
- helperメソッドを使う
- Decoratorパターンを利用してる何らかのgemを導入する
というアプローチをとることで、Viewとなるファイルの中に複雑なロジックが入り込まなくなるかと思います。
Rails側で出来そうなことは、無理にVue.jsを利用した実装にするのは控えました。
form_forベースのViewにプラスαとなる機能を提供したい箇所でVue.jsを積極的に利用
一方で、何らかのフォーム要素に対して、快適な入力が行えるような仕組みを提供したい場合というのがあるかと思います。
快適な入力というのはちょっと抽象的ですが、例えば
- インクリメンタルサーチのような仕組み
- 入力内容にエラーがあったら、どこがエラーなのかわかるようになってる
というようなケースで、従来のRails側の処理だけではちょっと厳しい・複雑になりそうな処理の場合に積極的にVue.jsを利用する形にしました。
結果としてはform_forベースのViewに対してVue.jsの良さを活かす形のものをこの1年作ってきたと思うので以下で3つのステップで振り返ります。
ステップ1:導入初期
従来複数の画面に分かれていた登録フォーム系の処理を1つの画面に集約するリニューアル時に
- 元々入力項目が多いフォーム
- 利用するユーザー属性(例えば、日本人と外国の人)によって表示項目を動的に切り替えたい
- 必須項目のバリデーションを良い感じにしてほしい
というような感じの想定仕様で、Vue.js使えばイメージ通りのものが出来そうな気がしたので使って見ました。
どのように利用したか?
前述したように、TaskRunner/bundlerのようなツール類を導入せず、かつ、 ES5のスタイルでまずは試したかったので、Railsのapp/assets/javascripts配下 にダウンロードしてきた vue.min.jsを配置して読み込む形で導入しました。
※なお、現状もVue.js本体はこのスタイルで利用してます。
ディレクトリ構成は
├── app.js
└── vue.min.js
こんな感じで、app.jsに
var vm = new Vue({
el: '#some-element',
data:{
someID: '',
japanesePageFlag: true,
isValidSomthing: false,
isValidAnotherSomthing: false,
firstName: '',
// その他多数のdata定義
methods: {
}
というスタイルでまずは実装しました。
導入初期の良かった事
当初のイメージ通り、簡単に始められて思い通りのものが作れたのがとても良かったかなと思います。
開発中に動作するものをディレクター担当に都度見せながら、フィードバックもらって細かい修正依頼も入ったのですが、大幅なロジック変更が伴うことが無かったこともあり、比較的サクッと対応できたのでそういう点でも使って良かったと実感してます。
導入初期の段階で工夫していたこと
自分が作った後に、細かい所で他の人も修正する可能性あったので、社内ではQiitaTeamにこんな感じ↓で画面のどの部分でどういう処理を使ってるのか解説記事を書いておきました。
コードを見てもらいつつ、ある程度ノウハウを共有できたので、最初の段階でこういうのをやっておいて良かったと思ってます。
導入初期の困ったこと
上記のように、app.jsにひたすら処理を書いたので、ちょっと見通しが悪い点が一番困ったことでした。(全部で300行程度だった気がします)
- Component利用する事で改善できるような気もしたのですが、具体的にどのようにして良いのかがこの段階ではイメージがわかなかった
- この機能をリリースしてから自分の役割がちょっと違うことを求められた
という理由で一旦はそのままにしました。
ステップ2:途中苦しみながらもコンポーネントの恩恵を感じられるようになった時期
導入初期の作業からしばらくして、「ある部分だけでも良いので、日本語、英語に加えて、最低限で良いので中国語の対応もしたい」という企画が出てきました。
- 既存のRailsは、Controller&Modelも肥大化していたのですが、それ以上にapp/asssets配下のファイルも把握しづらい状況
- 既存システムが大きすぎるため、ある機能単位で適切に切り出したい
というような事を踏まえて、RailsEngineの仕組みを使って、ある機能単位で作り直すことにしました。
コンポーネントを本格活用する
ステップ1の段階でそれなりにVue.js使えそうという感触を得ていたものの、そのままのアプリケーション設計だと肥大化したapp.jsが出来上がるのが明白でした。
この段階で公式ドキュメントを見ながらコンポーネント使った処理を頑張って書いていきました。
- Componentの概念理解があやふやだったけど、まずはちょっと試してみる
- 親子関係のイメージが掴めてきて、色々作っていたらかなり手に馴染んできたので実装を進める
- 他の人にも理解してもらえるようにサンプルを作ったりこんな資料とかを作ってノウハウを共有するように努力
というようなことを繰り返し特にコンポーネントから親に何か情報を渡す所の処理の理解が中々進まずに途中かなり苦しんだのですが、コンポーネントの恩恵を感じられるようになってきました
コンポーネント化したことの恩恵
RailsEngineの仕組みを使ってる部分のassets/javascriptsはこんな感じになってます。
xxx
├── app.js
├── application.js
├── components
│ ├── master-editor.js
│ └── xxxxx-with-pagination.js
├── filters
│ └── xxx.js
├── model
│ ├── ここはRails側のAPIと連携する処理に特化したものを配置。
│ ├── axiosとかは利用せずRailsに慣れてる人のことを考えてjQueryの$.ajaxベース
│ └── xxxx.js
├── view_model
│ ├── xxx.js
│ └── xxx.js
└── vue.min.js
都道府県の一覧や地域の名称について、日本語以外の言語のマスターデーターを内部で管理する必要がありそのための管理画面で、
<master-editor mastertype="prefectures"></master-editor>
とか
<master-editor mastertype="areas"></master-editor>
という感じの記述をERB側に書いてあげることで、それぞれの言語のデーターが表示・編集できるような仕組みを提供することが出来たのでコンポーネント化の恩恵を凄く感じてます。
ステップ3:RailsとVueのそれぞれの良い所を活かすための設計に悩み始めてる
ステップ2の作業は、今年の6月位からRails側の開発含めて1人で全部やってきて、10月頃からちょっとづつ新しくチームに加わる人が増えて、フロントエンド側中心に開発してきた人も1名ジョインしました。
そうなると
- 自分の役割
- なるべくRails側担当
- フロントエンド側中心に開発してきた人
- Vue.jsを利用した開発にフォーカスしてもらう
という感じである程度分担したほうが作業効率もあがるかなと思ってます。
近いうちに、ある機能について比較的大きなリニューアル作業が発生するかもしれず、想定する仕様考えると、Vue/Vuex+vue-routerとかにした方が開発しやすそうなイメージを持ってる一方で、Rails側とフロント側の処理それぞれの責任範囲をどこで区切るかが結構悩ましいなぁと最近ずっと考えてます。
Rails4でVue/Vuex+vue-routerのような組み合わせだと
xxx
├── app
│ └── Rails側の処理郡
├── front_end
│ └── npmとかを利用して必要なフロント側の開発ツールなど含めてソース一式が配置されるイメージ
└── その他省略
という感じで、Railsの標準構成のディレクトリと別に、front_end のようなディレクトリを作り、フロントエンド側の開発はそこで閉じつつ、build先は、Railsのapp/assets配下になる構成や、完全にリポジトリ切り離して、Rails側も新しく考えて・・・等など色々考えてはいるのですが、判断基準が定まらないので、今年のVue.jsのAdventCalendarで、この辺りの知見を持ってる人のが記事が出るのをちょっと期待してたりします
最後に
個人的な意見ですが、Rails4の環境の場合では、form_forを使った処理でVue.js使った処理がはじめの一歩として取り組みやすいかと思ってます。
知り合いがこういう↓記事を書いててるので、こういうのを参考にしつつ、あとは充実した公式ドキュメントを見ながら、カジュアルに取り組み始めてみても良いかと思ってます。
https://qiita.com/kaorina/items/ea365be58da73d23b54b