はじめに
デプロイ後のアプリのルートが http://ホスト名/subdir
となっているとき /subdir
が webpacker で管理しているファイルからの参照URLに含まれていません。
以下は、試行錯誤して対応した記録です。
環境
-
gem
- rails 5.1.5
- webpacker 3.2.0
-
npm
- @rails/webpacker 3.2.0
- webpack-dev-server 2.9.7
- webpack 3.11.0
どこが問題か?
- https://github.com/rails/webpacker/blob/3cd48fc74a6e12216c3644c3cb5f6d4fe46c1ac5/package/config.js#L41 で、最終的に outputPath を publicPath として上書きしているところ。ドメイン直下にデプロイする前提になっちゃってる。
- config/webpacker.yml で publicPath が考慮されていないところ。
対応した手順
対応と言ってもやっつけですが、デフォルトの設定 https://github.com/rails/webpacker/blob/master/package/rules/file.js を参考にしつつ、
config/webpack/loaders/file.js
を以下の内容で作成します。
const publicPath = {
production: '/subdir/packs/', // ← 本番のときだけサブディレクトリを指定
development: '/packs/',
test: '/packs-test/',
}[process.env.NODE_ENV]
module.exports = {
test: /\.(jpg|jpeg|png|gif|tiff|ico|svg|eot|otf|ttf|woff|woff2)$/i,
use: [
{
loader: 'file-loader',
options: {
publicPath: publicPath,
outputPath: 'files/',
name: '[name]-[hash].[ext]',
},
},
],
}
もし wav ファイルなどを import している場合は test のところの正規表現に追加しておきます。
test じゃなくて exclude の形で書く方法もありますが gihtub での最近の修正 https://github.com/rails/webpacker/pull/1196/files#diff-5738d5d73471ec5cb82aa72024b3d794R5 を見ると test の形で書いた方が良いようです。
で、いちばん重要なのは production のとき publicPath を /subdir/packs/
にしておくところです。
/packs/
など config/webpacker.yml と内容が重複している箇所がありますが、DRY にしようとするとさらに複雑化するので気にしないことにします。
続いて、設定を有効にするため以下を config/webpack/environment.js
の module.exports = environment
より前に追記します。
const file = require('./loaders/file')
environment.loaders.append('file', file)
これ、 node_modules/@rails/webpacker/package/rules/file.js
の方で定義しているのと干渉するのでは? と心配するかもしれませんがキーの 'file' が衝突すると既存の設定を破棄するので問題ありません。
次にデプロイして確認するのはしんどいので開発環境で確認します。
確認しやすいように次のようなファイルへの参照がある小さなファイルを作っておきます。
body
background-image: url(path/to/rails.png)
あとは rails webpacker:compile
の出力を確認します。
- RAILS_ENV=production rails assets:clobber webpacker:compile を実行
- public/packs/foo-xxxxxxxx.css のなかの参照に /subdir が含まれているか確認
- public/packs/files/rails-xxxxxxxx.png があるか確認
今後はもっと簡単になりそう
2018-03-05 の時点で8日前に、Rails 側が見ている環境変数 RAILS_RELATIVE_URL_ROOT の値を webpacker で参照する予定の WEBPACKER_RELATIVE_URL_ROOT に渡すという PR https://github.com/rails/webpacker/pull/1236 があったので、そのうちもっと簡単になりそうです。