てくすた

ピクスタ株式会社のエンジニア・デザイナーがつづるよもやまテクニカルブログです

browserify から webpack に移行した話

はじめまして、技術推進チームの id:yszk0123 です。

ピクスタではアプリケーション開発に Ruby on Rails (以下 Rails と表記) をメインで使っていますが、最近 JavaScript (以下 JS と表記) 周りのビルドツールを browserify から webpack に移行しました。本エントリでは、webpack に移行した理由や、Sprockets との兼ね合い、最近登場した webpacker との比較について話したいと思います。具体的な導入方法については Qiita のエントリをご参照ください。

qiita.com

次のような読者が対象です。

  • Rails エンジニア
  • モダンなフロントエンド環境を Rails で使いたい人
  • webpack と Sprockets を共存させたい人
  • webpacker を導入できない・導入に迷っている人

背景

Rails では、JS をはじめとした assets ファイルの管理にはデフォルトで Sprockets が使われます。ピクスタでも Sprockets を使っており、それに加えて Yarn と browserify を使って依存関係の管理やビルドを行っていましたが、問題がいくつかありました。

まず、Sprockets を使っていると JS 周りのエコシステムを最大限に活用できないという問題があります。また、browserify によるビルドとの相性が良いとは言えませんでした1

とは言っても、Sprockets を全く使用しないというのは難しいです。すでに多くの箇所で使われている javascript_include_tag のようなパス解決のためのヘルパーメソッドはそのまま利用したいと考えました。

また、browserify は webpack よりもシンプルで扱いやすいですが、最近登場した開発ツールは webpack 向けに実装されることが多く、browserify では対応できない場面が増えてきました2

もう1つ、Rails5.1 から導入された webpacker を使えば JS 周りの開発フローが大幅に簡略化できますが、Rails5.1 以前では使えない、結合が密でいざという時に捨てにくい、といった問題があります3

このような理由から、ピクスタでは browserify や webpacker を使わず、webpack と Sprockets を適度に共存させる構成を採用しました。

導入

Sprockets によるビルド過程をすべて webpack で行うようにして、javascript_include_tag と stylesheet_link_tag のパス解決にのみ Sprockets を利用するようにしました (下図参照)。

f:id:yszk0123:20170509173551p:plain

表向きの機能は変わりませんが、全てのページのJSに影響するため、少しずつリリースすることで影響範囲を狭めるようにしました。

結果

webpack を基本とした構成にすることで、柔軟な設定ができるようになり、今後の改善の土台が整ったと思います。 Rails のレールから大きく外れないように配慮したため、大きな変更も必要ありませんでした。

一方で、難しかった点もあります。 ファイルの圧縮やダイジェスト値の付与といった Sprockets の挙動を理解し、それを再現する webpack の設定を考える必要がありました。 また、browserify に比べると webpack の仕組みはかなり複雑なため、開発チーム内に使い方を普及させる必要がありました。

おわりに

このようにして、主要なサービスに webpack を導入することができましたが、本当に行いたい改善はこれからです。 今後は計測の仕組み化や設定のチューニングを行っていきたいと思います。

ピクスタでは、より良い開発環境を作るのが好きなエンジニアを募集しています!


  1. 例えば uglify-js のバージョン管理や圧縮をフロントエンド側で行いたい。source maps が上手く動かない。等々

  2. 例えば CSS Module を扱うためのプラグイン。browserify にも同様のプラグインがありますが、まだ試験段階のようです。

  3. grunt や gulp のプラグインのようにバージョンアップに追従できない問題や、rollup のような新たなツールが登場する中で、webpack がいつまで生き残るかと言った不安もあります。似たような理由で grunt や gulp の使用も避けています。