Membuat Module Bundler Sendiri ala Front-end Engineer LINE

Halo semuanya!

Kali ini kita akan bahas materi seputar web development. Tulisan kali ini adalah salah satu oleh-oleh yang penulis pelajari saat mengikuti LINE Developer Day 2019 di Tokyo bulan November kemarin. Jika Anda baru memperlajari Javascript, mungkin pembahasannya akan agak sedikit lebih berat, jadi siapin kopi dulu yuk. Tulisan ini juga pas untuk kalian yang sudah mengikuti kelas Progressive Web Apps. Semoga kalian bisa mengikuti hingga akhir ya.

Apa itu module?

Hal pertama yang perlu kita pahami yaitu module. Makanan jenis apakah ini?

💻 Mulai Belajar Pemrograman

Belajar pemrograman di Dicoding Academy dan mulai perjalanan Anda sebagai developer profesional.

Daftar Sekarang

Sayangnya, ini bukanlah jenis makanan. Sederhananya, module adalah sebuah berkas yang berisi script kode. Module memiliki sifat khusus, yakni dapat memuat atau dimuat oleh module lainnya. Berkat sifat inilah antar module dapat saling ekspor dan impor untuk bertukar fungsi.

Sebagai contoh, berikut ini adalah module sayHi.js [rujukan]


… kemudian di sisi lain, module lainnya mengimpor module tersebut:

The Bad Part!

Satu dua atau tiga module yang kita gunakan mungkin tidak akan bermasalah. Namun coba bayangkan website-website besar saat ini, pasti punya banyak sekali module! Dengan banyaknya module yang digunakan, sangat mungkin bahwa di antara module-module tersebut memiliki kesamaan nama fungsi.

Tidak jarang juga ditemukan module script yang bergantung pada script lainnya. Misalnya, saat menggunakan bootstrap sebagai basis template. Akan terdapat script ‘bootstrap.js’ yang tak dapat berfungsi jika sebelumnya script ‘jquery.js.’ tidak dipasang.

Berikutnya adalah hal kecil yang mungkin sering terlewatkan. Salah urutan penempatan script saja, dapat membuat fungsi-fungsi yang telah dibuat, tidak berjalan sesuai rencana.

Module Bundler

Selamat, semua hal tadi kini sudah ada solusinya. Menggunakan module bundler kita tidak perlu lagi memikirkan masalah di atas. Module bundler secara otomatis akan mengumpulkan semua module-module yang digunakan, mengurutkannya dengan benar dan membungkusnya menjadi satu berkas module saja.

Salah satu tools module bundler yang sering digunakan adalah Webpack. Sebagaimana yang disebutkan dalam core concepts mereka, Webpack akan membangun sebuah dependency graph saat dijalankan. Dependency graph ini berisi pemetaan setiap module yang dibutuhkan dalam proyek dan mengeluarkan sebuah bundle module statis.

Webpack Module Bundler

Core Concept

Untuk lebih memahami bagaimana module bundler bekerja, perlu kita pelajari dahulu bagaimana konsep dasarnya. Menurut Webpack, ada beberapa bagian dasar dari sebuah module bundler, yaitu Entry, Output, Loaders, Plugins, Mode dan Browser Compatibility [rujukan]. Namun, pada kesempatan ini kita hanya perlu menggunakan dua (2) bagian saja, yakni Entry dan Output.

Entry

Sebuah entry point adalah titik permulaan yang digunakan oleh module bundler sebagai acuan script mana yang perlu dibaca pertama kali dan digunakan untuk permulaan pembuatan dependency graph. Contohnya:

Output

Properti output memberitahukan di mana module bundler harus menyimpan hasil bundler yang telah dikumpulkan dan menentukan nama bundle-nya.

Yuk Praktek!

Pertama, jika Anda belum memasang NodeJS silakan pasang terlebih dahulu sesuai dengan sistem operasi yang Anda gunakan. Berkas instalasi NodeJS bisa diunduh pada tautan berikut ini.

Selanjutnya, silakan lakukan clone atau unduh contoh proyek module bundler sederhana yang telah dibuat oleh mas Sing-Ming Chen – LINE Front-end Engineer dari repository berikut ini: https://github.com/Asing1001/module-bundler

Setelah mengkloning repository di atas, jangan lupa juga untuk mengunduh semua kebutuhan module yang diperlukan selama pengembangan dengan menjalankan perintah “npm install”.

Pada berkas index.html dapat kita temukan bahwa ia memuat 3 buah module javascript yang ada di direktori src/. Module-module inilah yang akan di-bundling menjadi satu berkas.


Sebagai latihan, kita akan menggunakan webpack terlebih dahulu. Pertama, isikan berkas konfigurasinya seperti ini:


Selanjutnya, jalankan perintah “npm run webpack untuk menjalankan proses bundling.

Run bundling webpack

Setelah selesai, sesuai konfigurasi yang kita buat, hasil bundle dapat kita temukan di ‘dist/bundle.js’. Sampai pada tahap ini, kita sudah bisa mengganti module-module yang digunakan di berkas index.html menggunakan berkas hasil bundling tadi.

Sebelum


Sesudah

Membuat Module Bundler Sendiri

Sampailah kita ke bagian inti tulisan ini, yaitu membuat module bundler sendiri.

Standarisasi Module

