「俺の最近のRailsのJS開発環境」 for フロントエンドエンジニア
TL;DR
- 「片手間のJS」ならhogehoge-railsで大丈夫(e.g. browserify-rails, sass-rails, etc.)
- 「本気でJS書く」ならsprocketsから切り離す(e.g. SPA, etc.)
- 迷えるフロントエンドエンジニアに愛の手を
※ 個人の見解です
はじめに
本記事の内容は個人の見解であり、所属する組織の公式見解ではありません.
本職は学生,片手間にRailsエンジニア,そのさらに片手間に過激派フロントエンドエンジニアやってる人間の戯言です.
『俺の最近のRailsのJS開発環境を教えてやる』を受けて,フロントエンドエンジニアの視点から見たRailsのJS環境を考察してみた記事になります.
元記事をdisっているわけではなく,むしろリスペクトしたうえで視点を変えてみたという内容です(不愉快に思われたらもうしわけありません).
あと,途中まで書いて1週間ぐらい寝かせたら何書いてたか忘れたので,推敲せずそのまま公開しちゃった記事になります.
言ってることが破綻していたら適宜修正するので優しく教示いただけると幸いです.
俺の最近のRailsのJS開発環境を教えてやるについて
Sprocketsを使っており,Rails Wayから逸脱することなくモダンJSに追従していくという例であり非常に参考になる.
開発時はいつもどおりにapp/assets
以下にコード書いていけばいいし,デプロイはいつもどおりrake assets:precompile
すればいいだけである.
Railsエンジニアはいままでの環境をほぼ崩さなくていい.フロントエンドエンジニアは普段通りBrowserifyが利用できる.Babelifyを使えばES6のコードが書ける.頑張ったらテストだってできる.
Railsエンジニアが片手間にJS書いてて,最新のJSに追い付きたいということであれば十分である.
なにが足りない?
一見すると何も問題ない,みんなが幸せになれる環境である.
なにが足りないのか.
例としてSassを取り上げる.
Sass 3.3よりmapというデータタイプが追加されている.飛び散りがちなSassの変数定義をいい感じのデータ構造でくるんだりできる,素晴らしい機能である.このSass 3.3がリリースされたのが2014年7月7日.ではRailsのSprockets上でSassを扱うためのgemであるsass-railsがSass 3.3に対応したのはいつか,2014年12月13日リリースのv5.0.0である(それ以前はSass 3.1しか使えなかった).
Railsエンジニアは最新追っかけて新機能とキャッキャウフフしてて楽しいかもしれないが,フロントエンドエンジニアはSprocketsが対応してくれるまで首を長〜くして延々待たないといけないのである.
もし何らかの理由でRailsがアップデート出来ない状況であれば,それにつられてSassも半分ミイラ化した古のバージョンを使い続けることを強いられてしまう.
似たような状況はSassとsass-railsのような関係を持つライブラリ全てに起こり得る.
Browserifyとbrowserify-rails,TypeScriptとtsify,fontawesomeとfontawesome-rails,….すぐに本家に追従してくれるかの保証はない.大きくAPIが変わったりするとついていってくれないかもしれない.
これらの被害を被るのはすべてフロントエンドエンジニアなのである.
普段からブラウザの依存問題に悩まされてるのに,こんどはRailsとモダンJSの相性問題に苦しめられるなんて….
JSのテストどうすんねん問題
個人的にはこれもかなり深刻だと思っている.
- sprocketsの
require
ディレクティブを使ったJSのコードをテストしたいとき -
app/assets/templates
等に配置したJSから利用するテンプレート群の扱い
など.
JSのテストしたいだけなのにわざわざRailsアプリ立ち上げてコンパイルとかしてたら時間の無駄になる.
AngularJSのテストしたいからkarmaつかいたい! karma-rails入れよう!とかなるとまた無駄な闇を踏むかもしれない.
karma-rails使うために面倒くさい作業をするのは「JSのテストなんてあまり関係ないRailsエンジニア」か「Railsは専門でない,JSのテスト書きたいフロントエンドエンジニア」か,どちらになるんでしょうかね.
Sprockets.evil? # => false
別にSprocketsが悪であると言いたいわけではない.
登場した当初はCSS/JSの依存を解決することができるrequire
ディレクティブは画期的であり素晴らしいものであった(筆者はSprockets以前のRailsを知らない世代ではあるが…).
ただ,CSS/JSのエコシステム外からそれらを管理するということに無理が生じるのはどうしようもないことであるような気がする.
RailsがRails自身のことを考えつつ,CSS/JSの進化に完全に追従していくというのがそもそも無理な要求なのかもしれない….
ならどうするか: JSの世界でJSを書く
Sprocketsからの脱却を目指す.
方針
gulp/gruntなどのフロントエンド界のツールを利用してJS/CSSをビルドしていく.
これで無理なくフロントエンド側のエコシステムに追従できる.
Railsとの共存だが,ビルド結果をpublic/{javascript,stylesheet}s
以下に配置することでjavascript_include_tag
やstylesheet_include_tag
等のViewヘルパを利用できる.
また,本番ビルド(Rails界で言うところのrake assets:precompile
)時にgulp-rev及びgulp-rev-rails-manifestを利用することでdigestの恩恵も受けることができる.
これについては『Sprockets再考 モダンなJSのエコシステムとRailsのより良い関係を探す - Qiita』を参照されたい.
gulpfile?
gulpfileについては以下の記事でも読んで全力で憔悴したらいいと思う.
自分の専門領域ならyak shavingはたのしい
- npm で依存もタスクも一元化する - Qiita
- もうgulpで憔悴しない - 低依存gulpfileのレシピ - Qiita
- web-starter-kit/gulpfile.babel.js at master · google/web-starter-kit
ディレクトリ構造
app/assets
は使わない.
JavaScript/StyleSheetはすべてfrontend/assets
以下に書いていく: Railsとはほぼ別プロジェクト扱いになる.
.
├── Gemfile # いつもの(Rails側に徹する)
├── package.json # JSのライブラリ(全部npmで)
├── gulpfile.coffee # JS/CSSのビルドスクリプト(別に何でもいい)
├── app
│ ├── assets # つかわない
・ ・
・ ・
・ ・
│
├── frontend
│ └── assets
│ ├── javascripts # *.js/*.coffee/*.ts等の元ファイル
│ ├── templates # JSから利用するHTML等のテンプレート
│ └── typings # TypeScript用型定義ファイル
├── tmp
│ └── javascripts # 一時ファイル(templateをJSにしたやつとか)
├── public
│ ├── javascripts # 開発用ビルドされたJSが入る
│ ├── stylesheets # 開発用ビルドされたCSSが入る
│ └── assets # 本番用ビルドされたJS/CSSが入る
・
・
・
別の方策: Sprocketsのload pathを弄る
@joker1007 氏よりフィードバックをいただいた.
俺の書いた記事が出てた。最近はgulp + browserifyを適当な所に吐いてそこをsprocketsのロードパスにしつつsourcemapの出力先を調整するか、public/assetsに直接吐くかのどっちかって感じ。 http://t.co/sLS46kUvON
— イカはじめました joker0x3ef (@joker1007) June 30, 2015
@izumin5210 ありがとうございますー。sprocketsのロードパスにしておいて圧縮とかmanifestの生成をassets:precompileに任せるイメージですね。vendor/assets以下にjqueryのプラグインを置くみたいなイメージです。
— イカはじめました joker0x3ef (@joker1007) June 30, 2015
@izumin5210 やはり何もかも上手くいくわけはなく、sourcemapに対してブラウザがアクセスする時のパスとsourcemapが認識しているソースコードまでのパスを上手く調整しておかないと駄目なのが少し難点です。
— イカはじめました joker0x3ef (@joker1007) June 30, 2015
この記事ではpublic/javascripts
に吐いてたもの(=> browserifyのビルド結果とか)を何処か別の,Sprocketsのload pathに含まれるディレクトリに吐くようにしたもの.これでgulp-rev
/gulp-rev-rails-manifest
やminify系のモジュールを使わず,rake assets:precompile
だけで済ませられる.
イメージとしてはvendor/assets
に追加したみたいな感じ.
ただ,sourcemapまわりでややこしさは残るらしい.
僕もどちらかと言うと@joker1007さんのやり方が好きかもしれない(?)
Sprocketsのload path弄るのは『2.2.1 Search Paths | The Asset Pipeline — Ruby on Rails Guides』に書いてある.
Conclusion
だらだらの思いつくままに書いてみたが,結局は冒頭に書いたような考え方でいい気がしている.
- 「片手間のJS」ならhogehoge-railsで大丈夫(e.g. browserify-rails, sass-rails, etc.)
- 「本気でJS書く」ならsprocketsから切り離す(e.g. SPA, etc.)
- 迷えるフロントエンドエンジニアに愛の手を
sprocketsと共に生きるか,見捨てるか.
現時点ではどちらがベストとも言い難い.
みんなで一緒になって,血で血を洗う殴り合いと泥臭い議論をしよう.