最近はgulp
やgrunt
でビルドプロセスを自動化していかないとやってられない、というような流れになってきている気がしますが、gulp
もgrunt
もいろんなライブラリが出まくっていて、一つ覚えたと思ったらもう新しくてさらに効率のいいライブラリが出てきたりしてますよね。。。と、愚痴を言っていても仕方ないのですが、今回はlink
タグとかscript
タグを自動で注入(inject
)してくれるgulp
のライブラリ、wiredep
とgulp-inject
の基本的な使い方について検証したのでまとめます。
指摘事項や、「こうしたらほうがいいよ?」などありましたら遠慮無くコメント欄やメッセージなどで気軽に教えていただけると喜びますm(__)m
はじめに
まず、下のようなページがあったとします。
<html>
<head>
<link rel="stylesheet" href="../../bower_components/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="../../bower_components/font-awesome/css/font-awesome.css" />
<link rel="stylesheet" href="styles/app.css">
</head>
<body>
<div id="main-region"></div>
</body>
<script src="../../bower_components/react/react.js"></script>
<script src="app/app.js"></script>
</html>
すごいシンプルなので、ここからは問題はあまり見えてこないんですけど、bower
使って便利ライブラリをいろいろとインストールしていって、css
やらscript
やらが増えてくると、いちいち自分でindex.html
に書いてられないですよね?おまけにこれに各アプリケーション特有のcss
とscript
も増えていくのがほとんどのケースだと思います。これを全部管理するっていうのは人間のやることじゃない。って考える人は世の中にいっぱいいて、そうなるとやっぱり便利ツールは出現するんです。そこで登場するのがwiredep
とgulp-inject
。
ライブラリについて
wiredep
Wire Bower dependencies to your source code.
と、githubで書かれているように、bower install --save
したライブラリをhtml
に自動で注入してくれるのがwiredep
です。dependencies
を見ながらhtml
に注入してくれるので、(やや難がありますが)注入順についても意識しなくても良いという特徴があります。
gulp-inject
A javascript, stylesheet and webcomponent injection plugin for Gulp, i.e. inject file references into your index.html
と、githubに書かれているように、bower
に特化せず、css
やらscript
やらを注入できるのがgulp-inject
(多分)。 依存関係とかを勝手にいい感じにやってくれる って機能はないはずなので、今回はgulp-inject
をアプリ特有のcss
やscript
に使おうと思います。
下準備
あらかじめ入れてある前提で話を進めるnpm package
はgulp
(もちろん)とgulp-load-plugins
です。
今回のように小規模なサンプルの場合gulp-load-plugins
はどう考えても必要ないけど、たいていの場合私はgulp-*
系なライブラリを多用するのでgulp-load-plugins
を使います。これについては詳しく説明しません。ってなわけでインストールしておきます。
npm install --save-dev gulp gulp-load-plugins
wiredep
とgulp-inject
もインストールしちゃいましょう。
npm install --save-dev wiredep gulp-inject
wiredep関連の作業
html編集
bower
経由でインストールしているライブラリのタグをcss
ならbower:css
で、script
ならbower:js
で下のように囲んで、元のタグは消しちゃいます。ここにwiredep
が自動注入してくれるようになるからです。
<html>
<head>
<!-- bower:css -->
<!-- endbower -->
<link rel="stylesheet" href="./styles/app.css">
</head>
<body>
<div id="main-region"></div>
</body>
<!-- bower:js -->
<!-- endbower -->
<script src="./app/app.js" charset="utf-8"></script>
</html>
gulpfile.js編集
それではgulpfile.js
の編集をします。書きっぷりとしては下のように書いておけば(たいていの場合)完了です。
gulp.task('wiredep', function() {
var wiredep = require('wiredep').stream;
return gulp
.src('./src/client/index.html')
.pipe(wiredep()) // wiredep bower dependencies
.pipe(gulp.dest('./src/client')) // output the index.html
})
ただし、今回の例の場合うまくいきません。仮にgulp wiredep
と実行してもタスクは完了して何も注入されていないことに気づきます。
何故かと言うと、wiredep
の仕組み上、注入するための情報が不足しているからです。
wiredep
が自動注入する際に参考にしている情報は各ライブラリの.bower.json
のmain
の内容とdependencies
の内容です。
今回使っているbootstrap
の.bower.json
を見ると、
// 割愛
"main": [
"less/bootstrap.less",
"dist/js/bootstrap.js"
],
// 割愛
"dependencies": {
"jquery": ">= 1.9.1"
},
となっており、注入してほしいdist/css/bootstrap.css
が記述されていません。こんな時は自分のbower.json
に明示的に情報を付加してあげる必要があります。書きっぷりは下のような感じになります。
"overrides": {
"bootstrap": {
"main": "dist/css/bootstrap.css",
"dependencies": {}
},
"font-awesome": {
"main": "css/font-awesome.css"
}
}
overrides
の下にライブラリ名: {プロパティ名: 与えたい値}
という具合で情報を増やしてあげます。今回はbootstrap
のdependencies
であるjquery
も使いたくなかったので明示的にdependencies
を空オブジェクトにしています。ここのそのままにしているとbower:js
で囲まれている箇所にjquery
が意図せず注入されてしまいます。
これでwiredep
関連の自動化は完了。gulp wiredep
でbower
関連のライブラリが注入されるはずです。
gulp-inject関連の作業
それでは、各アプリ特有のcss
とscript
も注入できるようにします(多くの場合app.js
だったりapp.css
だったりするファイルです)。要領はwiredep
のときと同様ですが、囲むタグをcss
の場合はinject:css
で、script
の場合はinject:js
とします。
下のようになるはずです。これで手動で書くタグはなくなりましたね!
htmlの編集
<html>
<head>
<!-- bower:css -->
<!-- endbower -->
<!-- inject:css -->
<!-- endinject -->
</head>
<body>
<div id="main-region"></div>
</body>
<!-- bower:js -->
<!-- endbower -->
<!-- inject:js -->
<!-- endinject -->
</html>
gulpfile.jsの編集
先ほどのwiredep
タスクにちょっとコードを足します。
gulp.task('wiredep', function() {
var wiredep = require('wiredep').stream;
return gulp
.src('./src/client/index.html')
.pipe(wiredep()) // wiredep bower dependencies
.pipe($.inject(gulp.src(['./src/**/*.js', './src/**/*.css']), {
relative: true // no need for the './src/client' part
}))
.pipe(gulp.dest('./src/client')) // output the index.html
})
gulp-load-plugins
を使っていて、かつそれを$
としてrequire
しているのでgulp-inject
は$.inject
でアクセス可能になってます。対象ファイルはとりあえずsrc
配下のcss
とjs
としてます。そして、オプションなしでこのまま実行するとlink
やscript
タグが./src/client
からパスを初めてしまうので、index.html
からみた相対パスを注入してもらうようにrelative: true
というオプションを渡しています。
以上で完了です。これでgulp wiredep
を実行したらindex.html
に自動でlink
やscript
タグが注入されるようになります。
それぞれのソースの最終形
<html>
<head>
<!-- bower:css -->
<!-- endbower -->
<!-- inject:css -->
<!-- endinject -->
</head>
<body>
<div id="main-region"></div>
</body>
<!-- bower:js -->
<!-- endbower -->
<!-- inject:js -->
<!-- endinject -->
</html>
var gulp = require('gulp');
var $ = require('gulp-load-plugins')({
lazy: true
});
gulp.task('wiredep', function() {
var wiredep = require('wiredep').stream;
return gulp
.src('./src/client/index.html')
.pipe(wiredep()) // wiredep bower dependencies
.pipe($.inject(gulp.src(['./src/**/*.js', './src/**/*.css']), {
relative: true // no need for the './src/client' part
}))
.pipe(gulp.dest('./src/client')) // output the index.html
})
{
"name": "wiredep-inject-starter",
"version": "0.0.0",
"homepage": "https://github.com/kenfdev/wiredep-inject-starter",
"authors": [
"Ken Fukuyama <kenfdev@gmail.com>"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"bootstrap": "~3.3.5",
"font-awesome": "~4.4.0",
"react": "~0.13.3"
},
"overrides": {
"bootstrap": {
"main": "dist/css/bootstrap.css",
"dependencies": {}
},
"font-awesome": {
"main": "css/font-awesome.css"
}
}
}
課題
課題というか、このサンプルだけでは足りていないことは、
- アプリ特有の
script
の依存関係を考えた順番の注入ができていない - 実際は
css
やjs
のビルドプロセスが存在するため、このタスク単体では実務では使えない。(依存タスクをもっと作る必要あり)
などなど、まだまだたくさんあります。
が、とりあえずはwiredep
とgulp-inject
の雰囲気がつかめたのでよしとしようかと。
おまけ
wiredep-inject-starterとして今回のソースを上げています。