PUG dan LESS untuk Mempercepat Development Halaman Web
yussan 5 Januari 2017
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$gulpJika 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, 1 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 diatasMembuat 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 :htmlhead
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 block, block 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/defaultblock 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/defaultblock 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.bigTapi hal tersebut tidak berlaku untuk tag lain, sebagai contoh navbar memiliki kelas 'big', maka penulisannya menjadi :
navbar.bigHal tersebut berlaku untuk semua tag kecuali div. Untuk penulisan atribut lain, seperti inline style, data-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 Pug, const 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/