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

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

概要

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

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

shakacode/shakapacker - GitHub

以下の記事もどうぞ。

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

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

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

🔗 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
  • 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が実行されることを期待していた部分では、代わりにconfig/webpack/RAILS_ENV.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 {
    console.log(`WARNING: Using default webpack configuration. Did not find a Env specific file at path ${path}`)
    return webpackConfig
  }
}

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の中で定義されます。

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

    Shakapacker v6の新しい設定ではネストを許可していません。その代わり、JavaScriptのルートディレクトリにエントリポイントを置けます。この変更について詳しくはWebpackerの#3156で参照できます。

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

    注意: gemのページで最新バージョンを確認し、shakapacker 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はピア依存関係をインストールします。

  • 5. 新しいデフォルトの webpacker.yml への変更点を確認します。特に、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の中で定義されます。

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

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

    Shakapacker v6の新しい設定ではネストを許可していません。その代わり、JavaScriptのルートディレクトリにエントリポイントを置けます。この変更について詳しくはWebpackerの#3156で参照できます。

  • 7. webpack-dev-serverを最新バージョン(4.2より上)にアップデートし、package.jsonをアップデートします。

  • 8. ビューで使われている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というオプションを渡してください。

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

  • 10. 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);
  • 11. .browserslistrcファイルにカスタムのブラウザリスト設定がある場合は、その設定をpackage.json"browserslist"キーにコピーして、.browserslistrcファイルを削除します。

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

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

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

  • 13. webpacker.ymlファイルからextensionsが削除されました。カスタム拡張子は、以下のようにオブジェクトをマージする形で自分の設定ファイルに移動してください。詳しくはREADMEの『Webpack Configuration』ドキュメントを参照してください。
{
  resolve: {
    extensions: ['.ts', '.tsx', '.vue', '.css']
  }
}
  • 14. webpacker.ymlファイルにwatched_pathsがある場合はadditional_pathsに置き換えます。

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

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

  • 16. webpacker.ymlファイルとconfig/webpackに適用された設定の新しいデフォルトを確認します。特に、source_entry_pathsource_pathのトップレベルにするなど、本ガイドで提案されている変更点を注意深く検討してください。

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

  • 18. RAILS_ENV=production bin/rails assets:precompileを問題なく実行できることを確認します。確認後、必ずbin/rails assets:clobberを実行して、生成されたアセットをクリーンアップすること。

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

  • 20. 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の最終リリースでは、1つのwebpack.config.jsを使うように変更されました。

  • 21. ここまで完了したら、上述のWebpacker v6.0.0.rc.6をShakapacker v6にアップグレードする手順を実行します。

🔗 v5からv6への移行例

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

関連記事

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


CONTACT

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