はじめに
※この文章はベータ版です。
既存のプロジェクトで 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の)
トランパイルの対象ではなくなります。
https://github.com/rails/webpacker/blob/master/CHANGELOG.md#600---2021-tbd
https://github.com/rails/webpacker/pull/2624
追記
Rails7.0 から、Webpacker が Rails 本体から分離され、改名、有志の手に
より Shakapacker として開発・メンテナンスされていくことになりました。
Shakapackerは、いつまで開発・メンテナンスされていくのか、Railsの
バージョンアップにどこまで追従されていくのか、不透明のため、一時的に
Webpacker -> Shakapacker するにしても、どこかの時点で、
jsbundling-rails への移行に踏み切るのが無難と思われます。
(継続的に機能追加・メンテナンスされていくWEBアプリの場合)
Webpacker 5.x -> jsbundling-rails
jsbundling-rails は Rails6.x に対応しています。
公式の手順通りにすれば、移行できます。
Rails: Webpacker→jsbundling-rails+webpackアップグレード手順(翻訳)
https://techracho.bpsinc.jp/hachi8833/2022_02_03/115289
(オマケ) turbo-links -> turbo
Turbo も Rails6.x に対応しています。
Rails UJS・Turbolinks -> Turboアップグレードガイド(翻訳)
https://techracho.bpsinc.jp/hachi8833/2022_01_25/115082
Turbo Frame / Turbo Stream を利用する場合、Stimulus との
併用が視野に入ってきます。(Hotwire)
(オマケ) webpack -> esbuild/vite etc
jsbundling-rails では、フロントエンドのビルドツール
として、webpack だけでなく esbuild etcもサポートしています。
esbuild は goで書かれていて、高速に動作します。
jsbundling-rails ではサポートされていませんが、vite_rails gemを
利用すれば、vite をrailsに導入できます。
これからのRails系のフロントエンド開発では、webpack から esbuild/vite
への移行が進んでいくと思います。
JSガッツリなフロントエンド開発では、Vite(現行の最新版(2020/12現在)
ではesbuildを内部で利用)or esbuild or rspack への移行が進んでいるようです。
esbuild/vite への移行をオススメします。
Webpacker の話に戻すと、Webpacker -> jsbuilding-rails
で esbuild への移行を行いたい場合でも、
Webpacker -> jsbuilding-rails + webpack ->
jsbuilding-rails + esbuild、 と、ワンクッション挟んでの
移行をオススメします。
jsbuilding-rails + webpack においても、esbuild-loader
を利用して、babel-loader を置き換えることで、esbuild に
移行した場合ほどではありませんが、ビルドを高速化できます。
(jsのトランスパイルを babel -> esbuild することで、ビルドを
高速化します。)
esbuild/vite 及び そのプラグイン? でオルタナティブの提供されていない
webpack の loader を利用していて、webpack → esbuild/vite できない
場合、esbuild-loader は有用です。
推敲中...