IT・技術研修ならCTC教育サービス

サイト内検索 企業情報 サイトマップ

研修コース検索

コラム

Ruby on Rails 海外事情コラム

CTC 教育サービス

 [IT研修]注目キーワード   Python  UiPath(RPA)  最新技術動向  Microsoft Azure  Docker  Kubernetes 

第57回 なぜRails 6にはWebpackerとSprocketsの両方が含まれているのでしょうか? (野田貴子) 2020年6月

こんにちは。アプリケーションを作るときには、様々な技術の取捨選択を行いますよね。たとえば、フロントエンドの実現に使う技術(React、Vue、Angular、jQueryなど)の選択です。私も、これまでに何度も何度も類似技術の調査をして、比較表を作り、上司やチームメイトに提案してきました。その度に、「すでにどこかに要点をまとめたサイトがないものか」と思っていました。

今回紹介する記事は、WebpackerとSprocketsを比較検討するものです。少し長いかもしれませんが、選択に悩んでいるかたは是非お読みください。

なぜRails 6にはWebpackerとSprocketsの両方が含まれているのでしょうか?
Why does Rails 6 include both Webpacker and Sprockets?
https://rossta.net/blog/why-does-rails-install-both-webpacker-and-sprockets.html

ネタバレ:DHHがそう言っているから・・・ですが、自分で選ぶことも可能です。

この投稿を読んでいるみなさんはすでに、Rails 6ではWebpackerとSprocketsの両方がインストールされるということをご存じで、これがWTFになっているのかどうかが気になっているのではないでしょうか。ちなみに、こちらがRailsのすべてのMay of WTFsです。

だって、SprocketsとWebpackerは基本的に同じことをしませんか?

あなたがもしこのように考えていたとしても、それはあなただけではありません。

こちらのRedditの投稿 や、こちらのStackOverflowの質問、またはこちらの別のRedditの投稿のように、同じ質問が増え続けています。

私の同僚の@danmayerはこのようにツイートしています。

https://twitter.com/danmayer/status/1258577270760804353

@avdiも先週このようにツイートしています。

https://twitter.com/avdi/status/1256742291890413570

WebpackerとSprocketsの共存が多くの人を驚かせていることは明らかですが、それには理由もあります。

Sprocketsとwebpackが、「ブラウザー用のアセット(JavaScript、CSS、画像、フォント)のパッケージ化」という同じ課題を解決するという考えは間違いありません。

Sprocketsとwebpackには次の類似点があります。

  • 多くのソースファイルを1つあるいは少数の本番用バンドルに結合する
  • ある構文から別の構文にソースファイルをトランスパイルする
  • 本番用ビルドの際にアセットを縮小してフィンガープリントする
  • 開発中に変更されたソースファイルを段階的に再ビルドする
  • JavaScriptとCSSの両方に対して上記すべてを実行する

ただし、Sprocketsとwebpackのアセットのバンドル方法は非常に異なります。

Sprocketsが発表されたのは2007年(!)で、Node.jsの前、JavaScriptのカンブリア爆発の前、CommonJS、AMD、EcmaScriptモジュールなどのモジュール仕様の前、webpack、browserify、$SONOTA_NO_MODULE_AWARE_ASSET_BUNDLERの前です。Sprocketsは、JavaScriptコミュニティの他のプロジェクトのように、ツールや、言語機能、ブラウザー機能(ソースマップ用の保存)の改善に追いついていません。

一方、WebpackはJavacriptモジュールの概念を完全に取り入れていて、BabelやPostCSSなど、ほぼすべての最近のWebフレームワークを統合します。コード分割のための動的インポートなど、多くのモジュール構文をサポートしています。さまざまな設定用のソースマップオプションもあります。何から何まで、webpackのコンパイルプロセスは常にモジュール化されており、カスタマイズが可能になっています。

では、なぜRailsには両方が含まれるのでしょか?

Rails 5.1で推奨されるJavaScriptコンパイラーとして、Webpackが最初に導入された2016年に、DHHが簡潔でシンプルな答えを出しています。

https://twitter.com/dhh/status/808349072734027776

まばらなJavaScriptや、静的ファイルのCSSや画像などには引き続きアセットパイプラインを使用します。2つのアプローチは共存できます。

この決定について詳しく説明すると、WebpackerをRails 6のデフォルトのJavaScriptコンパイラにするためのGitHubのDHHのプルリクエストで、DHHが次のような返答をしていました。(github.comサイト)

@dwightwatson 興味本位なのですが、CSSや静的アセットはWebpackerがデフォルトでサポートしているのに、Sprocketsを使用し続ける根拠は何ですか?

@dhh 個人的な意見ですが、Webpackのサポートはぎこちなく、Sprocketsに勝るメリットがありません。JavaScriptコンパイルの分野とは違うのです。

紐解くべきものがたくさんあります。

アセットのバンドルに関しては、「Rails的な方法」では、JavaScriptはWebpackで、他のものはSprocketsで扱います。Basecampが使用するものと同様の、Rail 6の新規インストールでのデフォルトのセットアップは、CSS、画像、フォントをSprocketsでコンパイルします。

つまり、Basecampのメンバーであれば、すべてのwebpack JavaScriptのソースファイルは app/javascript にあり、すべてのSprockets CSSと画像は app/assets に残りますが、rails assets:precompile を実行すると、最初にすべてのSprocketsアセットが public/assets ディレクトリにビルドされ、次にすべてのwebpackアセットが public/paks ディレクトリにビルドされます。

