PUG dan LESS untuk Mempercepat Development Halaman Web

yussan 5 Januari 2017

PUG dan LESS untuk Mempercepat Development Halaman Web

Sering ketika saya sedang membuat sebuah halaman html yang didalam sudah mencangkup css untuk styling, terjadi proses copy paste terutama untuk bagian header dan footer yang pasti selalu ada di setiap halaman html. Masalah mulai muncul ketika ternyata ada perubahan pada desain header, dengan terpaksa saya harus merubah satu persatu halaman html agar sesuai dengan desain yang baru, tentu ini merepotkan jika perubahan tidak hanya pada satu titik yang sama. Karena hal tersebut saya mencari solusi yang tepat untuk permasalahan ini, hingga saya menemukan pug dulunya dikenal dengan jade untuk detail selengkapnya silakan baca di halaman resminya https://pugjs.org/. Merupakan sebuah library untuk templating html. Melalui pug saya bisa membagi halaman html menjadi component-component kecil yang sifat reusable alias bisa digunakan di berbagai tempat, disamping itu pug juga memungkinkan untuk menjalankan conditional dan looping, sangat cocok ketika saya membuat halaman berisi chat list, cukup membuat data JSON  dan satu component maka bisa menghasilkan chat list yang banyak dengan sedikit melakukan koding.

Less sendiri memilki konsep yang sama dengan pug, hanyak saya bukan ditujukan untuk html melainkan untuk styling di css, detail selengkapnya bisa dibaca di halaman resminya http://lesscss.org. Disini saya tidak akan menunjukan penggunaan pug dan less secara independen, tetapi menggunakan gabungan dari Node JS sebagai server dan Gulp untuk buildernya, tujuannya agar kita bisa fokus ke pug dan less dan biarkan builder yang melakukan kompilasi secara otomatis, dan disini saya menggunakan bash shell untuk eksekusi beberapa commands, untuk pengguna Windows kemungkinan besar harus install bash dari pihak ketiga.

Karena ini hanya pengenalan, maka saya tidak menyertakan apa saja yang tersedia baik di pug atau less, untuk lebih mendalami kedua hal tersebut, silahkan baca dokumentasi resminya di link yang telah saya lampirkan.

Melakukan Persiapan

Sebelum mengikuti tutorial ini, pastikan kamu telah instalasi Node JS dan NPM di perangkat yang akan digunakan untuk development. Kamu bisa baca cara instalasinya dari Artikel buatan Tony Haryanto di link berikut.

Siapkan sebuah direktori kosong untuk inisialisasi project  baru, dan lanjutkan masuk ke direktori tersebut menggunakan terminal. Lanjutkan dengan inisialisi project baru menggunakan perintah.

$npm init

Ikuti pentujuknya hingga selesai, maka kamu akan mendapatkan file baru bernama pacakage.json. Berikut adalah install beberapa dependency yang dibutuhkan untuk proses developing. Didalam direktori aktif, silahkan install beberapa dependency berikut :

$sudo npm install gulp -g
$npm install gulp --save-dev
$npm install gulp-less --save-dev

$npm install gulp-pug --save-dev

$npm install browser-sync --save-dev

Karena semua dependency diatas cuma dibutuhkan waktu proses developing dan tersimpan difile package.json maka saya tambah option --save-dev. Sebenarnya untuk gulp bisa diinstall secara global atau tidak ada masalah. 

Berikut penjelasannya :

gulp adalah salah satu developer tool yang popular untuk beberapa javascript project, gulp akan saya gunakan untuk menyimpan task berisi compiler untuk file .pug dan .less secara otomatis.

gulp-pug dan gulp-less dependency ini dibutuhkan gulp untuk compile .pug menjadi .html dan .less menjadi .css.

browser-sync sangat berguna karena ketika gulp menyelesaikan tasknya untuk proses kompilasi, secara otomatis tampilan di browser akan berubah secara realtime sehingga kita tidak perlu untuk melakukan refreshing.

Struktur direktori :

Berikut struktur direktori yang sering saya gunakan, kalian bisa ubah sesuka hati, tapi untuk konfigurasi gulp task  hanya bisa jalan pada struktur berikut :

./
  _site/
    css/
  less/
    partials/
    style.less
  layouts/
    default.pug
  partials/
  index.pug

