Otomatisasi dengan Gulp

Gulp adalah sebuah program utilitas untuk otomatisasi pemrosesan file. Program ini bisa kita pake untuk minifikasi skrip (dengan plugin), kopi file dari satu tempat ke tempat lain, dan sebagainya. Kalo Anda pake Mac, program ini mirip dengan Automator, jadi bisa disebut juga task runner karena fungsi utamanya jalanin task.

Dari titel di websitenya,

Gulp: “The streaming build system”

Jadi, apa itu stream?

Kalo kita baca-baca di Wikipedia, istilah file stream banyak disebut dalam artikel yang ada kaitannya dengan I/O (input/output). Sederhananya, file stream adalah sederetan data, representasi sebuah file, yang bisa kita baca, modifikasi, & simpan dalam bentuk file lagi. File stream dibuat di memori pada waktu kita buka sebuah file. Modifikasi sebuah stream terjadi sangat cepat karena dilakukan saat data masih ada di memori sebelum disimpan kembali dalam bentuk file. Karena itulah, dibanding task runner lain seperti Grunt, Gulp lebih cepat dalam memodifikasi file.

Instalasi

Karena Gulp adalah program untuk NodeJS. Tentu step pertama adalah instal Node. Proses instalasinya di luar konteks tutorial ini, jadi silakan Anda coba sendiri.

Setelah kita instal Node, kita instal gulp pake NPM (Node Package Manager). Perintahnya begini:

npm install gulp

Terus pastikan gulp ada di system path.

Berikutnya, silakan baca-baca sedikit tentang Gulp API. Dari API yang ada di dokumentasinya, berikut ini yang paling sering kita pake.

  • gulp.task() : bikin task
  • gulp.src() : baca file/folder & bikin stream
  • gulp.dest() : simpen stream sebagai file
  • pipe() : kirim stream dari satu proses ke proses lain

Bikin Task

Seperti saya bilang di atas, Gulp adalah task runner jadi inti dari Gulp adalah task. Task yang ingin kita jalanin kita tulis dalam file yang disebut gulpfile. Jadi sekarang kita bikin file gulpfile.js yang kita isi dengan kode JavaScript.

var gulp = require('gulp');

gulp.task('hello',function(){
    console.log('hello gulp!');
})

Jalanin gulp di terminal.

gulp hello

Outputnya:

[gulp] Using gulpfile /Users/boss/Desktop/gulp_tut/demo/gulpfile.js
[gulp] Starting 'hello'...
hello gulp!
[gulp] Finished 'hello' after 80 μs

Secara default, Gulp jalanin task yang ada dalam file bernama gulpfile.js. Tapi kita bisa bikin file dengan nama lain, misalnya mybuildscript.js & kalo kita pake file ini, perintahnya jadi begini,

gulp --gulpfile mybuildscript.js hello

Kita coba bikin task untuk kopi file.

gulp.task('copy',function(){
    //buka file myfile.txt
    gulp.src('myfile.txt')
        //terusin (pipe) stream untuk disimpan di folder sub
        .pipe(gulp.dest('sub'));
})

Bikin dulu file myfile.txt terus jalanin gulp copy di terminal.

Output:

[gulp] Using gulpfile /Users/boss/Desktop/gulp_tut/demo/gulpfile.js
[gulp] Starting 'copy'...
[gulp] Finished 'copy' after 12 ms

Hasilnya

Gulp copy

Task Dependency

Sebuah task bisa bergantung pada eksekusi task lain (dependency). Sintaksnya

gulp.task('namatask',['namatasklainyangharusdijalaninjuga'],function(){
    //proses
})

Coba kita bikin task copy bergantung pada task hello.

gulp.task('hello',function(){
    console.log('hello gulp! mulai ');
})

//utk jalanin copy, hello juga harus dijalanin
gulp.task('copy',['hello'],function(){
    //buka file myfile.txt
    gulp.src('myfile.txt')
        //terusin (pipe) untuk dikopi
        .pipe(gulp.dest('sub'));
})

//untuk jalanin default, copy juga harus dijalanin
gulp.task('default',['copy'])

Jalanin task default.

gulp

Untuk jalanin task default kita ga perlu kasih nama task sebagai argumen karena kalo ada task default di dalam gulpfile & kita jalanin gulp tanpa argumen, gulp otomatis pilih task itu.

Output di terminal:

[gulp] Using gulpfile /Users/boss/Desktop/gulp_tut/demo/gulpfile.js
[gulp] Starting 'hello'...
hello gulp!
[gulp] Finished 'hello' after 81 μs
[gulp] Starting 'copy'...
[gulp] Finished 'copy' after 15 ms
[gulp] Starting 'default'...
[gulp] Finished 'default' after 11 μs

