今更ながらgulpを使ってみる

Syun Inoue
16 min readOct 24, 2017

--

webpackで事足りるんじゃと思ったりもしますが、
どこでもそうとは限らないし、何よりgulpはシンプルで分かりやすいです。

gulpって?

node.js製のビルドシステム。
類似のものにgruntwebpackなど。(厳密には前者はタスクランナー、後者はモジュールバンドラ)
JSONの様な定義形式の記述ではなく、ピュアなスクリプトで記述するため、タスクフローを可視化しやすかったりします。

ビルド処理自体は単なるストリーム処理でしかないので、
各種プラグインをチェーンしていくことで、最終的な成果物を出力することになります。

なぜビルドシステムが必要なの?

本来、Javascriptにはビルドは必要ありません。
ES5までなら普通に書いてHTMLのscriptタグで読み込めば使えます。

しかし、ここ数年のフロントエンド環境は非常に複雑化し、
Pugなどのテンプレート、commonJSやESModules、CSSプリプロセッサなど、人の手のみで管理することが難しくなってきているのが現状です。

そこにビルドシステムを導入することで、
機械的に処理できる部分を機械に任せることで効率化し、人はコーディングに注力することが出来るのです。

試してみる

インストール

$ yarn add gulp

エントリファイルの作成

まずはエントリファイルを作成します。
特に変哲のないJSとCSSにしています。

  • entry.js
function sum(a, b) {
return a + b;
}
var num = sum(100, 200);console.log(num);
  • entry.css
body {
margin: auto;
}

gulpfile.jsの作成

ビルドタスクはgulpfile.jsというJSファイルに書きます。
まずは特に加工せず、そのまま出力してみます。

  • gulpfile.js
const gulp = require('gulp');// build js
gulp.task('default', function() {
// entry.jsをエントリーポイントに読み込む
gulp.src('entry.js')
// distディレクトリに出力
.pipe(gulp.dest('dist'));
// entry.cssをエントリーポイントに読み込む
gulp.src('entry.css')
// distディレクトリに出力
.pipe(gulp.dest('dist'));
});

ビルドタスクの実行

タスクは、npmからgulpコマンドを呼び出すことで実行できます。

$ yarn gulpyarn run v1.2.1
$ /Users/user/Documents/Workspace/gulp-sample/node_modules/.bin/gu
lp
[04:41:02] Using gulpfile ~/Documents/Workspace/gulp-sample/gulpfil
e.js
[04:41:02] Starting 'default'...
[04:41:02] Finished 'default' after 7.51 ms
✨ Done in 0.32s.

ビルド実行後、./distディレクトリにコンパイル済みコードが出力されていることが確認出来ます。
今回は読み込んでそのまま出力しただけなので、コードに変更はありません。

  • ./dist/entry.js
function sum(a, b) {
return a + b;
}
var num = sum(100, 200);console.log(num);
  • ./dist/entry.css
body {
margin: auto;
}

プラグインを試す

gulpの真髄は各種プラグインを利用出来るというところにあります。
いくつか試してみましょう。

ES2015で書きたい

こんな感じでES2015で書かれたコードを、ブラウザで実行可能なJSにコンパイル(トランスパイル)してみます。
コードの処理内容は前のものと一緒です。

  • entry.es2015.js
const hogesum = a => b => a + b;let res = 0;
res = hogesum(100)(200);
console.log(res);
  • プラグインを追加する
    ついでにbabel用のes2015プリセットを追加します。
$ yarn add babel-core babel-preset-es2015 gulp-babel
  • .babelrcを作成する
    babel用のプリセットを記述する管理ファイルです。
{
"presets": ["es2015"]
}
  • gulpfile.jsにビルドタスクを追加する
    タスクを追加します。
    task関数の第一引数はタスク名となり、コマンドライン引数で指定することで、そのタスクをピンポイントで実行出来ます。
const gulp = require('gulp');
const babel = require('gulp-babel');
// transpile es2015
gulp.task('es2015', function() {
gulp.src('entry.es2015.js')
.pipe(babel())
.pipe(gulp.dest('dist-es2015'));
});
  • ビルドを実行する
$ yarn gulp es2015yarn run v1.2.1
$ /Users/user/Documents/Workspace/gulp-sample/node_modules/.bin/gulp es2015
[05:42:44] Using gulpfile ~/Documents/Workspace/gulp-sample/gulpfile.js
[05:42:44] Starting 'es2015'...
[05:42:44] Finished 'es2015' after 7.44 ms
✨ Done in 0.62s.
  • ./dist-es2015/entry.es2015.js
"use strict";var hogesum = function hogesum(a) {
return function (b) {
return a + b;
};
};
var res = 0;
res = hogesum(100)(200);
console.log(res);

ちゃんと変換されています。

モジュール化したい

モダンなフロントエンドならモジュール化はあたりまえ。
browserifyでモジュール化したes2015コードをコンパイルしてみます。

  • 呼ばれる側(sub.es2015.js)
const fugasum = (a, b) => {
return b => a + b;
}
export default fugasum;
  • 呼ぶ側(entry.es2015.js)
import fugasum from './sub.es2015';const hogesum = a => b => a + b;let hogeres = 0;
hogeres = hogesum(100)(200);
let fugares = 0;
fugares = fugasum(200)(300);
console.log(hogeres);
console.log(fugares);
  • プラグインを追加する
yarn add browserify babelify vinyl-source-stream
  • gulpfile.jsにビルドタスクを追加する
const gulp = require('gulp');const browserify = require('browserify');
const babelify = require('babelify');
const source = require('vinyl-source-stream');
// transpile es2015 with browserify
gulp.task('browserify', function() {
browserify('entry.es2015.js', { debug: true })
.transform(babelify)
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest('dist-browserify'));
});
  • ビルドを実行する
