昨今のWebアプリでは複数のJavaScriptライブラリを当たり前のように使うようになりましたが、パッケージマネージャとしてbowerを使っている方も多いと思います。
読み込むJavaScriptファイルが多くなるに連れて、読み込みの時間に悩まされることが多くなります。そこで個別に読み込むのではなく、1ファイルに結合してロード時間を短縮するということが行われます。
タスク自動化ツールのGruntには、パッケージマネージャbowerで落としたJSファイルを1つにまとめるためのタスクがいくつかあります。ただ、bowerパッケージのディレクトリ構成の規約が甘く、パッケージによっては依存関係をいちいち書き下す必要があるものがほとんどです。
今回紹介するgrunt-useminは依存関係はhtmlを参照すればよいということに目を付けたのがポイント。使い勝手のよいタスクになっています。JSだけでなく、CSSの結合もできます。
ディレクトリ構成
以下のようなディレクトリ構成でappが開発用、distが本番デプロイ用のディレクトリです。テンプレートエンジンを使っていて、テンプレート(拡張子は.html)がapp/views以下にあるものとします。
やりたいことは、以下の2つ。
- app/views以下にあるテンプレートを読み込んでそこに書かれているJS、CSSをそれぞれ結合、圧縮してdistのpublic/scripts、public/stylesにファイルを作る。
- app/views以下にあるテンプレートをdist/viewsにコピーして、読み込むJS、CSSを上で作ったファイルに置き換える。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
. ├── .bowerrc ├── .git ├── .gitignore ├── Gruntfile.js ├── app // 開発用 │ ├── cache │ ├── database │ ├── include │ ├── public // DocumentRoot │ │ ├── bower_components │ │ ├── images │ │ ├── index.php │ │ ├── scripts │ │ └── styles │ ├── test │ ├── upload │ ├── vendor │ └── views // テンプレート ├── bower.json ├── composer.json ├── dist // 本番デプロイ用 ├── node_modules └── package.json |
htmlに結合ルールを記述
app/views以下のhtmlの結合したいJS、CSSの前後に以下のようなコメントを入れます。
CSS
1 2 3 4 |
<!-- build:css styles/common.css --> <link rel="stylesheet" type="text/css" href="bower_components/bootstrap/dist/css/bootstrap.css"> <link rel="stylesheet" type="text/css" href="bower_components/jquery.ui/dist/jquery-ui.min.css"> <!-- endbuild --> |
JS
1 2 3 4 5 6 |
<!-- build:js scripts/common.js --> <script src="bower_components/less.js/dist/less-1.5.1.min.js"></script> <script language="javascript" type="text/javascript" src="bower_components/jquery/jquery.min.js"></script> <script src="bower_components/bootstrap/dist/js/bootstrap.js"></script> <script language="javascript" type="text/javascript" src="bower_components//jquery.ui/dist/jquery-ui.min.js"></script> <!-- endbuild --> |
コメントのルールは以下の通りで、typeの部分にjs or cssを指定します。(alternate search path)の部分は今回は使わず、Gruntfileで指定します。
<!– build:<type>(alternate search path) <path> –>
… HTML Markup, list of script / link tags.
<!– endbuild –>
Gruntfile
Gruntfile.jsは以下の通り。useminPrepareはGruntのタスクを生成、useminはhtmlのJS、CSSの読み込み部分の書き換えを行います。
Gruntfile.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
copy: { main: { files: [{ expand: true, cwd: 'app/', src: ['views/**/*.html'], dest: 'dist/' }] } }, useminPrepare: { html: ['app/views/**/*.html'], options: { root: 'app/public', dest: 'dist' } }, usemin: { html: ['dist/views/**/*.html'], options: { root: 'app/public', dirs: ['dist'] } } |
useminPrepareを実行するとconcatやuglifyの処理を事前に確認できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
$ grunt useminPrepare (...) Configuration is now: concat: { generated: { files: [ { dest: '.tmp/concat/styles/common.css', src: [ 'app/public/bower_components/bootstrap/dist/css/bootstrap.css', 'app/public/bower_components/jquery.ui/dist/jquery-ui.min.css' ] }, { dest: '.tmp/concat/scripts/common.js', src: [ 'app/public/bower_components/less.js/dist/less-1.5.1.min.js', 'app/public/bower_components/jquery/jquery.min.js', 'app/public/bower_components/bootstrap/dist/js/bootstrap.js', 'app/public/bower_components/jquery.ui/dist/jquery-ui.min.js' ] } ] } } uglify: { generated: { files: [ { dest: 'dist/scripts/common.js', src: [ '.tmp/concat/scripts/common.js' ] } ] } } cssmin: { generated: { files: [ { dest: 'dist/styles/common.css', src: [ '.tmp/concat/styles/common.css' ] } ] } } Done, without errors. |
タスクを実行するとdist以下に結合、圧縮後のJS、CSSファイルとそのファイルを使うように書き換えられたhtmlが生成されます。
1 |
$ grunt useminPrepare concat uglify cssmin copy usemin |
上のコマンドを打つのは面倒なので、Gruntfileにタスクを登録しておきましょう。
1 |
grunt.registerTask('myusemin', ['useminPrepare', 'concat', 'uglify', 'cssmin', 'copy', 'usemin']); |
感想
grunt-useminはhtmlに簡単なコメントを入れるだけで、結合、圧縮ファイルが生成され、それにあわせてhtmlも書き換えてくれるという優れもので、重宝しそうです。