対象者
・Rails5.1
・webpacker v2
・サーバが複数台構成でサーバごとにアセットのプリコンパイルする
これがなんで問題か
複数台のサーバで、ダイジェストが付いたアセットを吐き出すのだけど、ダイジェストが一致しない!
これは、複数台構成では困る。
ロードバランサーが、振り分けた方にそのダイジェストが付いたアセットがなければ、404を返してしまう!
解決手順
1.アセット(例えばCSS)の中身が全く同じかを確認する
アセットの中身が違えば、ダイジェストが変わってしまうのは当然なので、とりあえず一緒になるように頑張る!
私の環境では、CSSが404になっていたので、CSSの差分を見てみました。
本番のCSS2つにアクセスして、適当なツール(Chromeの開発者ツールのpritty print)でミニファイされたCSSを整形して、diffを取ると ソースマップのリンクが差分となっていました!
そもそも、本番環境でソースマップを入れる必要はないので、config/webpack/production.js
から、
// Note: You must restart bin/webpack-dev-server for changes to take effect
/* eslint global-require: 0 */
const webpack = require('webpack')
const merge = require('webpack-merge')
const CompressionPlugin = require('compression-webpack-plugin')
const sharedConfig = require('./shared.js')
module.exports = merge(sharedConfig, {
output: { filename: '[name]-[chunkhash].js' },
devtool: 'source-map',
stats: 'normal',
plugins: [
new webpack.optimize.UglifyJsPlugin({
minimize: true,
// sourceMap: true, <- ここをコメントアウト
compress: {
warnings: false
},
output: {
comments: false
}
}),
new CompressionPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: /\.(js|css|html|json|ico|svg|eot|otf|ttf)$/
})
]
})
しました。とりあえず、それで私の環境ではCSSの差分はなくなりました。
2.差分がないのに、ダイジェストが一致しない
本当はこっちの方が問題です。普通、ファイルに差分がなかったら、ダイジェストが異なるはずはないと思うのですが、webpackerがコンパイルすると、どうもダイジェストが一致しない。
私は、サーバサイドのエンジニアで、webpackerとか全く詳しくなかったですけど、とりあえずwebpackが命名してるところを探そうと思いました。config/webpack/production.js
を見ても、cssの命名をしてそうにはなかったのですが、config/webpack/
を見ているとshared.js
が怪しそうでした。
これが、rails new
で準備した環境に、rails webpack:install
で生成されて一部分を取り出した、shared.js
です。
...
plugins: [
new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(env))),
// ↓ ここでプロダクションだったら、ExtractTextPluginに '[name]-[hash].css' を渡すようになっている
new ExtractTextPlugin(env.NODE_ENV === 'production' ? '[name]-[hash].css' : '[name].css'),
new ManifestPlugin({
publicPath: output.publicPath,
writeToFileEmit: true
})
],
...
ここでプロダクションだったら、ExtractTextPlugin
に [name]-[hash].css
を渡すようになっているのですが、このhashをどうやってつけているのかを調べるために,ExtractTextPlugin
でググりました。
そうすると、あるレポジトリにたどり着きました。
あれ、[name],[id] and [contenthash] ・・・🤔
[hash]
なんて記述がなくて、[contenthash]
になっていました。なんでや・・・。
ドキュメントにないオプションを指定してるような気がしたので、とりあえず、[hash]
ではなく[contenthash]
にしてみました。
そしたら、あっさりダイジェストが一致して、404が出ることはなくなりました。
bin/rails webpack:install
で吐き出す設定ファイルが間違ってるなんて誰がおもいつくんや・・・
ひょっとしたら、どっかのバージョンで[hash]
から[contenthash]
に変わったのかもと思って、v1のドキュメントも見てみたけど、[contenthash]
の記述しか見つからず・・・。
何故[hash]
になっているかの理由はわかりませんでしたが、とりあえず解決したので良しとします。
(一番の謎は、[hash]
でも、ちゃんとダイジェストが付いているところ・・・よくわからん)
まとめ
-
config/webpack/production.js
を弄って、ソースマップは出さないようにする! -
config/webpack/shared.js
を弄って、[contenthash]
にする!
この謎の問題に2,3時間溶かしてしまったorz
推測するのではなく、ちゃんと観測する!