$ yarn gulp browserifyyarn run v1.2.1
$ /Users/user/Documents/Workspace/gulp-sample/node_modules/.bin/gulp browserify
[19:02:17] Using gulpfile ~/Documents/Workspace/gulp-sample/gulpfile.js
[19:02:17] Starting 'browserify'...
[19:02:17] Finished 'browserify' after 13 ms
✨ Done in 1.08s.
  • ./dist/browserify/bundle.js
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';
var _sub = require('./sub.es2015');var _sub2 = _interopRequireDefault(_sub);function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var hogesum = function hogesum(a) {
return function (b) {
return a + b;
};
};
var hogeres = 0;
hogeres = hogesum(100)(200);
var fugares = 0;
fugares = (0, _sub2.default)(200)(300);
console.log(hogeres);
console.log(fugares);
},{"./sub.es2015":2}],2:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var fugasum = function fugasum(a, b) {
return function (b) {
return a + b;
};
};
exports.default = fugasum;},{}]},{},[1])
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJlbnRyeS5lczIwMTUuanMiLCJzdWIuZXMyMDE1LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7QUNBQTs7Ozs7O0FBRUEsSUFBTSxVQUFVLFNBQVYsT0FBVTtBQUFBLFNBQUs7QUFBQSxXQUFLLElBQUksQ0FBVDtBQUFBLEdBQUw7QUFBQSxDQUFoQjs7QUFFQSxJQUFJLFVBQVUsQ0FBZDtBQUNBLFVBQVUsUUFBUSxHQUFSLEVBQWEsR0FBYixDQUFWOztBQUVBLElBQUksVUFBVSxDQUFkO0FBQ0EsVUFBVSxtQkFBUSxHQUFSLEVBQWEsR0FBYixDQUFWOztBQUVBLFFBQVEsR0FBUixDQUFZLE9BQVo7QUFDQSxRQUFRLEdBQVIsQ0FBWSxPQUFaOzs7Ozs7OztBQ1hBLElBQU0sVUFBVSxTQUFWLE9BQVUsQ0FBQyxDQUFELEVBQUksQ0FBSixFQUFVO0FBQ3hCLFNBQU87QUFBQSxXQUFLLElBQUksQ0FBVDtBQUFBLEdBQVA7QUFDRCxDQUZEOztrQkFJZSxPIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsImltcG9ydCBmdWdhc3VtIGZyb20gJy4vc3ViLmVzMjAxNSc7XG5cbmNvbnN0IGhvZ2VzdW0gPSBhID0+IGIgPT4gYSArIGI7XG5cbmxldCBob2dlcmVzID0gMDtcbmhvZ2VyZXMgPSBob2dlc3VtKDEwMCkoMjAwKTtcblxubGV0IGZ1Z2FyZXMgPSAwO1xuZnVnYXJlcyA9IGZ1Z2FzdW0oMjAwKSgzMDApO1xuXG5jb25zb2xlLmxvZyhob2dlcmVzKTtcbmNvbnNvbGUubG9nKGZ1Z2FyZXMpO1xuIiwiY29uc3QgZnVnYXN1bSA9IChhLCBiKSA9PiB7XG4gIHJldHVybiBiID0+IGEgKyBiO1xufVxuXG5leHBvcnQgZGVmYXVsdCBmdWdhc3VtO1xuIl19

コンパイルされ、エントリーモジュールと依存関係のあるモジュールが一つにバンドルされ出力されます。
モジュールのexport/import/requireを現状ブラウザが解釈出来ないため、依存関係まとめて一つにすることで読み込み可能にしています。
ブラウザでJSを動く様に変化させる魔法、browserify。

さて、最後に一つ。
CSS周りもモダンにしてしまいましょう。

sassを使いたい

当然、sassもプラグインの追加でいけちゃいます。
今時のcssはsassで決まりですね。

  • entry.scss

変数・ネスト・mixinあたりを適当に。

$color: green;@mixin hoge($width, $height) {
width: $width;
height: $height;
}
.fuga {
background-color: $color;
@include hoge(400px, 300px);
.piyo {
font-weight: bold;;
}
}
  • プラグインを追加する
$ yarn add gulp-sass
  • gulpfile.jsにビルドタスクを追加する
const gulp = require('gulp');
const sass = require('gulp-sass');
// compile scss
gulp.task('build-sass', function() {
gulp.src('entry.scss')
.pipe(sass({ outputStyle: 'expanded' }))
.pipe(gulp.dest('dist-sass'));
});
  • buildを実行する
$ yarn gulp build-sassyarn run v1.2.1
$ /Users/user/Documents/Workspace/gulp-sample/node_modules/.bin/gulp build-sass
[21:50:15] Using gulpfile ~/Documents/Workspace/gulp-sample/gulpfile.js
[21:50:15] Starting 'build-sass'...
[21:50:15] Finished 'build-sass' after 8.33 ms
✨ Done in 0.60s.
  • ./dist-sass/entry.css
.fuga {
background-color: green;
width: 400px;
height: 300px;
}
.fuga .piyo {
font-weight: bold;
}

ブラウザで解釈できるcss形式にコンパイルされています。

まとめ

大規模化・複雑化していくフロントアプリの開発にJSのモジュールシステムやCSSプリプロセッサは非常に有効ですが、
その分開発環境そのものが複雑化していることも確かです。

幸い(?)、gulpはビルドシステムとして非常に分かりやすいので、取っ掛かりとしては最適でしょう。

まずはgulpから、モダンフロント開発の世界への仲間入りをしましょう。

--

--