Task hello, copy, & default dijalanin hampir bersamaan. copy ga nunggu hello selesai, default juga ga nunggu copy selesai. Buktinya begini, kita bikin task hello selesai dalam 2 detik.

gulp.task('hello',function(){
    console.log('hello gulp! mulai ');
    setTimeout(function(){
        console.log('hello gulp! selesai' );
    },2000);
})

Output di terminal:

[gulp] Using gulpfile /Users/boss/Desktop/gulp_tut/demo/gulpfile.js
[gulp] Starting 'hello'...
hello gulp! mulai 
[gulp] Finished 'hello' after 444 μs
[gulp] Starting 'copy'...
[gulp] Finished 'copy' after 14 ms
[gulp] Starting 'default'...
[gulp] Finished 'default' after 7.41 μs
hello gulp! selesai

Kita liat hello baru selesai setelah default selesai padahal task ini mulai dijalanin sebelum copy.

Jalanin task secara asinkron (berurutan)

Task dijalanin paralel kecuali kita pake callback , kirim stream sebagai nilai balik dari task atau pake promise.

Apa itu Promise? Promise adalah proses yang ditunda (deferred) & kita pake sebagai pengganti callback kalo kita ingin jalanin beberapa proses secara berurutan, satu proses setelah proses sebelumnya selesai. Untuk lebih jelasnya silakan baca penjelasan Promise di MDN

Di sini kita pake promise yang disediain library bernama Q. Untuk instal Q, kita pake perintah yang sama dengan perintah untuk instal Gulp. Hanya beda nama paketnya aja.

npm install q

Kita coba buat 4 task yang harus dijalanin secara berurutan. Jadi kurang lebih begini:

task1->task2->task3->default

Bikin 4 task baru di gulpfile.js.

//pake callback
gulp.task('task1',function(cb){
    gulp.src('myfile.txt')
        .pipe(gulp.dest('sub'));

    setTimeout(function(){
        console.log('task1 selesai')
        cb();
    },2000);        
})

//task2 bergantung task1 (dependency)
gulp.task('task2',['task1'],function(){
    //pake return stream
    var stream = gulp.src('myfile.txt')
        .pipe(gulp.dest('sub2'));
    console.log('task2 selesai');
    return stream;
})

//task3 bergantung task2
gulp.task('task3',['task2'],function(){
    //pake promise
    var Q = require('q');
    var d = Q.defer();
    setTimeout(function(){
        console.log('task3 selesai')
        d.resolve();
    },1000);
    return d.promise;
})

gulp.task('default',['task3'])

Jalanin gulp. Output di terminal:

[gulp] Using gulpfile /Users/boss/Desktop/gulp_tut/demo/gulpfile.js
[gulp] Starting 'task1'...
task1 selesai
[gulp] Finished 'task1' after 2.01 s
[gulp] Starting 'task2'...
task2 selesai
[gulp] Finished 'task2' after 6.33 ms
[gulp] Starting 'task3'...
task3 selesai
[gulp] Finished 'task3' after 1 s
[gulp] Starting 'default'...
[gulp] Finished 'default' after 14 μs

Kita liat task2 nunggu task1 selesai, task3 nunggu task2 selesai, dan seterusnya.

gulp-watch

Selain beberapa API yang kita coba di atas, ada lagi satu API yang berguna untuk otomatis jalanin task kalo ada perubahan isi file / direktori. Namanya watch.

Kita bikin direktori bernama sub3, bikin file file1.txt, terus bikin task.

gulp.task('watchsub3',function(){
    gulp.watch('sub3/*/*',function(event){
        console.log(event.path+' ' + event.type);
    })    
})

