更新日:2017年03月07日
0. 環境
フロントエンドの話なのでサーバー環境はあまり関係ないのですが、参考まで。
サーバー
[Nginx] 1.10.2 [Kitura] 1.1.2 [Swift] 3.0.1
ローカル
[Mac] 10.11.6 [Node.js] 7.6.0 [gulp] 3.9.1
1.準備
仕事でやっているWebサイトのスピードアップを個人でもやってみたくて、適当なページを1つ作ってみました。
そしてパフォーマンス改善の教科書に選んだのはこちらです。
2.現状
Apacheで運用しているWebアプリが他にあるため、下記のようなちょっと珍しい構成になっています。
Nginx(リバースプロキシとして使用) + ServerSide-Swift(Kitura)
僕のネット環境(下り57Mbps/上り18Mbps)(※1)だとシンプルカレンダーのロードタイムが約2.5秒(※2)でそこまでストレスは感じませんが、DBを使ってないわりにこの数字なので改善の余地ありです。
(※1) 回線速度はSPEEDTESTで計測。
(※2) Chrome Developer Tools で計測。
3.ブラウザからのリクエスト削減
Chrome Developer ToolsのNetworkタブで見るとCSS、JavaScript(以下JS)のダウンロードに時間がかかっているので、教科書の[1. Reduce number of HTTP requests]-[Combine files]から取り掛かってみました。
HTMLから静的ファイル(CSS、JSなど)を複数ダウンロードする際、ブラウザが並列でリクエストできる数が決まっているため、なるべくそれを減らしましょうという内容です。
複数の静的ファイルをまとめるためのツール(※3)を検討しましたが、一番簡単に実現できそうだったgulpを使いました。
(※3) webpack、gulp、Grunt
4.Node.jsの準備
Node.jsのバージョンを切り替えられるよう、nodebrew を使いたいと思います。(既にNode.jsをインストール済みの場合、読み飛ばしてもOKです)
HomebrewでNode.jsをインストール済みの場合は一度アンインストール。
$ brew uninstall node
nodebrewをインストール。
$ brew install nodebrew
nodebrewへのパスを通すため、.bashrcの末尾に下記を追記。
$ vim ~/.bashrc
# これを追記 export PATH=$HOME/.nodebrew/current/bin:$PATH
設定を反映します。
$ source ~/.bashrc
続けてNode.jsをインストールします。
$ nodebrew install-binary latest
エラーが出たので、このページに従ってディレクトリを作成。
$ mkdir ~/.nodebrew $ mkdir ~/.nodebrew/src
使用するNode.jsのバージョンを指定。
$ nodebrew ls v7.6.0 $ nodebrew use v7 $ node -v v7.6.0
5.gulpの準備
gulpをインストール。
自分だけのローカル環境なのでグローバル(-g)を指定してインストール。
$ npm install -g gulp
アプリ(プロジェクト)のルートディレクトリで下記を実行すると、package.jsonファイルが作成されます。(これにパッケージ情報が書き込まれる)
$ npm init
そのままgulpとgulpのプラグインをインストールし、”–save-dev”を付けることでpackage.jsonに記録します。
$ npm install --save-dev gulp $ npm install --save-dev gulp-concat gulp-uglify gulp-minify-css
アプリのルートディレクトリに gulpfile.js というファイルを作成し、こちらの内容を記入します。(パスは自分の環境に読み替えて下さい)
続けて下記コマンドを打つと指定したディレクトリに結合・圧縮したCSS、JSファイルが出力されます。
$ gulp
HTMLからはそれらを読み込むよう修正します。(上記の例ではbundle.css、bundle.js)
イメージはこんな感じです。
ブラウザでJSエラー発生。
修正後の画面をブラウザで確認したところ下記エラーが表示されました。
Bootstrap's JavaScript requires jQuery
どうやら上記の書き方だと、CSSやJSの読み込み順序が任意になり、BootstrapでjQueryが使えない状態になってるようです。
もともとHTMLに書いてあったのと同じ順序でCSSとJSを指定するとエラーは出なくなりました。
(IE9以下の指定で読み込んでいたJSもとりあえず含んでいます)
6.バックエンドとの接続不良
本番へアップすると、数回に一回、ブラウザ側でエラーが発生しました。
GET https://jyear.net/simple-cal/js/dist/bundle.js net::ERR_CONTENT_LENGTH_MISMATCH (index):47 GET https://jyear.net/simple-cal/css/dist/bundle.css net::ERR_CONTENT_LENGTH_MISMATCH (index):2196 Uncaught ReferenceError: $ is not defined
またこのエラーが起きるとNginxでは下記のログが出力されていました。(【】はマスク)
upstream prematurely closed connection while reading upstream, client: 【IP】, server: jyear.net, request: "GET /simple-cal/css/dist/bundle.css HTTP/1.1", upstream: "http://【ホスト名】/simple-cal/css/dist/bundle.css", host: "jyear.net", referrer: "https://jyear.net/cal/“
いろいろネットで調べたところ、バックエンドから接続が切られるとこのエラーがでるようです。
Nginxのproxy_connect_timeoutや、Kituraにタイムアウト設定があるか調べたのですが、解決策が見つからなかったため、1つにしていたbundleファイルを分割することにしました。
分割して1ファイル当たりのサイズを抑えることでエラーは出なくなりました。
(そもそも1ファイル約200KBだったのでWebで扱うには大きかった…)
最終的な gulpfile.js はこちらです。