2015年はgulpで決まり!開発環境をgruntから乗り換えよう!(コーダー編)
もーいーくつねーるーと~、おーしょーうーがーつー♪
という所で、今年も残り 10 営業日を切りましたね・・・・!早いですね!
皆さまいかがお過ごしでしょうか♪
世間はクリスマスなムード一色ですが、皆さまお忘れになってはいないでしょうか。
大掃除という名の一大行事を!!終えない限りはクリスマスを迎えられませんよね(鬱
今週こそはきっと・・・ほほほ。。
自分を追い込んでみたところで、本題に入りたいと思います!
こちらは、ソニックムーブ Advent Calendar 2014 12日目の記事になります!
目次
なぜ gulp なのか
当記事は grunt から gulp に乗り換えを考えているユーザーを対象としているので、Node.js のインストール方法の説明を省かせていただきます・・・!
gulp の実装当時は、grunt と比べてプラグインが少なかったことを理由に grunt を採用する方が多かったかと思います。ですが、今現在は何ら不便がないところまでプラグインも増えてきています!Google の WebStarterKit でも、ついに gulp が採用しました。これはもう乗り換えるしかありませんよね・・・!
gulp に乗り換えるにあたり、メリット・デメリットは下記のようになります。
メリット
- grunt に比べてコード量が少なくタスクを定義できる
- StreamAPI を利用することでファイルを毎回書き出す grunt より高速に処理ができる
- なんとなく先取り感が味わえる
デメリット
- 記述が Node.js 寄りなので、ある程度 javascript の知識が必要
- 記述を少なくできる言っても、処理が断長になれば記述もそれなりに多くなる
「なんとなく先取り感が味わえる」・・・これ大事ですよね!!! とりあえず、今回はこの「なんとなく先取り感が味わえる」ように、既存の grunt を gulp へ地道に書き換えてまいりますっ
目標
マークアップをする上で必要不可欠なタスクを厳選しています! これらのタスクなどの設定を順序立てて、解説していきます。
- Sass/Compass を扱う
- 簡易サーバーを立ち上げる
- ファイルが更新されたら自動でブラウザをリロードする
- 自動でベンダープレフィックスを付与する
- 自動で CSS のプロパティをソートする
- 画像のデータ容量を圧縮する
- ファイルをコピーする
- ファイルを削除する
- タスクを直列処理する
gulp-compass
sass/compass を扱うパッケージ。自動で css sprite を生成させる。
gulp-connect
簡易サーバーを立ち上げるパッケージ。
gulp-watch
ファイルが更新されたら自動でブラウザをリロード(Livereload)するパッケージ。
gulp-autoprefixer
自動でベンダープレフィックスを付与するパッケージ。
gulp-csscomb
自動で CSS のプロパティをソートするパッケージ。
gulp-imagemin
画像のデータ容量を圧縮するパッケージ。
gulp-clean
ファイルを削除するパッケージ。
run-sequence
タスクを並列/直列処理するパッケージ。
Before(grunt)
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
[sourcecode lang="javascript"]module.exports = function(grunt) { // pakage.json を呼び出す var pkg = grunt.file.readJSON('package.json'); grunt.initConfig({ dir: { // ディレクトリ設定 src: '_src', // _srcフォルダ置き換え dist: 'dist' // distフォルダ置き換え }, compass: { // Compassの設定 dist: { options: { config: 'config.rb' // confing.rbを読み込む } } }, connect: { // 簡易サーバー livereload: { options: { port: 3000, hostname: '*', base: '<%= dir.src %>', // ルートディレクトリの場所を指定 livereload: true } } }, watch: { // ファイル更新監視 compassdev: { // scssの監視 files: '<%= dir.src %>/**/*.scss', // 対象ファイル tasks: ['compass'] // 実行タスク(css開発用) }, html: {// htmlの監視 files: ['<%= dir.src %>/*.html','<%= dir.src %>/**/*.html'] }, options: { // ライブリロードを有効にする livereload: true } }, autoprefixer: { // ベンダープレフィックス付与設定 options: { browsers: [ 'last 2 versions' ] // 対象ブラウザの設定 }, default: { expand: true, cwd: '<%= dir.dist %>/css/', // 読み込みファイル src: '{,**/}*.css', dest: '<%= autoprefixer.default.cwd %>' // 書き出しファイル 同じファイルが続くので置き換える } }, csscomb: { // CSSのプロパティの順番整理 default: { src: '<%= autoprefixer.default.src %>', dest: '<%= autoprefixer.default.dest %>' } }, pngmin: { // PNG 画像を圧縮 compile: { options: { ext: '.png' }, files: [ { expand: true, src: ['{,**/}*.png'], cwd: '<%= dir.src %>/images/', dest: '<%= dir.dist %>/images/' } ] } }, copy: { // ファイルのコピー spritesImg: { expand: true, cwd: '<%= dir.src %>/', src: '{,**/}sprites.png', dest: '<%= dir.dist %>/' }, img: { src:['{,**/}*.{png,jpg,gif}'], dest: '<%= dir.dist %>/images/', expand: true, cwd: '<%= dir.src %>/images/' }, css: { expand: true, cwd: '<%= dir.src %>/', src: 'css/**', dest: '<%= dir.dist %>/' }, js: { expand: true, cwd: '<%= dir.src %>/', src: 'js/**', dest: '<%= dir.dist %>/' }, html: { expand: true, cwd: '<%= dir.src %>/', src: '**/*.html', dest: '<%= dir.dist %>/' } }, clean: { // 不要なファイルを削除する deleteDist: { // distフォルダ内のhtml以外を一度全て削除する src: ['<%= dir.dist %>/**/*.html','<%= dir.dist %>/css','<%= dir.dist %>/images','<%= dir.dist %>/js'] }, deleteSprites: { // スプライト画像生成フォルダ(images/sprites)を全て削除する src: ['{,**/}sprites-*.png','<%= dir.dist %>/{,**/}sprites'] } } }); // pakage.jsonに記載されているパッケージをオートロード var taskName; for(taskName in pkg.devDependencies) { if(taskName.substring(0, 6) == 'grunt-') { grunt.loadNpmTasks(taskName); } } // 以下タスクの登録 // デフォルト(各ファイル監視してビルド) grunt.registerTask('default', [ 'connect', 'watch' ]); // リリース用ビルド grunt.registerTask('dist', [ 'clean:deleteDist', 'compass', 'autoprefixer', 'csscomb', 'pngmin', 'copy', 'clean:deleteSprites' ]); };[/sourcecode] |
After(gulp)
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
[sourcecode lang="javascript"]// パッケージをインポートする var gulp = require('gulp'); var compass = require('gulp-compass'); var connect = require('gulp-connect'); var watch = require('gulp-watch'); var autoprefixer = require('gulp-autoprefixer'); var csscomb = require('gulp-csscomb'); var imagemin = require('gulp-imagemin'); var pngquant = require('imagemin-pngquant'); var runSequence = require('run-sequence'); var clean = require('gulp-clean'); // ディレクトリ設定 var dir = { src: '_src', // _srcフォルダ置き換え dist: 'dist' // destフォルダ置き換え } // Compassの設定 gulp.task('compass', function() { return gulp.src( dir.src + '/{,**/}*.scss' ) // 読み込みファイル .pipe(compass({ config_file: 'config.rb', // confing.rb を読み込む css: dir.src + '/css/', // 書き出し先 sass: dir.src + '/sass/' // 読み込み先 })); }); // 簡易サーバー gulp.task('connect', function() { return connect.server({ port: 3000, // ポート番号を設定 root: dir.src, // ルートディレクトリの場所を指定 livereload: true // ライブリロードを有効にする }); }); // 自動更新 gulp.task('reload', function () { return gulp.src(dir.src + '/{,**/}*.html') .pipe(connect.reload()); }); // ファイル更新監視 gulp.task('watch', function() { // scssの監視 gulp.watch([ dir.src + '/{,**/}*.scss' // 対象ファイル ],['compass']); // 実行タスク(css 開発用) gulp.watch([ dir.src + '/{,**/}*.html', // 対象ファイル dir.src + '/{,**/}*.css', dir.src + '/{,**/}*.js' ],['reload']); // 実行タスク(scss ファイル以外が更新されたタイミングでブラウザを自動更新) }); // ベンダープレフィックス付与設定 gulp.task('autoprefixer', function () { return gulp.src( dir.src + '/{,**/}*.css' ) // 読み込みファイル .pipe(autoprefixer({ browsers: ['last 2 versions'] // 対象ブラウザの設定 })) .pipe( gulp.dest( dir.dist ) ); // 書き出しファイル }); // CSSのプロパティの順番整理 gulp.task('csscomb', function () { return gulp.src(dir.src + '/{,**/}*.css') // 読み込みファイル .pipe(csscomb()) .pipe(gulp.dest(dir.dist)); // 書き出し先 }); // 画像を圧縮 gulp.task('imagemin', function () { return gulp.src( dir.src + '/{,**/}*.{png,jpg,gif}' ) // 読み込みファイル .pipe(imagemin()) .pipe(gulp.dest( dir.dist )); // 書き出し先 }); // ファイルのコピー gulp.task('copy', function () { return gulp.src([ dir.src + '/{,**/}*.html', // 対象ファイル dir.src + '/{,**/}*.js' ]) .pipe(gulp.dest( dir.dist )); }); // 不要なファイルを削除する // distフォルダ内を一度全て削除する gulp.task('clean-dist', function () { return gulp.src([ dir.dist + '/{,**/}*.html', // 対象ファイル dir.dist + '/css', dir.dist + '/js', dir.dist + '/img' ], {read: false} ) .pipe(clean()); }); // スプライト画像の生成データを全て削除する gulp.task('clean-sprite', function () { return gulp.src( [ dir.dist + '/{,**/}sprite-*.png', // 乱数付きのスプライト画像 dir.dist + '/{,**/}sprite' // スプライト画像生成フォルダ ], {read: false} ) .pipe(clean()); }); // 以下タスクの登録 // デフォルト(各ファイル監視してビルド) gulp.task('default', [ 'connect', 'watch' ]); // リリース用ビルド gulp.task('dist', function(callback) { return runSequence( // タスクを直列処理する 'clean-dist', 'compass', ['autoprefixer','imagemin'], 'csscomb', 'copy', 'clean-sprite', callback ); });[/sourcecode] |
ディレクトリ構成
構成はシンプルに開発用と納品用でディレクトリを分けるようにしています。
1 2 3 4 5 6 7 8 9 10 11 |
[sourcecode lang="text"]_src/ ← 開発用 css/ img/ js/ sass/ imdex.html dist/ ← 納品用 config.rb gulpfile.js package.json[/sourcecode] |
開発中にブラウザチェックを行なうルートとなるディレクトリは、「_src」 直下になります! ディレクトリ「dist」は空っぽで問題ありません!ディレクトリ「css」やディレクトリ「img」内は、カテゴリ毎でディレクトリを分けても耐えられるようにしています。
基本設定
1. package.json を作成する
1)コマンドプロンプトでプロジェクトとなるディレクトリに移動します。
1 |
[sourcecode lang="text"]cd [path][/sourcecode] |
※[path] は任意
2)コマンドプロンプトで下記コマンドを入力します。
1 |
[sourcecode lang="text"]npm init[/sourcecode] |
3)設定についていろいろ質問が続きますが・・・ ひとまずは、すべて Enter を押していきます。
すると、設定した内容で package.json が生成されたことが確認できます! package.json の設定はのちほど変更することができますが・・・。name の値が gulp となっていると、「3. ローカルに gulp をインストールする」でエラーが出るので、gulp 以外の適当な英数字な値に変更しておきましょう!!
2. グローバルに gulp をインストールする
管理者権限でコマンドプロンプトを立ち上げ、下記コマンドを入力します。
Windows の場合
1 |
[sourcecode lang="text"]npm install gulp -g[/sourcecode] |
Mac の場合
1 |
[sourcecode lang="text"]sudo npm install gulp -g[/sourcecode] |
3. ローカルに gulp をインストールする
コマンドプロンプトで再びプロジェクトとなるディレクトリに移動して、下記コマンドを入力します。
1 |
[sourcecode lang="text"]npm install gulp --save-dev[/sourcecode] |
grunt を扱っていた方はご存知なように、–save-dev を付けることによって package.json にパッケージの記述が自動的に追加されていきます!!
※github のリポジトリの記述がありますが、無くて大丈夫です。
4. gulpfile.js を作成する
もろもろ準備が整ったところで、gulp の設定を行ってまいりましょう!
1)ファイル名「gulpfile.js」として、新規ファイルを作成します。
2)gulpfile.js にパッケージ「gulp」をインポートする記述を追加します。
1 2 |
[sourcecode lang="javascript"]// パッケージをインポートする var gulp = require("gulp");[/sourcecode] |
3)gulpfile.js にディレクトリ設定の記述を追加します。
1 2 3 4 5 |
[sourcecode lang="javascript"]// ディレクトリ設定 var dir = { src: '_src', // _srcフォルダ置き換え dist: 'dist' // destフォルダ置き換え }[/sourcecode] |
このように定義して、ディレクトリパスを管理しやすくします!
さて・・・これで準備完了です!! 次はいよいよ、最強の武器となるタスクを設定していきます!
タスク設定
compass
sass/compass を扱うタスク。
自動で css sprite を生成させる。
パッケージ
インストール
1 |
[sourcecode lang="text"]npm install gulp-compass --save-dev[/sourcecode] |
設定
1 2 3 4 5 6 7 8 9 10 11 12 |
[sourcecode lang="javascript"]// パッケージをインポートする var compass = require('gulp-compass'); // Compassの設定 gulp.task('compass', function() { gulp.src( dir.src + '/{,**/}*.scss' ) // 読み込みファイル .pipe(compass({ config_file: 'config.rb', // confing.rb を読み込む css: dir.src + '/css/', // 書き出し先 sass: dir.src + '/sass/' // 読み込み先 })); });[/sourcecode] |
css や sass のオプションは必須のようです。設定が重複するので、confing.rb の css_dir や sass_dir は削除しておきましょう!
connect
簡易サーバーを立ち上げるタスク。
パッケージ
インストール
1 |
[sourcecode lang="text"]npm install gulp-connect --save-dev[/sourcecode] |
設定
1 2 3 4 5 6 7 8 9 10 11 |
[sourcecode lang="javascript"]// パッケージをインポートする var connect = require('gulp-connect'); // 簡易サーバー gulp.task('connect', function() { connect.server({ port: 3000, // ポート番号を設定 root: dir.src, // ルートディレクトリの場所を指定 livereload: true // ライブリロードを有効にする }); });[/sourcecode] |
reload
ファイル監視中に更新されたタイミングでブラウザを自動更新するために、事前にタスクを作成しておきます!!
設定
1 2 3 4 5 |
[sourcecode lang="javascript"]// 自動更新 gulp.task('reload', function () { gulp.src(dir.src + '/{,**/}*.html') .pipe(connect.reload()); });[/sourcecode] |
watch
ファイルが更新されたら自動でブラウザをリロード(Livereload)するタスク。
パッケージ
インストール
1 |
[sourcecode lang="text"]npm install gulp-watch --save-dev[/sourcecode] |
設定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[sourcecode lang="javascript"]// パッケージをインポートする var watch = require('gulp-watch'); // ファイル更新監視 gulp.task('watch', function() { // scssの監視 gulp.watch([ dir.src + '/{,**/}*.scss' // 対象ファイル ],['compass']); // 実行タスク(css 開発用) gulp.watch([ dir.src + '/{,**/}*.html', // 対象ファイル dir.src + '/{,**/}*.css', dir.src + '/{,**/}*.js' ],['reload']); // 実行タスク(scss ファイル以外が更新されたタイミングでブラウザを自動更新) });[/sourcecode] |
autoprefixer
自動でベンダープレフィックスを付与するタスク。
パッケージ
インストール
1 |
[sourcecode lang="text"]npm install gulp-autoprefixer --save-dev[/sourcecode] |
設定
1 2 3 4 5 6 7 8 9 10 11 |
[sourcecode lang="javascript"]// パッケージをインポートする var autoprefixer = require('gulp-autoprefixer'); // ベンダープレフィックス付与設定 gulp.task('autoprefixer', function () { gulp.src( dir.src + '/{,**/}*.css' ) // 読み込みファイル .pipe(autoprefixer({ browsers: ['last 2 versions'] // 対象ブラウザの設定 })) .pipe( gulp.dest( dir.dist ) ); // 書き出しファイル });[/sourcecode] |
csscomb
自動で CSS のプロパティをソートするタスク。
パッケージ
インストール
1 |
[sourcecode lang="text"]npm install gulp-csscomb --save-dev[/sourcecode] |
設定
1 2 3 4 5 6 7 8 9 |
[sourcecode lang="text"]// パッケージをインポートする var csscomb = require('gulp-csscomb'); // CSSのプロパティの順番整理 gulp.task('csscomb', function () { return gulp.src(dir.src + '/{,**/}*.css') // 読み込みファイル .pipe(csscomb()) .pipe(gulp.dest(dir.dist)); // 書き出し先 });[/sourcecode] |
imagemin
画像のデータ容量を圧縮するタスク。
パッケージ
インストール
1 2 |
[sourcecode lang="text"]npm install gulp-imagemin --save-dev npm install imagemin-pngquant --save-dev[/sourcecode] |
インストール(Windows7の場合)
1 2 |
[sourcecode lang="text"]npm install gulp-imagemin@1.0.0 --save-dev npm install imagemin-pngquant --save-dev[/sourcecode] |
設定
1 2 3 4 5 6 7 8 9 10 11 |
[sourcecode lang="javascript"]// パッケージをインポートする var imagemin = require('gulp-imagemin'); var pngquant = require('imagemin-pngquant'); // 画像を圧縮 gulp.task('imagemin', function () { gulp.src( dir.src + '/{,**/}*.{png,jpg,gif}' ) // 読み込みファイル .pipe(imagemin()) .pipe(gulp.dest( dir.dist )); // 書き出し先 }); [/sourcecode] |
copy
タスク「pngmin」で画像を圧縮した後、dist ディレクトリにコピーします! コピーするだけだと、特別なパッケージをインストールする必要はありません! 下記の記述を追加するだけとなりますっ
設定
1 2 3 4 5 6 7 8 |
[sourcecode lang="javascript"]// ファイルのコピー gulp.task('copy', function () { return gulp.src([ dir.src + '/{,**/}*.html', // 対象ファイル dir.src + '/{,**/}*.js' ]) .pipe(gulp.dest( dir.dist )); });[/sourcecode] |
clean
ファイルを削除するタスク。
パッケージ
インストール
1 |
[sourcecode lang="text"]npm install gulp-clean --save-dev[/sourcecode] |
設定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
[sourcecode lang="javascript"]// パッケージをインポートする var clean = require('gulp-clean'); // 不要なファイルを削除する // distフォルダ内を一度全て削除する gulp.task('clean-dist', function () { gulp.src([ dir.dist + '/{,**/}*.html', // 対象ファイル dir.dist + '/css', dir.dist + '/js', dir.dist + '/img' ], {read: false} ) .pipe(clean()); }); // スプライト画像の生成データを全て削除する gulp.task('clean-sprite', function () { gulp.src( [ dir.dist + '/{,**/}sprite-*.png', // 乱数付きのスプライト画像 dir.dist + '/{,**/}sprite' // スプライト画像生成フォルダ ], {read: false} ) .pipe(clean()); });[/sourcecode] |
default
開発用タスク。各ファイル監視してビルドする。
設定
1 2 3 4 5 6 |
[sourcecode lang="javascript"]// タスクの登録 // 開発用 gulp.task('default', [ 'connect', 'watch' ]);[/sourcecode] |
dist
納品用タスク。データを最適化したり、データ容量を圧縮する。
パッケージ
インストール
1 |
[sourcecode lang="text"]npm install run-sequence --save-dev[/sourcecode] |
設定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[sourcecode lang="javascript"]// パッケージをインポートする var runSequence = require('run-sequence'); // タスクの登録 // 納品用 gulp.task('dist', function(callback) { return runSequence( // タスクを直列処理する 'clean-dist', 'compass', ['autoprefixer','imagemin'], 'csscomb', 'copy', 'clean-sprite', callback ); });[/sourcecode] |
gulp は登録したタスクが並列で実行されていくようになっているのですが、並列で動作するとタスク「imagemin」で画像が軽量化される前に タスク「copy」が実行され、軽量化されないデータがディレクトリ「dist」に書き出されてしまうなど、色々と問題が発生してしまうのです。。これらを防ぐため、タスクが完了してから次のタスクを実行するよう直列な処理ができるように、パッケージ「run-sequence」を併用してあげます!
以上で gulpfile.js が完成となります!!
トラブルシューティング
package.json の name を gulp にしていた場合のエラー
package.json にある name の値が gulp となっていませんか? gulp 以外の適当な英数字な値に変更しましょう!
gulp-imagemin をインストールする際に発生するエラー
※2014/12/11現在 gulp-imagemin@2.0.0
このようなエラーが発生したら・・・。 Windows7 で最新版をインストールしようとすると、エラーが出るので旧バージョンをインストールしましょう。
1 2 |
[sourcecode lang="text"]npm install gulp-imagemin@1.0.0 --save-dev npm install imagemin-pngquant --save-dev[/sourcecode] |
どうやら・・・Windows7 に対応している最新バージョンは「1.0.0」なようです。最新版からスタートして、インストール/アンインストールを繰り返し地道に調べましたよっ
さいごに
いかがでしたでしょうか?
今回は grunt で使っていたタスクをそのまま gulp に書き換えるよう専念しましたが、処理を組み合わせることで、もっともっと記述を短くして処理を軽くすることができるようです!
パッケージをインポートする部分の記述は package.json の内容を自動で読み込むように改変したい・・・!! 今後、今の半分は記述を減らせるように精進したいと思います!!
こちらの記事が皆様のお役に立てていただければ幸いでございます!
長文となりましたが・・・お付き合いいただきありがとうございました!