Di proyek JavaScript skala menengah hingga besar, modularisasi kode adalah kunci untuk maintainability, reusability, dan performance.
Bab ini membahas advanced module patterns, perbedaan CommonJS vs ES Modules, serta teknik dynamic import, tree shaking, code splitting, dan best practices.
Contents
1. ES Modules (ESM) vs CommonJS (CJS)
JavaScript memiliki dua sistem modul populer:
a. ES Modules (ESM)
- Sintaks modern (ES6+)
- Mendukung
importdanexport - Statis: analisis dependensi bisa dilakukan sebelum runtime
// math.js
export function add(a, b) {
return a + b;
}
export const PI = 3.14;
// main.js
import { add, PI } from './math.js';
console.log(add(2, 3)); // 5
console.log(PI); // 3.14
b. CommonJS (CJS)
- Digunakan di Node.js sebelum ESM
- Menggunakan
require()danmodule.exports - Dinamis: modul dievaluasi saat runtime
// math.cjs
function add(a, b) { return a + b; }
module.exports = { add };
// main.cjs
const { add } = require('./math.cjs');
console.log(add(2, 3)); // 5
Perbedaan utama:
| Feature | ESM | CJS |
|---|---|---|
| Syntax | import/export | require/module.exports |
| Evaluasi | Static | Dynamic |
| Browser support | Native di modern browser | Tidak native, butuh bundler |
| Hoisting | Terbatas | Bisa require kapan saja |
2. Dynamic import()
Dynamic import memungkinkan memuat modul secara on-demand, bukan saat aplikasi mulai. Cocok untuk lazy loading dan code splitting.
// Dynamic import
async function loadMathModule() {
const math = await import('./math.js');
console.log(math.add(5, 7)); // 12
}
loadMathModule();
Manfaat:
- Mengurangi ukuran bundle awal
- Mempercepat load page
- Memungkinkan modul hanya dimuat saat dibutuhkan
3. Tree Shaking & Bundling
Tree Shaking
Tree shaking adalah teknik menghapus kode yang tidak digunakan dari bundle akhir, biasanya digunakan dengan bundler seperti Webpack atau Rollup.
// utils.js
export function used() { console.log('used'); }
export function unused() { console.log('unused'); }
// main.js
import { used } from './utils.js';
used(); // hanya fungsi used yang dimasukkan ke bundle akhir
Bundling
Bundler (Webpack, Rollup, Vite) menggabungkan banyak modul menjadi satu file (atau beberapa file) agar efisien di browser.
4. Code Splitting
Code splitting adalah teknik membagi aplikasi menjadi beberapa bundle agar hanya modul yang diperlukan yang di-load.
// Webpack example
// main.js
button.addEventListener('click', () => {
import('./moduleA.js').then(module => {
module.doSomething();
});
});
Manfaat:
- Mempercepat load aplikasi
- Mengurangi waktu parsing JavaScript
- Membuat aplikasi skalabel
5. Module Patterns & Best Practices
a. Module Patterns
- Revealing Module Pattern: mengembalikan objek dengan API publik, private tetap tersembunyi
const Counter = (() => {
let count = 0; // private
function increment() { count++; }
function getCount() { return count; }
return { increment, getCount };
})();
Counter.increment();
console.log(Counter.getCount()); // 1
- Singleton Module: memastikan hanya ada satu instance modul
const Database = (() => {
let instance;
function createInstance() {
return { connection: 'Connected' };
}
return {
getInstance() {
if (!instance) instance = createInstance();
return instance;
}
};
})();
const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2); // true
b. Best Practices
- Gunakan ES Modules untuk project modern
- Pisahkan modul berdasarkan fitur, bukan jenis file
- Hindari circular dependency
- Gunakan dynamic import untuk modul besar atau jarang digunakan
- Terapkan tree shaking friendly: hindari side-effect di modul
Kesimpulan
Menguasai modules & dependency management adalah kunci untuk membangun aplikasi JavaScript modern yang scalable, maintainable, dan performant.
- ES Modules vs CommonJS → pilih sesuai environment
- Dynamic import() → lazy loading modul
- Tree shaking & bundling → mengurangi ukuran bundle
- Code splitting → load modul sesuai kebutuhan
- Module patterns & best practices → meningkatkan modularity dan keamanan kode
Bab berikutnya akan membahas Advanced Asynchronous Patterns, termasuk generator, async iterator, dan reactive programming, yang sangat relevan untuk modular dan event-driven architecture.