はじめに
※この文章はベータ版です。
既存のプロジェクトで Rails5.2 + Webpacker 3.5.5 -> Rails6.1 + Webpacker5.2.1 -> Rails6.1 + jsbundling-rails
(-> Rails7.0 + jsbundling-rails)したので、手順etc をメモしておきます。
Rais6 -> Rails 7 する際には、Webpacker -> jsbundling-rails、turbo-links -> turbo など、Rails7 からの正式採用なものの
Rails6 でも動作する gem への移行、Rails6 では動作するもののRails7以降への対応が怪しい gem の Rails7対応済/対応中の
gemへの移行、(例:Refile -> Shrine)をインクリメンタルに行なってから、Rails6 -> Rails7 することをオススメします。
Rails5.2 -> Rails6.1
プロジェクトの rails & Webpacker gem を更新する
プロジェクトのルート・パスに移動後、gems.rb(Gemfile) を編集し、バンドルされた gem を更新します。
% vim gems.rb
gem 'rails', '~> 6.1.0'
gem 'webpacker', '~> 5.2.1'
% bundle update
表示されるメッセージで gem の依存関係を確認し、依存関係に問題がなくなるように gems.rb(Gemfile) を編集し、bundle update
を実行します。この作業をエラーが出なくなるまで繰り返します。
アップデートタスクを実行する
% bundle exec rails app:update
プロジェクトをGit etcでリポジトリでバージョン管理していない場合にはバックアップをとってから実行します。
実行により、いくつかのファイルのコンフリクトが指摘され、上書きするかどうか訊いてきますが、全て、上書きします。
上書きされたファイルとリポジトリ上(or バックアップ)にある対応するファイルの差分をチェックし、上書きされたファイルに必要な記述を復元します。
Webpacker 3.5.5 -> 5.2.1
% bundle exec rails webpacker:install
実行により、いくつかのファイルのコンフリクトが指摘され、上書きするかどうか訊いてきますが、全て、上書きします。
上書きされたファイルとリポジトリ上(or バックアップ)にある対応するファイルの差分をチェックし、上書きされたファイルに必要な記述を復元します。
Vue.js まわりのアップデート (オプション)
% bundle exec rails webpacker:install:vue
他のフレームワークを利用している場合には、対応したタスクがあれば、それを実行します、対応したタスクがない場合には自前で更新します。
babel-loader の設定変更 (オプション)
Vue.jsでHTMLテンプレートのコンパイルをブラウザでの実行に行う場合にはconfig/webpack/environment.js
に次の設定のどちらかを追加します。
// Vue.js フル版(Compiler入り)
environment.config.resolve.alias = { 'vue$': 'vue/dist/vue.esm.js' } // Vue2
environment.config.resolve.alias = { 'vue$': 'vue/dist/vue.esm-bundler.js' } // Vue3
この設定がないときは、コンパイラなしの
vue/dist/vue.runtime.esm.js (Vue2)
/ vue.runtime.esm-bundler.js (Vue3)
が、読み込まれます。
(Vue.jsでHTMLテンプレートの実行時コンパイルを行なっている場合、エラーになります。)
rails-erb-loaderのアップデート (オプション)
% bundle exec rails webpacker:install:erb
node_modules の更新
% yarn install
表示されるメッセージで NPM モジュールの依存関係を確認し、必要な NPM モジュールがあればyarn add
でインストールしてから、再度、yarn install
を実行します。この手順をエラーが出なくなるまで繰り返します。
.babelrc の削除
Webpackerの3.xでは必要でしたが、Webpacker4.x 以降では、babel.cofig.js
、postcss.config.js
、.postcssrc.yml
に置き換わっているので、削除します。
バンドル
% bin/webpack
動作確認
% bundle exec rails s
rails-ujs -> @rails/ujs (オプション)
% yarn add @rails/ujs
Sprocketsを利用している場合は、
app/assets/javascripts/application.js
のrails-ujs
を@rails/ujs
に変更します。
//= require @rails/ujs
Webpackerを利用しているorする場合は、app/javascript/packs/application.js
に、次の2行を追加します。
import Rails from '@rails/ujs';
Rails.start();
Webpackerでの管理に新規に移行する場合には、erbにあるjavascript_include_tag 'application'
をjavascript_pack_tag 'application'
に変更します。
WebPackerの 設定変更 (オプション)
SplitChunk の有効化 (オプション)
config/webpack/environment.js
に次の設定を追加します。
environment.splitChunks()
erbにある javascriot_pack_tag
をjavascript_packs_with_chunks_tag
に変更します。
node_modules を babel-loader の対象から除外する(オプション)
config/webpack/environment.js
に次の設定を追加します。
environment.loaders.delete('nodeModules')
Webpacker4.x以降では、デフォルトでは、node_modules
ディレクトリにあるファイルが babel-loader 経由での(Babelの)トランパイルの対象になっています。
この追加により、Webpacker3と同様にWebpacker4以降でもbabel-loaderがnode_modules
ディレクトリを無視する挙動になります。
Webpacker4以降でブラウザで動作確認を行なった際に、node_modules
下にあるNPMモジュールでエラーが発生している場合、この設定変更を試すことをオススメします。
node_modules
ディレクトリにあるファイルがbabel-loader経由でのトランパイルの対象になっていることにより、思わぬ変換が行われていることが原因である可能性があります。
例えば、node_modules
ディレクトリにあるバンドル対象のファイル内に module.exports =
の記述がある場合、WebPacker4.x以降のデフォルト設定では、
Cannot assign to read only property 'exports' of object
エラーが発生することがあります。
自作の NPMモジュールをnode_modules
ディレクトリで管理していてクライアントサイドから利用しているので Babel でのトランスパイルが
必要etc、の理由で、babel-loader のトランスパイル対象からnode_modules
ディレクトリを外せない場合には、次のようにして、
エラーが発生している任意の NPM モジュールを babel-loader でのトランスパイルの対象から外すことができます。
const nodeModulesLoader = environment.loaders.get('nodeModules')
if (!Array.isArray(nodeModulesLoader.exclude)) {
nodeModulesLoader.exclude = (nodeModulesLoader.exclude == null)
? []
: [nodeModulesLoader.exclude]
}
nodeModulesLoader.exclude.push(/任意のNPMモジュール/)
追記
Webpackerは、6.0.0から、デフォルトでは、node_modules
ディレクトリにあるファイルは babel-loader 経由での(Babelの)トランパイルの対象ではなくなります。
追記
Rails7.0 から、Webpacker が Rails 本体から分離され、改名、有志の手によりShakapacker として開発・メンテナンスされていくことになりました。
Shakapackerは、いつまで開発・メンテナンスされていくのか、Railsのバージョンアップにどこまで追従されていくのか、不透明のため、一時的に Webpacker -> Shakapacker するにしても、どこかの時点で、jsbundling-rails への移行に踏み切るのが無難と思われます。
(継続的に機能追加・メンテナンスされていくWEBアプリの場合)
Webpacker 5.x -> jsbundling-rails
jsbundling-rails は Rails6.x に対応しています。
公式の手順通りにすれば、移行できます。
(オマケ) turbo-links -> turbo
Turbo も Rails6.x に対応しています。
Turbo Frame / Turbo Stream を利用する場合、Stimulus との併用が視野に入ってきます。(Hotwire)
(オマケ) Webpack -> Vite/esbuild etc
jsbundling-rails では、フロントエンドのビルドツールとして、Webpack だけでなくesbuild etcもサポートしています。
esbuild は goで書かれていて、高速に動作します。
Vite/esbuild への移行をオススメします。
Vite は、jsbundling-rails ではサポートされていませんが、vite_rails gemを利用すれば、railsに導入できます。
Rails系のフロントエンド開発では、Webpack からVite/esbuild への移行が進んでいます。
JSガッツリなフロントエンド開発では、Vite((2025/06現在)esbuildを内部で利用)
or esbuild or Rspack への移行が進んでいるようです。
esbuild は 高速ではあるものの、アセット最適化に制限があるため、パフォーマンス上必要なアセット最適化がesbuildの機能では必要十分に行えないプロジェクトには向いていません。
(esbuildのコード分割はWIPな(開発途上の)機能です。)
そのようなプロジェクトでは、Viteへの移行(Viteの採用)をオススメします。
Webpacker の話に戻すと、Webpacker -> jsbuilding-railsで esbuild への移行を行いたい場合でも、Webpacker -> jsbuilding-rails + webpack ->
jsbuilding-rails + esbuild、 と、ワンクッション挟んでの移行をオススメします。
jsbuilding-rails + webpack においても、esbuild-loaderを利用して、babel-loader を置き換えることで、esbuild に移行した場合ほどではありませんが、ビルド速度を改善できます。
(jsのトランスパイルを babel -> esbuild することで、ビルドを高速化します。)
Vite/esbuild への移行が難しい場合には、Webpackとの互換性の高い Rspack への移行も視野に入ってきます。
Vite/esbuild 及び そのプラグイン? でオルタナティブの提供されていないwebpack の loader? を利用していて、webpack → Vite/esbuild できない場合でも、Rspackならオルタナティブ(のloader?)が提供されている可能性が高いです。
Webpack + esbuild-loader より Rspackのほうがビルド速度が高速です。
推敲中...