20
14

More than 1 year has passed since last update.

importmap とか jsbundling-rails とか tailwindcss-rails とか何なんだよ!

Last updated at Posted at 2023-04-20

これは何

  • 2023/04/20 の gotanda.rb#52 の発表資料です
    • もともと社内 wiki にメモがてら書いたものを転用しています

自己紹介

概要

  • rails でフロントエンドをやっていく方法は、rails のバージョンとともに移り変わっている
    • rails 5 くらいまでは sprockets がメイン
    • rails 6 くらいからは webpacker がメイン
    • rails 7 になってからよくわからなくなった
      • 体感、このあたりから「rails でフロントエンドまでやるのやめよう」「逆にサーバーサイドも js でやろう」のような流れが強くなった感覚がある
  • この記事では、そんな rails 7 でフロントエンド開発をどう進めるのがよさそうか整理してみた

rails 7 における選択肢

[補足] なんで選択肢が増えたのか?

  • rails 脳に染まっていると、「rails 公式がおすすめする唯一の手法を提示してほしすぎる!」となってしまうが、なぜここにきて rails は Import Maps と Bundling Gems という 2 つの道を用意したのか?
  • この点について、wantedly の技術ブログに書かれていることがそれっぽかったので引用

Railsは「Rubyでワンストップのエコシステムを提供することにこだわるか」「Node.jsのよくできた(そして多くのフロントエンドエンジニアが使い慣れた)エコシステムに身を委ねるか」というジレンマに悩まされるようになったのだといえます。Webpackerはその中間的な存在であり、お世辞にも上手くいったとは言えないのではないかと思います。

Rails 7.0では、ひとつの方法で全てのユーザーを幸せにすることを諦めて、複数の選択肢を提示するという方向に舵を切ったのでしょう。これは今までのRailsのあり方とは異なるようにも見えますが、フロントエンドエコシステムについてRailsが抱える問題に正面から向き合った結果だとも思います。

Import Maps

  • node.js を一切使わずにやっていくパターンの手法
  • importmap-rails という gem で実現
  • import map という言葉自体は、ブラウザのレイヤーに存在する機能を指している
    • 事前処理で import を解決して複数の JS を 1 ファイルにまとめてから配信するのではなく、ブラウザ自身が複数の JS を import して使えるようにする機能
  • ようは、最近のブラウザはブラウザ自身で import を解決できるんだから、自前で頑張らずにブラウザに任せちゃえばよくね?という発想
    • vite の哲学に近い気がする(曖昧です)
  • import をブラウザに任せることで、以下のようなメリットがある
    • 事前の bundling (複数の .js を 1 ファイルにまとめる作業) が不要
    • 事前の bundling のための node.js の導入が不要
    • 例えばアプリが JS パッケージ A と B と C に依存していて、B だけ更新があったときに、B のキャッシュだけ invalidate して最小限の再取得で済ませられる
      • 全てを bundling していると、B だけの更新のために A + B + C の巨大な 1 ファイルを再取得する必要がある
  • ただし、デメリットも存在する
    • モダンなブラウザにしか対応できない
      • import map に対応している必要あり
      • 複数の js を並列でリクエストできるように、HTTP 2 に対応している必要あり
        • これはサーバー側もそう
    • トランスパイルもしなくなるので、 例えば JSX をコンパイルできない
      • これで必要十分になるくらい JS を使わないプロダクトじゃないと、Import Maps でやっていくのは厳しそう
  • import map 自体が JS のための仕組みなので、CSS は対象外っぽい
    • CSS を使いたい場合は、昔ながらの app/assets/stylesheets 配下に書いて sprockets に任せるとか、後述の tailwindcss-rails を使うとかになる?
  • config/importmap.rb というファイルで依存管理する
    • bin/importmap pin <package name> みたいなコマンドもある
config/importmap.rb
pin "react", to: "https://ga.jspm.io/npm:react@17.0.2/index.js"
pin "react-dom", to: "https://ga.jspm.io/npm:react-dom@17.0.2/index.js"
pin "object-assign", to: "https://ga.jspm.io/npm:object-assign@4.1.1/index.js"

Bundling Gems

  • node を使うパターンの手法
  • jsbundling-railscssbundling-rails という gem を使って実現
  • トランスパイルと bundling だけいい感じにやって、app/assets 配下においてくれる
    • その先は sprockets に任せる
      • つまり sprockets を置き換えるものではなく、むしろ協調作業になる
    • トランスパイルと bundling をどうやって実現するかは、複数の候補の中から選択できるっぽい
  • package.json で依存管理する(曖昧です)

Import Maps とあわせて使いたい: tailwindcss-rails

  • https://github.com/rails/tailwindcss-rails
  • Import Maps パターンのように、node.js を導入したくない場合に検討すべきパターンがこれ
  • tailwind は v3 系からビルドの概念が導入されている
    • tailwind が提供する巨大なスタイル定義を丸ごと配信する代わりに、実際に参照されているクラスに紐づくスタイルだけを抜き取って css ファイルを生成する処理が導入された
      • これまでは似たようなことをするために PurgeCSS というものを使っていた
  • ビルドを行うには node.js が必要になるが、tailwind は公式に stand alone cli なるものを配信していて、これを使えば node.js を導入せずにビルドが可能になる
  • tailwindcss-rails gem は、その stand alone cli をラップしている
  • つまりImport Maps & tailwindcss-rails の組み合わせなら、node.js と一切関わらずに rails のフロントをやっていくことができる
  • 逆に、Import Maps ではなく Bundling Gems を使っていく場合(= node.js の導入を受け入れる場合)、あえて tailwindcss-rails を使ったりせず、おとなしく node.js に染まって cssbundling-rails を使うほうがよいっぽい
  • 前述の通り Import Maps では CSS の依存関係を扱えないので、こういう gem で管理する感じになっているが、なんだか webpacker 以前に戻ったような?

まとめ

  • node.js と関わりたくない場合
    • JS は importmap-rails を使う
    • CSS は tailwindcss-rails を使う or Sprockets を使う?
  • node.js との関わりを受け入れる場合
    • JS は jsbundling-rails を使う
    • CSS は csbundling-rails を使う
20
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
14