Pertama, kita perlu membuat ulang setiap module yang telah dibaca. Struktur standar sebuah module terdiri dari beberapa properti, yaitu: id modul, lokasi berkas, script kode, dependensi, peta dependensi. Perhatikan contoh module berikut:


Karena banyaknya module yang digunakan, proses ini tidak mungkin kita lakukan secara manual. Untuk itu, pada berkas bundler.js, isikan kode berikut:

Mengisi Code

Sampai pada tahap ini kita sudah mengisikan ID dan filePath pada module baru yang dibuat. Selanjutnya untuk bagian code isikan content file yang telah dibaca. Namun, karena content tersebut masih berformat Javascript ES6, kita perlu seragamkan menjadi format CommonJS.

ES6 Module


CommonJS Module


Untuk mengubah format Javascript ES6 ke CommonJS, kita dapat menggunakan tools babel transformSync seperti berikut ini:


Sehingga, hasil akhirnya menjadi:

Mengumpulkan Dependencies

Untuk mengumpulkan semua dependency apa saja yang digunakan oleh sebuah module, kita dapat memanfaatkan fitur Abstract Syntax Tree atau AST. Sebagai gambaran seperti apa itu AST, silakan lihat di website astexplorer.net melalui url berikut: https://bit.ly/2sc1PBI

abstract syntax tree explorer

Dapat kita lihat di gambar bahwa AST membaca kode yang diberikan, kemudian mendapati bahwa kode tersebut memiliki dependency ke module “./message”.
Untuk mendapatkan informasi AST di script module bundler, kita dapat memanfaatkan fungsi babel parseSync. Kemudian kita juga bisa memanfaatkan babel traverse untuk mendapatkan nama module dependency-nya.

Hasilnya menjadi seperti berikut:

Menyelesaikan Module

Pada tahap ini kita sudah dapat membuat ulang sebuah module dengan struktur standar module yang sudah ditentukan sebelumnya. Namun karena dalam sebuah module bisa saja terdapat dependency ke module lainnya, kita perlu membuat ulang juga dependency module tersebut agar sesuai struktur standar.

Untuk itu, kita harus ulangi cara sebelumnya pada setiap dependency module yang ada. Jangan lupa perbaiki alamat berkas dependency module dahulu agar sesuai dengan alamat sebenarnya ya. Proses pembuatan ulang module pun dapat berjalan seperti sebelumnya.

Hasilnya sebagai berikut:

Packaging

Sampai pada tahap ini kita hanya perlu membungkus hasil module-module yang telah kita buat ulang menjadi satu berkas bundle. Untuk itu, pertama ubah dahulu module-module tersebut menjadi javascript object.

Setelah diubah menjadi javascript object, kumpulan module ini tinggal memiliki dua (2) buah properti saja. Properti pertama yaitu factory yang berfungsi sebagai pembungkus module. Properti factory sejatinya dalah sebuah function di mana di dalamnya terdapat kode utama module. Selain itu juga pada parameternya perlu ditambahkan callback function berupa require untuk mengimpor dependency module dan exports untuk keperluan mengekspor module. Hal ini sesuai dengan prinsip module wrapper yang digunakan pada NodeJS [rujukan].

module wrapper

Properti kedua yaitu dependencyMap. Properti ini akan berguna pada tahap selanjutnya, yaitu saat memperbaiki fungsi require().
Hasil modifikasi kodenya menjadi seperti berikut ini:

Memperbaiki “require”

Seperti yang telah kita bahas sebelumnya, cara menambahkan dependency pada format CommonJS yaitu menggunakan perintah require(). Perintah ini tidak dapat berjalan normal pada bundle module karena alamat file yang tertulis didalamnya tidak lagi sesuai.

Kita perlu mengarahkan alamat ini agar sesuai dengan alamat pemetaan dependency (dependency map) yang telah dibuat sebelumnya. Jalan termudah untuk melakukannya ialah dengan dengan cara menimpa (override) fungsi standar require().

Fungsi require() pada dasarnya hanya menerima satu parameter, yaitu alamat berkas dependency module berada. Karena alamat berkas ini sudah tidak sesuai, maka alamat tersebut bisa kita ubah berdasarkan dependency map.

Hasilnya seperti ini:

Menyimpan bundle

Langkah terakhir adalah menyimpan hasil bundle menjadi sebuah file. Caranya adalah sebagai berikut:

Menjalankan Module Bundler

Untuk menjalankan module bundler yang telah kita buat, silakan gunakan perintah: npm start.

npm start module bundler

Setelah proses bundling, Anda dapat menggunakannya sebagai dependency script pada index.html seperti saat Anda menggunakan Webpack module bundler.

Penutup

Untuk Anda yang masih bingung cara pembuatannya, silakan lihat langkah demi langkah solusinya pada direktori “solutions”.

Masih penasaran dengan materi lainnya dari LINE Developer Day 2019? Berikut ini tautannya ya:

  1. Evolusi LINE Things dan Produk yang Dirilis
  2. Belajar Membuat gRPC Microservice dengan LINE Armeria dan Spring WebFlux

Referensi

Ronen Amiel
Minipack
Build Your Own Webpack

Luciano Mammino
Unbundling the JavaScript module bundler

Adam Kelly
Let’s learn how module bundlers work and then write one ourselves


Belajar Pemrograman Gratis
Belajar pemrograman di Dicoding Academy dan mulai perjalanan Anda sebagai developer profesional.