今更ながらgulpを使ってみる
webpack
で事足りるんじゃと思ったりもしますが、
どこでもそうとは限らないし、何よりgulpはシンプルで分かりやすいです。
gulpって?
node.js
製のビルドシステム。
類似のものにgrunt
、webpack
など。(厳密には前者はタスクランナー、後者はモジュールバンドラ)
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から、モダンフロント開発の世界への仲間入りをしましょう。