sub3/**/* artinya semua file yang ada di sub3 & subdirektorinya. Kalo sub3/* artinya semua file yang ada di sub3, nggak termasuk yang ada di subdirektori.

Jalanin task, gulp watchsub3

Sekarang coba hapus file.txt. Perhatiin status di terminal.

[gulp] Using gulpfile /Users/boss/Desktop/gulp_tut/demo/gulpfile.js
[gulp] Starting 'watchsub3'...
[gulp] Finished 'watchsub3' after 7.26 ms
/Users/boss/Desktop/gulp_tut/demo/sub3/file1.txt deleted

Bikin file baru, file2.txt.

/Users/boss/Desktop/gulp_tut/demo/sub3/file2.txt added

Ubah isi file2.txt.

/Users/boss/Desktop/gulp_tut/demo/sub3/file2.txt changed

Supaya watch bisa jalan, isi direktori targetnya ga boleh kosong waktu task dijalanin.

watchsub3 terus jalan sampai kita matiin pake Ctrl+C (Linux/OSX) atau Ctrl+D (Windows).

Kalo cuman pake contoh sederhana di atas, nggak asik kan… 😉 Jadi sekarang kita coba pake Gulp untuk otomatisasi proyek website. Dalam contoh berikutnya kita coba jalanin beberapa task yang umum dibutuhin dalam pembuatan website:

  1. minifikasi/optimasi asset: JS, CSS, HTML, & gambar
  2. simpan hasil minifikasi di direktori khusus yang terpisah dari source code

Bukan berarti Gulp hanya cocok untuk proyek web lho … dia bisa dipake untuk segala macem keperluan yang butuh otomatisasi. Pokoknya mirip Automator di OSX lah.

Otomatisasi Proyek Web

Kita buat dulu direktori untuk proyek, kasih nama myweb. Terus bikin subdirektori src & di dalamnya kita bikin subdirektori untuk file JS, CSS, & HTML. Tambahin juga satu atau dua gambar. Bikin lagi satu subdirektori, kasih nama public_html, tempat kita simpan hasil minikasi. Kita bikin juga file gulpfile.js di direktori myweb. Jadi kurang lebih struktur direktorinya begini:

Direktori Proyek

Direktori Proyek

Task 1 : Minifikasi JS

Untuk minifikasi JS, kita perlu pake plugin yang namanya gulp-uglify. Kita instal dulu.

npm install gulp-uglify

Terus kita bikin tasknya.

var gulp = require('gulp');
var DEST = 'public_html';

//task 1
var uglify = require('gulp-uglify')
gulp.task('minifyjs',function(){
    return gulp.src('src/js/*')
            .pipe(uglify())
            .pipe(gulp.dest(DEST+'/js'));
});

Buka file index.js & tulis kode berikut:

(function(){
    console.log('index.js');
})();

Coba jalanin: gulp minifyjs.

Hasilnya, file src/js/index.js diminifikasi & hasilnya ada di public_html/js/index.js.

Minified JS

Minified JS

Task 2 : Minifikasi CSS

Instal gulp-minify-css.

npm install gulp-minify-css

Buat task minifycss.

//task 2
var minifyCSS = require('gulp-minify-css');
gulp.task('minifycss',function(){
    return gulp.src('src/css/*')
            .pipe(minifyCSS())
            .pipe(gulp.dest(DEST+'/css'));
})

Buka file index.css & tulis kode berikut:

body{
    padding:0;
    margin:0;
}

Jalanin task gulp minifycss.

Hasilnya:

Minified CSS

Minified CSS

Task 3 : Minifikasi HTML

Instal plugin gulp-minify-html.

npm install gulp-minify-html

Bikin tasknya.

var minifyHTML = require('gulp-minify-html');
gulp.task('minifyhtml',function(){
    return gulp.src('src/*.html')
            .pipe(minifyHTML())
            .pipe(gulp.dest(DEST));
})

Buka file index.html & isi dengan kode berikut:

<html>
    <head>
        <title>My Awesome Web</title>
    </head>
    <body>
    </body>
</html>

Jalanin task, gulp minifyhtml.

Hasilnya:

Minified HTML

Minified HTML

Task 4 : Optimasi Gambar

Instal gulp-image.

npm install gulp-image

Plugin ini agak besar, jadi instalnya lumayan lama. Bisa ditinggal ngopi dulu lah …

Kalo udah selesai, bikin tasknya.

var optimizeImg = require('gulp-image');
gulp.task('optimage',function(){
    return gulp.src('src/images/*')
            .pipe(optimizeImg())
            .pipe(gulp.dest(DEST+'/images'));
})

Terus jalanin gulp optimage

Hasilnya (di komputer saya):

[gulp] Using gulpfile /Users/boss/Desktop/gulp_tut/demo/myweb/gulpfile.js
[gulp] Starting 'optimage'...
[21:31:15] - image-1.jpg -> Can't improve upon 39.37 kB
[21:31:16] ✔ image-2.png -> before=6.07 kB after=3.01 kB reduced=3.06 kB(50.4%)
[gulp] Finished 'optimage' after 4.09 s
Optimized Images

Optimized Images

Task Default : Otomatisasi Task 1 – 4

Kalo jalanin task satu-satu setiap kali kita bikin file baru atau modifikasi file ya ga asoy …

Kita bikin beberapa watcher untuk masing-masing tipe file.

gulp.task('watchjs',function(){
    //jalanin task minifyjs kalo isi src/js/ 
    //atau file di dalamnya berubah
    gulp.watch('src/js/*',['minifyjs'])
});

gulp.task('watchcss',function(){
    gulp.watch('src/css/*',['minifycss'])
});

gulp.task('watchhtml',function(){
    gulp.watch('src/*.html',['minifyhtml'])
});

gulp.task('watchimg',function(){
    gulp.watch('src/images/*',['optimage'])
});

Jalanin semua task di atas dalam task default.

gulp.task('default',['watchjs','watchcss','watchhtml','watchimg']);

Terus jalanin gulp.

Output di terminal:

[gulp] Using gulpfile /Users/boss/Desktop/gulp_tut/demo/myweb/gulpfile.js
[gulp] Starting 'watchjs'...
[gulp] Finished 'watchjs' after 6.79 ms
[gulp] Starting 'watchcss'...
[gulp] Finished 'watchcss' after 1.47 ms
[gulp] Starting 'watchhtml'...
[gulp] Finished 'watchhtml' after 889 μs
[gulp] Starting 'watchimg'...
[gulp] Finished 'watchimg' after 914 μs
[gulp] Starting 'default'...
[gulp] Finished 'default' after 7.01 μs

Semua watcher di atas jalan terus sampai kita terminasi pake Ctrl+C atau Ctrl+D.

Coba kita edit file index.js.

(function(){
    var name = 'index.js';
    console.log(name);
    console.log('hello'); 
})();

Pas kita simpan file ini, di terminal kita lihat minifyjs otomatis dijalanin lagi (setelah default di atas).

[gulp] Starting 'minifyjs'...
[gulp] Finished 'minifyjs' after 8.2 ms

Dan isi public_html/js/index.js juga berubah.

Coba bikin file baru, src/js/app.js. Task minifyjs dijalanin lagi & ada file baru public_html/js/app.js.

Coba lagi, edit file src/css/index.css.

body{
    padding:0;
    margin:0;
    background: black;
}

Kalo file ini kita simpan, task minifycss dijalanin lagi.

Silakan coba sendiri task yang lain.

Misalnya, kita ingin kirim file proyek ke klien dalam bentuk Zip. Kita bikin task baru, pake plugin gulp-zip.

Setelah plugin kita instal, kita bikin tasknya.

var zip = require('gulp-zip');
gulp.task('zip',function(){
    return gulp.src(DEST+'/**/*')
            .pipe(zip('myweb.zip'))
            .pipe(gulp.dest('.'));
});

