Sinatraアプリケーションで、JSファイルを圧縮するsinatra-assetpackを利用していて、
production環境で動作させようとしたら動かなくなってしまった問題について調査した。
起こったこと
Sinatraを使ってアプリケーションを作っていて、development環境で完成したので、 prorudction環境で動作させようとしたら、jsのエラーが出るようになってしまい、正常に動かなくなった。
アクセスすると、以下のエラーがでる。要はjqueryがないとのこと。
Uncaught ReferenceError: $ is not defined
jQueryはもちろん読み込ませてるし、なんでproduction環境でだけこのような事象が起きたのか?
ソースコード
sinatraのメインアプリケーションであるapp.rbには以下のように、sinatra-assetpackを利用してjsを読み込んでいる。
assets do
serve '/js', from: 'public/js'
serve '/bower_components', from: 'bower_components'
js :app, '/js/app.js', [
'/js/index.js',
]
js :libs, '/js/libs.js', [
'/bower_components/jquery/dist/jquery.js',
'/bower_components/bootstrap/dist/js/bootstrap.js',
]
js_compression :jsmin
end
layout.erbにはもちろん、libs.jsが先に来るように記述している。
<%= js :libs %>
<%= js :app %>
sinatra-assetpackの挙動
productionでのみ発生する事象なので、改めてsinatra-assetpackのproduction環境時の挙動を確認した。
production環境では、複数のjsファイルを1つのファイルにまとめ、圧縮を行う。
development環境
3つのjsファイルがあったら以下のように3つ別々に読み込まれる。
<script type='text/javascript' src='/js/vendor/jquery.283479.js'></script>
<script type='text/javascript' src='/js/vendor/underscore.589491.js'></script>
<script type='text/javascript' src='/js/app/main.589491.js'></script>
production環境
3つあったjsファイルは1つにまとめられ、また圧縮される。
<script type='text/javascript' src='/js/app.589491.js'></script>
詳細はこちら
rstacruz/sinatra-assetpack · GitHub
事象の理由
ChromeのデバッグツールのNetworkでファイルのダウンロード状況を確認してみると意外なことがわかった。
画像が小さくて見づらいかもしれないが、
5行目と6行目のapp.jsとlibs.jsで先にlibs.jsを読み込んでいるのに、おそらく圧縮とダウンロードに時間がかかり、
app.jsのほうが先にダウンロードが終わっている。
libs.jsにはjQueryなどが含まれていて、app.js内でjQueryを利用する。
よって、先にapp.jsが読み込まれてしまったことで、jQueryがねーぞ!と怒られてしまったのである。
対策と考慮
sinatra-assetpackなどを利用して、jsを圧縮する際には、 ファイルを1つにまとめたり圧縮したりする時間がかかることを十分に考慮しなければいけない。
あまり賢い手段をは言えないが、libs.jsとapp.jsひとつにまとめることで今回の事象は避けられる。 app.rb
assets do
serve '/js', from: 'public/js'
serve '/bower_components', from: 'bower_components'
js :app, '/js/app.js', [
'/bower_components/jquery/dist/jquery.js',
'/bower_components/bootstrap/dist/js/bootstrap.js',
'/js/index.js',
]
js_compression :jsmin
end
また、事前に圧縮しておいて、ダウンロードだけする状態にしてもいいかもしれない。
rstacruz/sinatra-assetpack · GitHub