この記事は、Ruby on Rails その2 Advent Calendar 2018 の 22 日目です。
1 年半前の遺物
約 1 年半前に作った Rails プロジェクトがありました。
受託で 2017 年 4 月に僕 1 人で開発をはじめ、その年の 6 月に僕 1 人で開発を終えたプロジェクトです。
当時は、Rails が 5.1.0.rc1
から 5.1.0
にアップデートされてリリースされ、webpacker は 1.1
から 1.2
にアップデートされたあたりの時期でした。
その 6 月に開発を終えて heroku にデプロイされたそのアプリはその後大きな改修もなく 放置され 粛々と運用されていました。
その後新しい機能の追加を行う予定がなかったため放置していたプロジェクトですが、突然そのアプリをベースにして新しいビジネスを始めることになりました。
そして、1 年半前の遺物の開発が再び動き出したのです。
1 年半前の遺物を再開発する
2018 年 12 月現在、Rails は 5.1.0
から 5.2.2
に進化し、webpacker に至っては 1.2
から 3.5.5
まで進化していました。
ライブラリの古いバージョンを使い続けることは、ライブラリの脆弱性のリスクのみならず、最新の開発手法を利用できないために開発効率が上がらず開発スピードの低下にも繋がります。
特にフレームワークである Rails や webpacker では開発効率の低下の影響が大きいです。
時代に取り残されたプロジェクトを最新のバージョンに追随させる作業を 2 日間やっていましたが、その中で一番の大敵だった webpacker
の 1.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.2
と 3.5.5
の違い
まず、webpacker をアップデートする上で設定ファイルなどのファイル構成がどう変わったのかを知る必要があります。
Rails のバージョンの差異は、RailsDiff という Web サイトで容易に確認することができますが、webpacker
ではそのようなサイトは発見できなかったので自分で差異を調べることにしました。
Ruby 2.4.5 + Rails 5.1.0 + webpacker 1.2
と Ruby 2.4.5 + Rails 5.1.0 + webpacker 3.5.5
のそれぞれで rails new
をしてプロジェクトを作成してそのファイル構成の差分を取ることにしました。
プロジェクトの作成には、docker で rails の開発環境を作成する自前の rails_docker_template を利用しました。( Rails プロジェクトを Docker で開発したい場合は参考にしてみてください。)
それによって2つのバージョンの rails new
を試してみました。内容は以下のリポジトリにアップロードしてあります。
- webpacker
1.2
- webpacker
3.5.5
以下のスクリプトでプロジェクトを作成しました。
$ 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 クライアントアプリでその差分を見てみました。
なるほど。
これで設定ファイルのどれが不要になってどれが追加され、どれが中身が変更されたのかがわかりました。
公式のアップデートコマンド
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/webpack
とbin/webpack-dev-server
というスクリプトの中身が変更されておりrails webpacker:binstubs
を実行することによって上書き変更される@rails/webpacker
という謎の npm パッケージが使われるようになっている。webpack-dev-server
は2.11.1
でバージョン固定されている。- 設定ファイルの追加や削除、修正はされない
謎の npm パッケージ @rails/webpacker
ここで、@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 の webpacker
を 3.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.2
と 3.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.2
と 3.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
なんていう過去の遺物を使っているプロジェクトは少ないんじゃないかと思いますが、アップデートする時は参考にして見てください。
現場からは以上です。