Ada 5 macam direktori pada deskripsi diatas, _site/ digunakan untuk menyimpan hasil kompilasi .pug yaitu .html. Didalamnya ada css/ digunakan untuk meyimpan hasil kompilasi .less menjadi .css . Masing-masing direktori less/ dan ./ terdapat direktori partials/ nantinya akan digunakan untuk menjadi file .pug atau .less yang sifatnya reusable(dapat digunakan kembali). Sedangkan untuk layouts/ digunakan untuk .pug  yang bertugas sebagai base layout, contoh pada suatu halaman suatu web pasti ada header dan footer, menggunakan base layout ini maka bisa digunakan untuk membungkus container dengan header dan footer yang sama dengan container lainnya.

Membuat Gulp Tasks

Ada 4 tasks yang saya terapkan untuk gulp, tapi sebelumnya, di direktori utama silahkan buat file kosong bernama gulpfile.js , dan isi dengan code berikut :
const gulp = require('gulp'),
    path = require('path'),
    pug = require('gulp-pug'),
    less = require('gulp-less')
    browserSync = require('browser-sync');

const SITE_DIR = '_site', LESS_DIR = 'less', CSS_DIR = '_site/css';

/**

  • pug compiler / gulp.task('pug', function(){ gulp.src('.pug') .pipe(pug({pretty: true})) .pipe(gulp.dest(SITE_DIR)) .pipe(browserSync.reload({stream: true})) })

/**

  • less compiler / gulp.task('less', function(){ return gulp.src(LESS_DIR + '/.less') .pipe(less({ includePaths: LESS_DIR, })) .pipe(gulp.dest(CSS_DIR)) .pipe(browserSync.reload({stream: true})) })

gulp.task('browser-sync', ['less', 'pug'],function(){ browserSync({ server: {baseDir: SITE_DIR}, notify: true }) })

gulp.task('watch', function(){ gulp.watch(LESS_DIR + '/', ['less']) gulp.watch(['*pug', '/*.pug'], ['pug']) })

gulp.task('default', ['browser-sync', 'watch'])

Berikut penjelasannya tasknya

Ada 4 task yang saya gunakan di konfigurasi gulpfile , pertama adalah default task, sifatnya adalah mandatory untuk setiap gulpfile dan task inilah yang dipanggil pertama kali untuk kemudian akan mentrigger tasks lainnya. Dilanjutkan task browser-sync  yang memungkinkan ketika .pug atau .less telah selesai terkompilasi maka halam di browser secara otomatis ikut berubah. Task watch ditujukan untuk selalu memonitor task pug dan task less yang tugasnya mengecek perubahan yang terjadi pada direktori dan file .pug atau .less untuk kemudian dilanjutkan dengan kompilasi ke .html dan .css.

Test run

Didalam direktori utama eksekusi perintah berikut
$gulp
Jika konfigurasi benar, maka keluar tampilan seperti berikut.

Untuk port bisa berbeda-beda tergantung ketersediaan, defaultnya menggunakan port 3000, jika tidak ada error di halaman peramban dan ada file index.html pada direktori _site, maka persiapan selesai dan siap untuk masuk tahap development.

Memulai Bagian Pug

Contoh yang saya berikan kali ini adalah halaman chat, untuk .pugnya membutuhkan 1 base layout yaitu default.pug,container  yaitu index.pug, kemudian header.pug , chat-item.pug dan editor.pug.

Bagian pertama kita fokus untuk membuat layout/default.pug, jika terbiasa dengan python maka mudah pula untnuk terbiasa dengan pug, jika dibandingkan dengan html maka perbedaan yang paling terlihat untuk code style nya adalah, pug tanpa tag, contoh :

di html

di pug

p

strong mama lapar

Pug menggunakan indentation untuk membedakan apakah node dibawahnya merupakan node lain atau sebagai childnode, jika sudah terbiasa dengan phyton atau bahasa lain yang menggunakan style yang sama, pasti tidak terlalu sulit untuk memahami ini .

Memulai Bagian PUG

Seperti yang sudah saya sampikan diatas

Membuat layout

Sebelumnya pastikan konfigurasi Gulp  sudah berjalan dengan baik, untuk kemudian jalankan terus untuk melanjutkan bagian ini. Bagian ini fokuskan untuk membuat satu buah file bernama default.pug didalam direktori /layouts, file bisa terus bertambah sesuai dengan kebutuhan, isinya sebagai berikut :
html
head

link(href="./css/style.css" rel="stylesheet" type="text/css")

block script

title idmore - PUG and LESS boilerplate

body

block content

Untuk lebih memudahkan penjelasan layout diatas mari kita lanjutkan ke bagian container.

Membuat container

Rancangan layout diatas yang adalah berisi tag wajib untuk halaman html. Tapi ada jika diperhatikan ada 2 tag yang berbeda, yaitu blockblock sendiri bisa dibilang tempat untuk meletakan child node, defaultnya adalah kosong, layout tersebut yang akan digunakan untuk semua container di tutorial ini. Contoh penggunaan untuk index.pug adalah sebagai berikut :
extends layouts/default
block content

p this is content

Karena container membutuhkan layout/default.pug  sebagai base layoutnya maka perlu di extends terlebih dahulu seperti contoh. Setelah diubah menjadi html maka seperti inilah hasilnya.

Bagaiman dengan block script, karena di container index.pug tidak saya deklarasi, maka defaultnya kosong.

Pug menggunakan indentation sebagai penanda apakah node merupakan child atau parent, pada contoh diatas bisa dilihat bagaimana indentation bekerja di pug. Gunakan alamat yang didapat dari Gulp untuk melakukan review terhadap halaman web yang telah dibuat.

Membuat component

Saya mengembangkan index.pug  hingga menjadi seperti berikut :
extends layouts/default
block content header.chat-title span.text Chat with @erza

.chat-block .chat-item.opponent div are you ready small 2 minutes ago .chat-item.opponent div okay let'get started small a moment ago

.chat-editor div textarea

Berikut hasil setelah tercompile.

Penulisan div dan class

Div memiliki keistimewaan sendiri di Pug, sebagai contoh ada div memiliki class 'col-md-2 big', maka penulisannya cukup menjadi :
.col-md-2.big
Tapi hal tersebut tidak berlaku untuk tag lain, sebagai contoh navbar memiliki kelas 'big', maka penulisannya menjadi :
navbar.big
Hal tersebut berlaku untuk semua tag kecuali div. Untuk penulisan atribut lain, seperti inline styledata-attribute, untuk penulisannya sendiri sama seperti di html hanya saja, atribut tersebut ditulis didalam tanda kurung seperti contoh :
.col-md-2(data-toggle="modal" ref="gender")

Dummy data

Dari index.pug  ada baris yang menggunakan kode sama, pada kasus ini adalah pada div.chat-item, tapi disamping sama ada satu kondisi lain, yaitu untuk hasil tulisan sendiri memiliki class .chat-item.me, sedang untuk hasil tuisan lawan obrolan memilki class .chat-item.opponent.

Untuk memudahkan langkah selanjutnya saya membuat variabel berisi dummy data untuk isi obrolan, untuk versi prety json bisa dicek pada file dummy_chat.json pada repo yang telah saya sertakan di artikel ini isinya adalah dummy data yang meliputi isi obrolan.

[

{

"id": 1,

"user": {

"username": "aika"

},

"text": "are you ready ?",

"created_at": "2 mins ago"

},

{

"id": 2,

"user": {

"username": "rin"

},

"text": "okay let's get started",

"created_at": "a moment ago"

}

]

Berikut adalah penulisan variabel di index.pug 

...

.chat-block

  • var dummy = [{"id":1,"user":{"username":"aika"},"text":"are you ready ?","created_at":"2 mins ago"},{"id":2,"user":{"username":"rin"},"text":"okay let's get started","created_at":"a moment ago"}]

.chat-item.opponent

...

Saya menaruh variabel dalam satu line diantara .chat-block dan .chat-item.

Component 

Berikutnya adalah membuat component  dan menaruhnya didalam direktori /partials, component dibuat terpisah karena sifatnya yang reusable alias akan digunakan dicontainer atau bahkan di component lain. Membuat file baru bernama /partials/chat-item.pug, dan isi seperti berikut :
div(class=n.user.username === 'aika' ? "chat-item me":"chat-item opponent")
div #{n.text}

small #{n.created_at}

Sedang untuk index.pug berubah menjadi seperti berikut :

extends layouts/default

block content

header.chat-title Chat with @erza

.chat-block

  • var dummy = [{"id":1,"user":{"username":"aika"},"text":"are you ready ?","created_at":"2 mins ago"},{"id":2,"user":{"username":"rin"},"text":"okay let's get started","created_at":"a moment ago"}]

each n, key in dummy

include partials/chat-item

.chat-editor

textarea

Mari bahas terlebih dahulu untuk index.pugnya. Perubahan terjadi pada chat-item, dari dummy data yang sudah disiapkan sebelumnya, dilakukan looping array seperti yang biasa dilakukan pada bahasa pemrograman lain. Tiap perulangan akan include component partials/chat-item yang sekaligus mengirim variabel n untuk bisa digunakan di gunakan di component  tersebut.

Cukup seperti ini dulu untuk .pugnya, jika membaca di situs resminya yang telah saya lampirkan diakhir, masih banyak yang bisa dieksplorasi untuk lebih mengoptimalkan penggunannya.

Memulai Bagian LESS

Beberapa hal yang perlu diperhatikan untuk bagian Less, saya membagi file  menjadi beberapa bagian, antara lain, main bisa dibilang sama dengan container untuk Pugconst untuk menyimpan konstanta yang meliputi warna, ukuran dan perhitungan lain yang bersifat reusable dan satu bagian akhir untuk beberapa style yang sifatnya reusable.

Jika sebelumnya pernah mengenal scss/sass  maka kalian akan terbiasa dengan less, saya pilih less karena banyak framework terkenal untuk web frontend untuk stylingnya, salah satu contohnya bootstrap.

Beberapa hal yang saya bahas di bagian ini adalah nesting, mixins dan operations, karena 3 hal tersebut yang paling sering ada pada project less.

Nesting

Untuk lebih gampangnya, saya ada perbandingan dari css dan less.

di css :

.chat-block{
  width: 100%;
  display: table;
}

.chat-block.chat-item{ display: table-row }

di less :

.chat-block{
  width: 100%;
  display: table;
  .chat-block.chat-item{
     display: table-row
  }
}

Baris less  dibawah menhasilkan css yang sama seperti diatas, dengan nesting akan mempermudah pada developer untuk memahami hubungan antar style satu dan lainnya.

Mixin

Konsepnya sama seperti component  di pug, memungkinkan style, method, variabel dan hal lainnya bisa digunakan di .less lain alias reusable. Sebagai contoh, saya punya style sebagai berikut :

di less :

@mixin text-bold($size){

font-weight: strong;

font-size: $size

}

h1.title{

@include text-bold(23px)

}

hasil di css :

h1.title{

font-weight: strong;

font-size: 23px;

}

Operations

Sederhananya adalah perhitungan aritmetika yang biasa kita lakukan sehari-hari, disamping itu less juga menyertakan method yang memungkina kita utuk menciptakan warna gradasi, mencari warna tengah antara 2 warna, ataupun perhitungan lainnya.

Di less :

@margin: 10px;

div {

margin: @margin - 1px;

}

Hasil css :

div {

margin: 9px;

}

Membuat konstanta dan style

Mari kita kembali ke pembahasan tutorial, saya biasa membuat 1 file khusus untuk menyimpan konstanta, isinya bisa berupa warna, ukuran atau hal lainnya. Buat 1 buah file bernama less/const.less dan isi seperti berikut.
@color_blue_1 : rgb(0, 161, 255);
@color_white_1 : #FFFFFF;
@color_opponent : #f4f4f4;
@color_me: @color_white_1;
Warna yang terdaftar di const.less akan digunakan pada style.less, tujuan kenapa disimpan di konstanta adalah, agar warna-warna yang digunakan pada style konsisten, dan jika terjadi perubahan pada salah satu warna, maka tidak perlu report-repot untuk merubah warna pada style lain. Lanjutkan ke style.less dan tulis kode berikut :
@import "const";
html, body, navbar, header, footer{ margin: 0; }

.padding-item{ padding:10px; }

.fullwidth{ width:100%; }

.chat-title, .chat-block, .chat-editor{ .fullwidth; }

.chat-title { background: @color_blue_1; color: @color_white_1; padding:10px 0; .text{ .padding-item; }; }

.chat-block{ .chat-item{ .padding-item; };

.chat-item.me{ background: @color_me; };

.chat-item.opponent{ background: @color_opponent; }; }

.chat-editor{ position: absolute; bottom: 0; div { .padding-item; }; textarea{ .fullwidth }; }

Untuk bisa menggunakan konstanta yang tersedia pada const.less perlu dilakukan impor kedalam style.less menggunakan @import 'file tujuan'. Berikut adalah hasil yang bisa kita lihat di browser-sync dari kombinasi pug dan less.

 

Catatan : ketika sedang develop ternyata tidak ada perubahan di browser-sync jangan lupa untuk check di terminal unutk memastikan bahwa tidak ada kode yang error. Cukup sekian dulu yang bisa saya sampaikan untuk mengawali tutorial pug dan less  kali ini

Lampiran

Repositori :

Repositori ini berisi boilerplate dari tutorial yang telah saya buat https://github.com/idmore/gulp-pug-less-boilerplate .

Link referensi :

Pug : https://pugjs.org/

Less : http://lesscss.org

Node JS : https://nodejs.org/

NPM : https://www.npmjs.com

Gulp : http://gulpjs.com/