kawasin73のブログ

技術記事とかいろんなことをかくブログです

Webpackerを過去の遺物(1.2)から現代(3.5.5)にバージョンアップする

この記事は、Ruby on Rails その2 Advent Calendar 2018 の 22 日目です。

1 年半前の遺物

約 1 年半前に作った Rails プロジェクトがありました。

受託で 2017 年 4 月に僕 1 人で開発をはじめ、その年の 6 月に僕 1 人で開発を終えたプロジェクトです。

当時は、Rails5.1.0.rc1 から 5.1.0 にアップデートされてリリースされ、webpacker は 1.1 から 1.2 にアップデートされたあたりの時期でした。

その 6 月に開発を終えて heroku にデプロイされたそのアプリはその後大きな改修もなく 放置され 粛々と運用されていました。

その後新しい機能の追加を行う予定がなかったため放置していたプロジェクトですが、突然そのアプリをベースにして新しいビジネスを始めることになりました。

そして、1 年半前の遺物の開発が再び動き出したのです。

1 年半前の遺物を再開発する

2018 年 12 月現在、Rails5.1.0 から 5.2.2 に進化し、webpacker に至っては 1.2 から 3.5.5 まで進化していました。

ライブラリの古いバージョンを使い続けることは、ライブラリの脆弱性のリスクのみならず、最新の開発手法を利用できないために開発効率が上がらず開発スピードの低下にも繋がります。

特にフレームワークである Rails や webpacker では開発効率の低下の影響が大きいです。

時代に取り残されたプロジェクトを最新のバージョンに追随させる作業を 2 日間やっていましたが、その中で一番の大敵だった webpacker1.2 から 3.5.5 へのアップデートの詳細をここで紹介したいと思います。

webpacker とは

webpacker は、Rails で webpack を使ったフロントエンド環境の構築をサポートしてくれるライブラリです。

webpacker は Rails 向けの webpack の設定ファイルの自動生成や、webpack でビルドされた js ファイルや css ファイルと Rails の View テンプレートをバインディングしてくれるヘルパーの提供などをするライブラリです。

webpack をはじめとしたモダンな Web フロントエンド開発環境を簡単に Rails の中で使えるようになる便利なライブラリです。

ただ、webpack の設定を隠蔽しているため細かい調整をしようとすると逆にややこしくなったり、最新の webpack を使えないというデメリットもあり、Web フロントエンジニアのリソースが豊富な場合は素の webpack を使うというプロジェクトもあるようです。

いかんせん僕は 1 人で開発しているので webpack と Rails の橋渡しの部分の設定を任せるために webpacker を使っています。

また、heroku では webpacker を検出して自動で npm モジュールのインストールや webpack のコンパイルとアセットファイルの設定を行ってくれます。そのデプロイの容易さも heroku + Rails 環境で webpacker を使うメリットです。

webpacker 1.23.5.5 の違い

まず、webpacker をアップデートする上で設定ファイルなどのファイル構成がどう変わったのかを知る必要があります。

Rails のバージョンの差異は、RailsDiff という Web サイトで容易に確認することができますが、webpacker ではそのようなサイトは発見できなかったので自分で差異を調べることにしました。

Ruby 2.4.5 + Rails 5.1.0 + webpacker 1.2Ruby 2.4.5 + Rails 5.1.0 + webpacker 3.5.5 のそれぞれで rails new をしてプロジェクトを作成してそのファイル構成の差分を取ることにしました。

プロジェクトの作成には、docker で rails の開発環境を作成する自前の rails_docker_template を利用しました。( Rails プロジェクトを Docker で開発したい場合は参考にしてみてください。)

それによって2つのバージョンの rails new を試してみました。内容は以下のリポジトリにアップロードしてあります。

github.com

以下のスクリプトでプロジェクトを作成しました。

$ script/init

// webpacker のバージョンを指定してインストール

$ bin/rails webpacker:install
$ bin/rails webpacker:install:react

git diff の結果は以下の通りです。

Diff between 1.2 and 3.5.5 · Issue #1 · kawasin73/webpacker_diff · GitHub

$ git diff ruby-2.4.5-rails-5.1.0-webpacker-1.2 ruby-2.4.5-rails-5.1.0-webpacker-3.5.5 --name-only
.babelrc
.gitignore
.postcssrc.yml
Gemfile
Gemfile.lock
bin/webpack
bin/webpack-dev-server
config/environments/development.rb
config/environments/production.rb
config/secrets.yml
config/webpack/configuration.js
config/webpack/development.js
config/webpack/development.server.js
config/webpack/development.server.yml
config/webpack/environment.js
config/webpack/loaders/assets.js
config/webpack/loaders/babel.js
config/webpack/loaders/coffee.js
config/webpack/loaders/erb.js
config/webpack/loaders/react.js
config/webpack/loaders/sass.js
config/webpack/paths.yml
config/webpack/production.js
config/webpack/shared.js
config/webpack/test.js
config/webpacker.yml
package.json
yarn.lock

ただ git diff をしても CLI ではその差異がわかりにくかったので、SourceTree という GUI の git クライアントアプリでその差分を見てみました。

f:id:kawasin73:20181222230438p:plain

なるほど。

これで設定ファイルのどれが不要になってどれが追加され、どれが中身が変更されたのかがわかりました。

公式のアップデートコマンド

