Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails: Webpacker v5からShakapacker v6へのアップグレードガイド(翻訳)

概要

MITライセンスに基づいて翻訳・公開いたします。


  • 2022/03/10: 初版公開
  • 2022/05/26: 原文に合わせて更新
  • 2022/09/01: 原文に合わせて更新

表記は「Webpacker」「webpack」「Shakapacker」で統一しました。

shakacode/shakapacker - GitHub

以下の記事もどうぞ。

Rails: Webpacker(Shakapacker)とjsbundling-railsの比較(翻訳)

Rails: Webpacker v5からShakapacker v6へのアップグレードガイド(翻訳)

Shakapacker v6では、Webpacker 5からの移行に伴う大幅な変更点がいくつかあるため、手動での対応が必要です。本ガイドはそうした作業を支援するためのドキュメントです。

ShakaCodeはWebpackerからのアップグレードやShakapackerの利用をサポートします。ご興味のある方はjustin@shakacode.comまでお知らせください。

🔗 Webpacker/Shakapackerは「Webpackのスリムなラッパー」になった

デフォルトのWebpacker 6は、JavaScriptのコンパイルとバンドルに重点を置いています。これは、CSSや静的画像をSprocketsでトランスパイルするRailsの既存のアセットパイプラインと組み合わせる形になります。ほとんどの開発者にはこの組み合わせが推奨されますが、CSSや静的アセットもWebpackerで扱いたい場合は、READMEの『integrations』を参照してください。

以前のWebpacker は、webpackを間接的に設定する形を取っていたため、複雑な二次設定プロセスが発生していました。これは元々、人気の高いフレームワークのデフォルト設定を提供することが狙いでしたが、結果的には解決される問題よりも複雑さの方が増してしまいました。そのため現在のWebpackerは、すべての設定をwebpackのデフォルト設定に直接委譲しています。さらに、webpackやbabelなどの主要な依存関係は「ピア依存関係」になっているので、自由にアップグレードできます。

フレームワークとの統合は自分で設定する必要がありますが、webpack-mergeが役に立ちます。詳しくは本記事のv5からv6への移行例にあるVueの移行例を参照してください。

🔗 Webpacker v6.0.0.rc.6をShakapacker v6.0.0に移行する

移行例については、shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refreshの#27を参照してください。

🔗 v6.0.0.rc.6からv6.0.0に移行する手順

: Webpacker v5を利用している場合は、最初に後述の『Webpacker v5をv6.0.0.rc.6にアップグレードする』手順に沿ってv6.0.0.rc.6にアップグレードしておいてください。

  • 1. gem名をwebpackerからshakapackerに変更し、NPMパッケージを@rails/webpackerからshakapackerに変更します。

  • 2. 以下を実行して、ピア依存関係をインストールします。

yarn add @babel/core @babel/plugin-transform-runtime @babel/preset-env @babel/runtime babel-loader compression-webpack-plugin terser-webpack-plugin webpack webpack-assets-manifest webpack-cli webpack-merge webpack-sources webpack-dev-server

古いバージョンのライブラリがインストールされている可能性があります。yarn installを実行して以下のような警告が出力されていないかどうかをチェックしてください。言い換えれば、このようなエラーは重大なものであり、対応しないと著しい混乱が生じます。

warning " > shakapacker@6.1.1" has incorrect peer dependency "compression-webpack-plugin@^9.0.0"
file-loader@1.1.11" has incorrect peer dependency "webpack@^2.0.0 || ^3.0.0 || ^4.0.0"
  • 3. bin/webpackbin/webpack-dev-serverを呼び出すスクリプトを更新して、それぞれbin/webpackerbin/webpacker-dev-serverに変更します。

  • 4. webpack の設定を更新して、単一の設定ファイル config/webpack/webpack.config.js を作成します。

    以前のようにNODE_ENVごとに個別のファイルを使う方法にしたい場合は、config/webpack/webpack.config.jsで以下のshimを利用できます。

警告: 以前は、NODE_ENV を設定しない場合のNODE_ENV のデフォルトはdevelopmentでした。そのため、以前config/webpack/development.jsが実行されることを期待していた部分では、代わりに自分のRAILS_ENVに対応するコンフィグファイルを使ってください。RAILS_ENVtestの場合はconfig/webpack/test.jsが実行されます。

// このファイル名はconfig/webpack/webpack.config.jsにする
const { env, webpackConfig } = require('shakapacker')
const { existsSync } = require('fs')
const { resolve } = require('path')

const envSpecificConfig = () => {
  const path = resolve(__dirname, `${env.nodeEnv}.js`)
  if (existsSync(path)) {
    console.log(`Loading ENV specific webpack configuration file ${path}`)
    return require(path)
  } else {                       
     // NODE_ENV用のファイルが存在しないのは、おそらく誤り
     throw new Error(`Got Error with NODE_ENV = ${env.nodeEnv}`);
  }
}