gulp.task('autozip',function(){
    gulp.watch(DEST+'/**/*',['zip']);
})

gulp.task('default',['watchjs','watchcss','watchhtml','watchimg','autozip']);

Matiin task default, terus jalanin lagi.

Sekarang setiap kali kita ada file baru atau ada file yang diupdate di direktori public_html atau subdirektorinya, gulp akan membuat file myweb.zip yang isinya sama dengan isi public_html. Mantaf kan? 🙂

MyWeb Zipped

MyWeb Zipped

gulpfile.js lengkapnya:

var gulp = require('gulp');
var DEST = 'public_html';

//task 1
var uglify = require('gulp-uglify')
gulp.task('minifyjs',function(){
    return gulp.src('src/js/*')
            .pipe(uglify())
            .pipe(gulp.dest(DEST+'/js'));
});

//task 2
var minifyCSS = require('gulp-minify-css');
gulp.task('minifycss',function(){
    return gulp.src('src/css/*')
            .pipe(minifyCSS())
            .pipe(gulp.dest(DEST+'/css'));
})

//task 3
var minifyHTML = require('gulp-minify-html');
gulp.task('minifyhtml',function(){
    return gulp.src('src/*.html')
            .pipe(minifyHTML())
            .pipe(gulp.dest(DEST));
})

//task 4
var optimizeImg = require('gulp-image');
gulp.task('optimage',function(){
    return gulp.src('src/images/*')
            .pipe(optimizeImg())
            .pipe(gulp.dest(DEST+'/images'));
})

gulp.task('watchjs',function(){
    gulp.watch('src/js/*',['minifyjs']);
});

gulp.task('watchcss',function(){
    gulp.watch('src/css/*',['minifycss']);
});

gulp.task('watchhtml',function(){
    gulp.watch('src/*',['minifyhtml']);
});

gulp.task('watchimg',function(){
    gulp.watch('src/images/*',['optimage']);
});

var zip = require('gulp-zip');
gulp.task('zip',function(){
    return gulp.src(DEST+'/**/*')
            .pipe(zip('myweb.zip'))
            .pipe(gulp.dest('.'));
});

gulp.task('autozip',function(){
    gulp.watch(DEST+'/**/*',['zip']);
})

gulp.task('default',['watchjs','watchcss','watchhtml','watchimg','autozip']);

Segini aja tutorialnya. Silakan coba-coba sendiri. Kalo ada pertanyaan, silakan tanya saya atau Om Google. Daftar plugin yang bisa Anda pake bisa diliat di NPM.

Also in this category ...