webpacker の README ( https://github.com/rails/webpacker#upgrading )でバージョンアップするためのコマンドが紹介されています。

bundle update webpacker
rails webpacker:binstubs
yarn upgrade @rails/webpacker --latest
yarn add webpack-dev-server@^2.11.1

# Or to install a latest release (including pre-releases)
yarn add @rails/webpacker@next

これを、webpacker 1.2 のプロジェクトに対して実行し 3.5.5 までアップデートしてみました。その差分は以下のコミットです。

Upgrade webpacker to 3.5.5 · kawasin73/webpacker_diff@c41fc94 · GitHub

これによると以下のことがわかります。

  • bin/webpackbin/webpack-dev-server というスクリプトの中身が変更されており rails webpacker:binstubs を実行することによって上書き変更される
  • @rails/webpacker という謎の npm パッケージが使われるようになっている。
  • webpack-dev-server2.11.1 でバージョン固定されている。
  • 設定ファイルの追加や削除、修正はされない

謎の npm パッケージ @rails/webpacker

ここで、@rails/webpacker という謎の npm パッケージがインストールされていることが発覚しました。その中身は以下の開発支援用のパッケージの集合です。

@rails/webpacker - npm

Dependencies (25)

  • babel-core
  • babel-loader
  • babel-plugin-syntax-dynamic-import
  • babel-plugin-transform-class-properties
  • babel-plugin-transform-object-rest-spread
  • babel-polyfill
  • babel-preset-envcase-sensitive-paths-webpack-plugin
  • compression-webpack-plugin
  • css-loader
  • extract-text-webpack-plugin
  • file-loader
  • glob
  • js-yaml
  • node-sass
  • optimize-css-assets-webpack-plugin
  • path-complete-extname
  • postcss-cssnext
  • postcss-import
  • postcss-loader
  • sass-loader
  • style-loader
  • uglifyjs-webpack-plugin
  • webpack
  • webpack-manifest-plugin

Dev Dependencies (6)

  • eslint
  • eslint-config-airbnb
  • eslint-plugin-import
  • eslint-plugin-jsx-a11y
  • eslint-plugin-reactjest

このパッケージのほとんどは webpacker 1.2 では package.json に直接記載されてインストールされていたものです。それを @rails/webpacker にまとめたものであると理解しました。

しかし、開発支援用のパッケージのうちビルドに必要なパッケージがが Dev Dependencies ではなく Dependencies としてインストールされているのはちょっと気持ち悪いです。

この理由は以下の issue で議論されている通り production 環境で js ファイルのビルドをできるようにするために Dependencies に配置されているようです。

Webpack executable not found on production · Issue #117 · rails/webpacker · GitHub

ここを独自にわざわざ Dev Dependencies に変更して本来の Dependencies のあり方を求めるより、Rails way にのっとってパッケージ管理を webpacker の内部に隠蔽して開発をスムースに進めることのメリットが大きいと判断して @rails/webpacker パッケージをそのまま使うことにしました。

アップデートの方針

アップデートは以下のように行うことにしました。設定ファイルの更新は自動ではやってくれないので自分で1ファイルずつ編集していきます。

webpacker のアップデート

Gemfile の webpacker3.5.5 にあげてアップデートします。

$ bundle update --conservative webpacker

アップデートコマンドで上書きするファイル

$ bin/rails webpacker:binstubs

このコマンドを実行することで以下のファイルが更新されます。

  • bin/webpack
  • bin/webpack-dev-server

追加するファイル

以下のファイルを追加します。ファイルの内容は webpacker 3.5.5 でビルドしたもの からコピーします。

  • config/webpack/environment.js
  • config/webpacker.yml

削除するファイル

以下のファイルを削除します。

  • config/webpack/configuration.js
  • config/webpack/development.server.js
  • config/webpack/development.server.yml
  • config/webpack/loaders/assets.js
  • config/webpack/loaders/babel.js
  • config/webpack/loaders/coffee.js
  • config/webpack/loaders/erb.js
  • config/webpack/loaders/react.js
  • config/webpack/loaders/sass.js
  • config/webpack/paths.yml
  • config/webpack/shared.js

修正するファイル

以下のファイルを 1.23.5.5 の差分をみて修正していきます。差分は Diff between 1.2 and 3.5.5 · Issue #1 · kawasin73/webpacker_diff · GitHub にまとめてありますが、SourceTree などの GUI アプリで差分を見た方がわかりやすいと思います。

  • .babelrc
  • .gitignore
  • .postcssrc.yml
  • config/webpack/development.js
  • config/webpack/production.js
  • config/webpack/test.js
  • config/environments/development.rb
  • config/environments/production.rb

package.json

1.23.5.5 の差分をみて package.json から @rails/webpacker パッケージにまとめられるパッケージを削除します。( Diff between 1.2 and 3.5.5 · Issue #1 · kawasin73/webpacker_diff · GitHub

そのあと、以下のコマンドで @rails/webpacker をインストールし、webpack-dev-server@^2.11.1 をインストールします。

$ bin/yarn add @rails/webpacker
$ bin/yarn add webpack-dev-server@^2.11.1

以上で webpacker のアップデートは完成です。

最後に

ここまで慎重に調査するのに疲れましたが、なんとか webpacker を 1.2 から 3.5.5 にアップデートできました。

これは、プロジェクトを作った時に webpacker の設定を独自に変更せずにそのまま使っていたのも功を奏していると思います。

おそらく、webpacker の 1.2 なんていう過去の遺物を使っているプロジェクトは少ないんじゃないかと思いますが、アップデートする時は参考にして見てください。

現場からは以上です。