tamuraです。
先日、社内勉強会で「なぜフロントエンドの開発にビルドが必要なのか?」という質問が出てうまく回答できなかったので、フロントエンド開発でなにを行っているか少しまとめてみました。
まあ一言で言うと開発効率向上のためです。
雛形作成
最近はフロントエンド側をAngularJSで作ることが多いのでYeomanを使って雛形を作っています。 その際にgenerator-angular
でアプリケーションの雛形を作ります。
$ mkdir sample
$ cd sample
$ yo angular sample
フロントエンド用のライブラリのダウンロード
Bowerはフロントエンド用のパッケージマネージャです。
例えばlodash
というライブラリを使いたい場合、 以前の私であればサイトからリリースファイルをダウンロードしてローカルに配置してということをやっていましたが、 Bowerを使うと
$ bower install lodash --save
だけで済みます。
これでbower_components
というディレクトリにダウンロードされるので、それを読み込むだけです。
Bowerでダウンロードしたファイルの自動反映
前述のBower等でインストールしたファイルはbower_components
ディレクトリに格納されます。 これを手でindex.html
に反映させても良いのですが、wiredep
を使うことで自動でindex.html
に反映してくれます。
Gruntfile.js
wiredep {
options: {
cwd: '<%= yeoman.app %>'
},
app: {
src: ['<%= yeoman.app %>/index.html'],
ignorePath: /\.\.\//
}
}
index.html
<html>
<head>
<!-- bower:css -->
<!-- endbower -->
</head>
<body>
<!-- bower:js -->
<!-- endbower -->
</body>
</html>
この状態で
$ grunt wiredep
と打つことでindex.html
にBowerでインストールしたライブラリが反映されます。
<html>
<head>
<!-- bower:css -->
<!-- endbower -->
</head>
<body>
<!-- bower:js -->
<script src="bower_components/lodash/lodash.js"></script>
<!-- endbower -->
</body>
</html>
この例はJavaScriptだけですが、CSSがある場合はCSSの読み込みも反映されます。
自作のJS/CSSの自動反映
JSやCSSが増える都度手作業でファイルをindex.html
等に追加するのは面倒です。
grunt-asset-injector
を使うことでwiredep
のようにファイルを自動で追加してくれます。
Gruntfile.js
injector: {
options: {
},
scripts: {
options: {
transform: function (filePath) {
filePath = filePath.replace('/app\/app/', 'app/');
filePath = filePath.replace('/app\/components/', 'components/');
filePath = filePath.replace('/.tmp/', '');
return '<script src="' + filePath + '"></script>';
},
starttag: '<!-- injector:js -->',
endtag: '<!-- endinjector -->'
},
files: {
'<%= yeoman.app %>/index.html': [
['{.tmp,<%= yeoman.app %>/{app,components}/{,*/}*.js',
'!{.tmp,<%= yeoman.app %>/{app,components}/{,*/}*.spec.js',
'!{.tmp,<%= yeoman.app %>/{app,components}/{,*/}*.mock.js']
]
}
},
css: {
options: {
transform: function (filePath) {
filePath = filePath.replace('/app\/app/', 'app/');
filePath = filePath.replace('/app\/components/', 'components/');
filePath = filePath.replace('/.tmp/', '');
return '<link rel="stylesheet" href="' + filePath + '">';
},
starttag: '<!-- injector:css -->',
endtag: '<!-- endinjector -->'
},
files : {
'<%= yeoman.app %>/index.html': [
'{.tmp,<%= yeoman.app %>}/{app,components}/{,*/}*.css'
]
}
}
}
index.html
<html>
<head>
<!-- bower:css -->
<!-- endbower -->
<!-- injector:css -->
<!-- endinjector -->
</head>
<body>
<!-- bower:js -->
<!-- endbower -->
<!-- injector:js -->
<!-- endinjector -->
</body>
</html>
この状態で
$ grunt injector
と打つことでindex.html
に対して、追加したJS/CSSファイルが反映されます。
<html>
<head>
<!-- bower:css -->
<!-- endbower -->
<!-- injector:css -->
<link rel="stylesheet" href="app/app.css">
<!-- endinjector -->
</head>
<body>
<!-- bower:js -->
<!-- endbower -->
<!-- injector:js -->
<script src="app/app.js">
<!-- endinjector -->
</body>
</html>
複数のファイルの結合
AngularJSを使ったアプリはJSファイルが多くなりがちです。 ファイル数が増えるとその分サーバへのアクセスが増え、結果的に遅くなります。 開発中はそれでも問題はないのですが、本番環境で動かす際に問題となります。
そのため、grunt-usemin
で複数のファイルを結合します。
Gruntfile.js
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>'
}
},
usemin: {
html: ['<%= yeoman.dist %>/{,*/}*html'],
css: ['<%= yeoman.dist %>/{,*/}*.css'],
js: ['<%= yeoman.dist %>/{,*}*.js'],
options: {
assetsDirs: [
'<%= yeoman.dist %>',
'<%= yeoman.dist %>/assets/images',
],
patterns: {
js: [
[/(assets\/images\/.*?\.(?:gif|jpeg|jpg|png|webp|svg))/gm, 'Update the JS to reference our revved images']
],
css: [
[/()/g, 'Replacing reference to FontFile']
]
}
}
}
<html>
<head>
<!-- build:css assets/css/vendor.css -->
<!-- bower:css -->
<!-- endbower -->
<!-- endbuild -->
<!-- build:css assets/css/app.css -->
<!-- injector:css -->
<!-- endinjector -->
<!-- endbuild -->
</head>
<body>
<!-- build:js assets/script/vendor.js -->
<!-- bower:js -->
<!-- endbower -->
<!-- endbuild -->
<!-- build:js assets/script/app.js -->
<!-- injector:js -->
<!-- endinjector -->
<!-- endbuild -->
</body>
</html>
この状態からビルドを行うことで、index.html
が更新されます。
<html>
<head>
<link rel="stylesheet" href="assets/css/vendor.css"/>
<link rel="stylesheet" href="assets/css/app.css"/>
</head>
<body>
<script src="assets/script/vendor.js"></script>
<script src="assets/script/app.js"></script>
</body>
</html>
その他
generator-angular
で色々なタスクが登録されています。 index.html
が変更されるため主に意識しているのは上記のタスクですが、 Gruntfile.js
に色々かいてあるので読んでみてください。
ちょっと紹介しきれませんでした。