Webpacker を剥がし jsbundling-rails に移行する

Ruby on Rails 6.1 で、Webpacker を止めて, jsbundling-rails + webpack に切り替える方法について。

  1. OpenSSL v3 環境では Webpacker は動かない。対策が必須。
  2. Rails 6 であっても, jsbundling-rails を導入すれば, 素の webpack への移行は簡単.

Fedora 36 / CentOS Stream 9 (OpenSSL v3)

Fedora 36 で Webpacker を利用するアプリケィションを実行すると, 次のようなエラーが生じる.

node:internal/crypto/hash:67
  this[kHandle] = new _Hash(algorithm, xofLen);
                  ^

Error: error:0308010C:digital envelope routines::unsupported
    at new Hash (node:internal/crypto/hash:67:19)
    at Object.createHash (node:crypto:130:10)
    at module.exports (/home/hori/repos/netsphere/rails-examples/LoginSample-sorcery-1/node_modules/webpack/lib/util/createHash.js:135:53)
    at NormalModule._initBuildHash (/home/hori/repos/netsphere/rails-examples/LoginSample-sorcery-1/node_modules/webpack/lib/NormalModule.js:417:16)
中略
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
  library: 'digital envelope routines',
  reason: 'unsupported',
  code: 'ERR_OSSL_EVP_UNSUPPORTED'

Fedora 36 は nodejs-16.14.0 と openssl-3.0.2 の組み合わせ。ググると Node.js v17 の話題は多く見つかるが、なかなか v16 のが見当たらない。しかも, Node.js v17 の話題であっても、古い挙動にする方法ばかり。

Building Node.js によれば, Node.js v16 のデフォルトは OpenSSL-1.1. configure --openssl-is-fips でビルドすれば OpenSSL v3.0 を利用する。後者でビルドされているのだろう。

md4 がハードコードされているのが原因。webpack の対応するバグ報告はこちら; Webpack Hash is not FIPS-Compliant #13572. 2022年5月現在, webpack v4.46.0 が v4 系列の最新。まだ修正されていない。この組み合わせでは通らない。

Workaround はこちら. 直接 webpack にパッチを当てる。ヒドい。

  $ find node_modules/webpack/lib -type f -exec sed -i 's|md4|sha512|g' {} \;
  $ find node_modules/compression-webpack-plugin/dist -type f -exec sed -i 's|md4|sha512|g' {} \;

createHash() 関数を置き換えてしまう、という方法もあるようだ。まだこちらのほうがマシか?

Shakapacker

Webpacker は, 結局 v6 が リリースされることなく, 完全に retire した。

Webpacker v6 の開発途中から引き継いで、正統な後継は Shakapacker. shakacode/shakapacker: Use Webpack to manage app-like JavaScript modules in Rails

ただ、もともと Webpacker は, 屋上屋を架す、webpack の設定を隠蔽して訳が分からなくなりやすい、など評判が非常に悪かった。Rails 7 であっさり廃止になったこともあり、わざわざ選ぶこともない。

jsbundling-rails + webpack に切り替える

上記のエラーは, Webpacker が webpack v4.46.0 に依存しているのが問題。単純に Webpacker を止めて, 素の webpack v5 系列を使えばよい。この対策が一番簡単で確実。

包括的な手順はこちら; jsbundling-rails/switch_from_webpacker.md at main · rails/jsbundling-rails

ざっくり手順

Gemfile ファイルで, gem 'webpacker' をコメントアウトし, gem "jsbundling-rails" を加える。

JavaScript エントリポイントが app/javascript/packs/application.js ファイルから app/javascript/application.js に替わる. 内容を適宜、移動する。

app/views/layouts/application.html.erb ファイルの javascript_pack_tag() (Webpacker::Helper クラス) を javascript_include_tag() に変更する。

次のファイル、ディレクトリを削除;

  • `bin/webpack`, `bin/webpack-dev-server`
  • `config/webpack/`, `config/webpacker.yml`
  • `.browserslistrc`
  • `babel.config.js`
  • `postcss.config.js`

package.json ファイルを適宜、調整. Webpacker 関連と webpack-dev-server を削除.