明確にしておくと、これはブラウザにアセットを提供するためにSprocketsとWebpackerの両方を実行する必要があるという意味ではありません。アセットをバンドルする2つのプロセスは完全に分離されており、依存関係を共有しません。異なるヘルパー、異なる実装、異なるディレクトリ、すべて異なります。これらは、Railsアプリケーショと共存できるように構築されています。

一方、すべてのアセットをまとめてバンドルするには、SprcketsまたはWebpackerのどちらか一方のみを使用します。

変な感じがしますか?

DHHは、JavaScript以外のアセットを扱うwebpackのアプローチを「変な感じがする(awkward)」と言っていますが、今、私はたまたまWebpackが好きですが、しかし、彼も間違ってはいません。

彼がこう述べる理由は、CSSと画像をwebpackにバルするために、JavaScriptファイルからCSSと画像をインポートする必要があるからです。

import '../application.css'
import myImageUrl from '../images/my-image.jpg'

webpackはすべてをJavaScriptモジュールとして扱いたがっています。「すべて」をです。

JavaScriptのすべてのインポートはJavaScrptモジュールとして扱われます。CSSをwebpackで使用するためにも、JavaScriptモジュールと同じようにインポートします。特にSprocketsの経験者から見ると、これは珍しく映ることでしょう。

これは単に「Rails的な意見」ではありません。Reactコミュニティの著名人であるRyan Florenceのこちらのツイートを考えてみてください。

https://twitter.com/ryanflrence/status/1258966331572928514

逆にSprocketsの良さを理解しているかのように聞こえますか? (私はフィフティーフィフティーに割れたことに驚きません)。

一部の人には変な感じがするかもしれませんが、webpackの「すべてがモジュール」という考え方は非常に強力です。ツールがそのようなメンタルモデルに完全に適合すれば、興味深い可能性が出てきます。「すべてがオブジェクト」の考えがRubyに何をもたらしたのかを考えてみてください。

WebpacerまたはSprockets(あるいは両方)の選択

良いニュースは、これについて心配する必要がないことです。RailsのデフォルトはBasecampチームの推奨アプローチを反映していますが、だからといってあなたがこれに賛同する必要もなければ、これがアプリケーションを作る正しい方法であるわけでもありません。Basecampのように両方を使用することもできますし、どちらか一方を選択することもできます。

みなさんの判断を助けるために、react-raisプロジェクトにあるこちらの素晴らしいガイドを持ってきました。

Sprocketsを選ぶ理由
  • RailsアプリがJavaScriptをあまり必要としていない
  • グローバルスクリプトとjQueryプラグインでの拡張が好きで、適切なJavaScriptモジュールシステムは必要ない
  • レガシーなRailsアプリをWebpackerにアップグレードするとコストがかかりすぎる
  • ローカル開発なので高度なツールは必要ない
  • Sprocketsで上手くいくし、代替案を増やす時間がない
  • Railsアプリが特定のアセットgemに依存しているので、NPMを選択できない
Sprocketsを選ばない理由
  • ローカル開発が遅くなる
  • アセットのコンパイルをより詳細に制御する必要がある
  • Railsアプリに多くのJavaScriptがあり、大量のペイロードを回避するためにコードの分割機能が必要
  • 長期的なサポートが心配
Webpackerを選ぶ理由
  • 適切なJavaScriptモジュールシステムを使用して依存関係を管理したい。つまり、グローバルスコープの汚染を制限し、import/exportとrequireで明示的な依存関係グラフを作成したい

  • ES6以上、Babel、PostCSSの最新機能を活用したい

  • 動的インポートやwebpackのsplitChunks最適化などのインテリジェントなコード分割機能が欲しい

  • ビルドシステムがソースマップを生成する方法に柔軟性を持たせたい

  • ホットモジュールリプレイスメント(HMR)など、ローカル開発用の高度なツールが欲しい

  • シングルページアプリを構築したい*

  • webpackを使用するためにシングルページアプリを用意する必要はありません。「マルチページアプリ」でも非常にうまく機能します。

Webpackerを選ばない理由
  • RailsアプリがJavaScriptをあまり必要としない
  • 自分はバックエンド開発者でJavaScriptエコシステムの知識が限られている
  • WebpackとWebpackerを理解するための時間を費やす準備ができていない
  • 複雑すぎるようにみえる
両方を使う理由
  • 「Rails的な方法」が良い。WebpackerでJavaScriptをコンパイルし、SprocketsでCSS、画像、フォントを扱う
  • SprocketsからWebpackerに段階的にアップグレードしたい
個人的なメモ

Sprocketsはもう過去のものにしたいです。Sprocketsが最初に導入されたときはアセットマネジメントを大きく飛躍させましたが、今はもう新技術を活用していません。コードの分割によるパフォーマンスの最適化など、webpackの主要な機能はファーストクラスなのに、Sprocketsは衰退しています。

Webpackはより複雑で、いくらかの投資が必要ですが、私にとって、その価値はありました。

JavaScriptが大量にあるアプリケーションにはwebpackが良い選択肢だと思います。

みなさんはどちらが合いますか?

 


 

 [IT研修]注目キーワード   Python  UiPath(RPA)  最新技術動向  Microsoft Azure  Docker  Kubernetes