module.exports = envSpecificConfig()
  • 5. JSXのサポートが必要な場合は、babel.config.jsを更新してください。詳しくはShakapackerの『Customizing Babel Config』ドキュメントを参照してください。

🔗 Webpacker v5をv6.0.0.rc.6にアップグレードする

  • 1. gitで新しいブランチを作成し、そのブランチで作業するようにしてください。

このブランチですべてのファイルを上書きし、不要な変更を元に戻すことになります。

訳注

以下の記述は削除されました。

  • 2. webpacker.ymlの以下のsource_entry_path をv5のデフォルトから変更することを検討します。
  source_path: app/javascript
  source_entry_path: packs

上のv5のパスを、以下のようにv6に変更することを検討します。

  source_path: app/javascript
  source_entry_path: /

続いて、app/javascript/packs/*にあるファイル(application.jsも含む)をapp/javascript/ディレクトリに移動してから設定ファイルを更新することも検討します。

なお、このファイル移動は必須ではなくオプションなので、packsentriesと呼ばれる別のディレクトリに引き続きエントリを保持できます。このディレクトリはsource_pathの中で定義されます。

サブディレクトリ内のエントリポイント用ファイルは、shakacode/shakapacker v6ではサポートされていません。それらのファイルをトップレベルに移動し、それらのファイルのimportを調整してください。

  • 2. source_entry_pathにネストしたディレクトリを置かないようにするか、nested_entries: trueオプションを設定します。

エントリポイント用のファイルをsource_entry_pathのサブディレクトリに置いていないかどうかを確認してください。

Shakapacker v6の新しい設定では、JavaScriptのルートディレクトリにエントリポイントを置けるようにするため、デフォルトではネストを許可しないようになっています。この変更について詳しくはWebpackerの#3156で参照できます。

  • 3. WebpackerのgemとNPMパッケージをアップグレードします。

注意: gemのページで最新バージョンを確認し、インストールするshakapacker gemとパッケージのバージョン番号が同じになるようにしてから、古いwebpacker gemを削除してください(メインのバージョン番号とベータ版の間の表記は、gemではハイフンが使われ、パッケージではドットが使われる点にご注意ください)。

以下は、特定のバージョンにおける例です。

# Gemfile
gem 'shakapacker', '6.0.0.rc.13'
bundle install
yarn add shakapacker@6.0.0-rc.13 --exact
bundle exec rails webpacker:install

以下を実行してすべてのファイルを上書きし、変更内容を確認します。

yarn add @babel/core @babel/plugin-transform-runtime @babel/preset-env @babel/runtime babel-loader compression-webpack-plugin terser-webpack-plugin webpack webpack-assets-manifest webpack-cli webpack-merge webpack-sources webpack-dev-server

なお、webpacker:installはピア依存関係をインストールします。

  • 4. 新しいデフォルトの webpacker.yml への変更点を確認します。

変更を示唆された箇所を1つずつ慎重に確認してください。特に、source_entry_pathsource_path のトップレベルになるように変更されていることをチェックしてください。

Webpacker v5では、以下のようにsource_entry_pathにデフォルトでpacksディレクトリが使われます。

source_path: app/javascript
source_entry_path: packs

Webpacker v6では、以下のようにデフォルトでトップディレクトリが使われます。

source_path: app/javascript
source_entry_path: /

この設定にしたい場合は、app/javascript/packs/*application.jsも含む)をapp/javascript/に移動し、設定ファイルを更新してください。

なお、このファイル移動は必須ではなくオプションなので、packsentriesと呼ばれる別のディレクトリにエントリを引き続き保持することもできます。このディレクトリはsource_pathの中で定義されます。

  • 5. source_entry_pathにネストしたディレクトリを置かないようにします。

エントリポイント用のファイルがsource_entry_pathのサブディレクトリに置かれていないかどうかを必ず確認してください。サブディレクトリ内のエントリポイント用ファイルは、shakacode/shakapacker v6ではサポートされていません。それらのファイルをトップレベルに移動し、それらのファイルのimportを調整してください。

Shakapacker v6では、JavaScriptのルートディレクトリにエントリポイントを置けるようにするため、ネストを許可していません。この変更について詳しくはWebpackerの[#3156](https://github.com/rails/webpacker/pull/3156/files#diff-7af8667a3e36201db57c02b68dd8651883d7bfc00dc9653661be11cd31feeccdL19)で参照できます。
  • 6. webpack-dev-serverを最新バージョン(4.2より上)にアップデートし、package.jsonをアップデートします。

  • 7. ビューで使われているAPIを更新します。

具体的には、javascript_packs_with_chunks_tagヘルパーをjavascript_pack_tagヘルパーに変更し、stylesheet_packs_with_chunks_tagヘルパーをstylesheet_pack_tagヘルパーに変更します。

注意: 変更の際は、レイアウトやビューで使うjavascript_pack_tag呼び出しとstylesheet_pack_tag呼び出しはそれぞれ最大1回までにしてください。これらのビューヘルパーメソッドにはバンドルを複数渡せるようになっています。この変更を忘れてヘルパーメソッドを複数置いてしまうと、パフォーマンスの問題や、Reactの重複読み込みに関連する他のバグが発生する可能性があります(#2932など)。

注意: app/javascript/application.jsファイル内で、import $ from "expose-loader?exposes=$, jQuery!jquery"のようにexpose-loaderでjQueryをグローバルに公開している場合は、javascript_pack_tagdefer: falseというオプションを渡してください。

  • 8. csspostcssReactTypeScript などの統合機能を使っている場合。それらがShakapacker v6でどう機能するかについては、READMEの『integrations』を参照してください。

  • 9. config/webpack/environment.jsのインポート方法はconfig/webpack/base.jsに変更され、ネイティブのwebpackコンフィグをエクスポートするようになったので、toWebpackConfigを呼び出す必要はありません。

変更には以下のようにmergeをお使い下さい。

// config/webpack/base.js
const { webpackConfig, merge } = require('@rails/webpacker');
const customConfig = {
  module: {
    rules: [
      {
        test: require.resolve('jquery'),
        loader: 'expose-loader',
        options: {
          exposes: ['$', 'jQuery']
        }
      }
    ]
  }
};

module.exports = merge(webpackConfig, customConfig);
  • 10. .browserslistrcファイルにカスタムのブラウザリスト設定がある場合は、その設定をpackage.json"browserslist"キーにコピーして、.browserslistrcファイルを削除します。

  • 11. babel.config.jsファイルをまったくカスタマイズしていない場合は削除します。babelのデフォルト設定を使うには、package.jsonで以下のように設定します。

"babel": {
  "presets": [
    "./node_modules/shakapacker/package/babel/preset.js"
  ]
}

Reactの設定については、『Customizing Babel Config』ドキュメントのカスタマイズ例を参照してください。

  • 12. webpacker.ymlファイルからextensionsが削除されました。

カスタム拡張子は、以下のようにオブジェクトをマージする形で自分の設定ファイルに移動してください。詳しくはREADMEの『Webpack Configuration』ドキュメントを参照してください。

{
  resolve: {
    extensions: ['.ts', '.tsx', '.vue', '.css']
  }
}
  • 13. webpacker.ymlファイルにwatched_pathsがある場合はadditional_pathsに置き換えます。

  • 14. #3056で一部の依存関係が削除されました。

Error: Cannot find module 'babel-plugin-macros'などのエラーが表示された場合は、yarn add <依存パッケージ> を実行する必要があります(<依存パッケージ>にはbabel-plugin-macroscase-sensitive-paths-webpack-plugincore-jsregenerator-runtimeなどが含まれます)。これらのパッケージへの依存を取り除くことを検討してもよいでしょう。

  • 15. webpacker.ymlファイルとconfig/webpackに適用された設定の新しいデフォルトを確認します。

特に、source_entry_pathsource_pathのトップレベルにするなど、本ガイドで提案されている変更点を注意深く検討してください。

  • 16. bin/webpackを実行して、エラーが発生しないことを確認します。

  • 17. RAILS_ENV=production bin/rails assets:precompileを問題なく実行できることを確認します。

確認後、必ずbin/rails assets:clobberを実行して、生成されたアセットをクリーンアップすること。

  • 18. bin/webpackbin/webpack-dev-serverを呼び出すスクリプトを更新して/bin/webpackerbin/webpacker-dev-server に変更します。

  • 19. NODE_ENVが設定されていない場合、bin/webpackerおよびbin/webpacker-dev-serverNODE_ENVはデフォルトでRAILS_ENVになります。

従来はNODE_ENVが設定されていない場合はデフォルトでdevelopmentになるため、以前のbinstubでは、config/webpack/development.jsに対応するwebpack設定が使われていました。

変更後は、たとえばRAILS_ENVtest の場合はNODE_ENVtestになります。Shakapacker 6.0の最終リリースでは、単一のwebpack.config.jsを使うように変更されました。

🔗 v5からv6への移行例

  1. React on Rails Project with HMR and SSR
  2. Vue and Sass Example

関連記事

Rails: Webpacker→jsbundling-rails+webpackアップグレード手順(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。