MICRO-FRONTENDS WEBPACK MODULE-FEDERATION FRONTEND ARCHITECTURE JAVASCRIPT WEB-DEVELOPMENT SCALABILITY CODE-SHARING DEPLOYMENT MONOREPO BUILD-TOOLS

Membangun Micro-Frontends yang Fleksibel dengan Webpack Module Federation

⏱️ 10 menit baca
👨‍💻

Membangun Micro-Frontends yang Fleksibel dengan Webpack Module Federation

1. Pendahuluan

Pernahkah Anda bekerja di proyek frontend yang semakin besar, di mana setiap penambahan fitur terasa seperti menambah berat pada beban yang sudah masif? Aplikasi monolitik frontend, meskipun mudah di awal, seringkali berakhir menjadi monster yang sulit di-maintain, di-deploy, dan di-skalakan. Di sinilah konsep Micro-Frontends hadir sebagai solusi, memecah aplikasi frontend raksasa menjadi bagian-bagian yang lebih kecil, independen, dan dikelola oleh tim yang berbeda.

Namun, implementasi Micro-Frontends sendiri bukannya tanpa tantangan. Bagaimana cara memuat bagian-bagian aplikasi yang berbeda ini secara dinamis? Bagaimana memastikan komponen dan dependensi yang sama tidak di-load berulang kali, menyebabkan bundle size membengkak? Dan yang terpenting, bagaimana menjaga konsistensi dan performa aplikasi secara keseluruhan?

Di sinaran tantangan ini, Webpack Module Federation muncul sebagai game-changer. Diperkenalkan di Webpack 5, fitur ini memungkinkan aplikasi JavaScript untuk secara dinamis memuat kode dari aplikasi lain pada runtime, menciptakan “ekosistem” di mana aplikasi dapat berbagi modul (komponen, fungsi, library) secara efisien. Ini bukan sekadar memuat komponen, tetapi benar-benar federasi modul, seolah-olah mereka adalah bagian dari satu kesatuan monolitik, namun tetap mempertahankan kemandiriannya.

Artikel ini akan membawa Anda menyelami Webpack Module Federation: apa itu, bagaimana cara kerjanya, dan bagaimana Anda bisa menggunakannya untuk membangun arsitektur Micro-Frontends yang fleksibel, skalabel, dan mudah dikelola. Siap untuk melepaskan diri dari belenggu monolit frontend? Mari kita mulai!

2. Apa Itu Webpack Module Federation? Analogi Pusat Perbelanjaan

📌 Konsep Inti: Bayangkan sebuah pusat perbelanjaan (aplikasi utama Anda) yang memiliki banyak toko (micro-frontend atau fitur independen). Setiap toko memiliki produknya sendiri (komponen, logika bisnis), dan pusat perbelanjaan ingin menampilkannya kepada pengunjung.

Sebelum Module Federation, jika toko baru ingin berjualan, pusat perbelanjaan harus “membangun ulang” seluruh mall agar toko baru itu bisa masuk. Ini tidak efisien dan memakan waktu. Belum lagi, jika ada produk umum seperti “kasir” atau “toilet” yang sama-sama dibutuhkan banyak toko, setiap toko harus membangun kasirnya sendiri! Duplikasi, kan?

💡 Dengan Module Federation: Module Federation mengubah cara kerja ini. Sekarang, pusat perbelanjaan (yang kita sebut Host) bisa secara dinamis “mengundang” toko-toko lain (yang kita sebut Remote) untuk bergabung. Toko-toko ini bisa di-deploy secara independen. Lebih keren lagi, jika ada “kasir” yang dibutuhkan banyak toko, kasir itu bisa disediakan oleh satu toko dan dibagikan (shared) kepada toko lain yang membutuhkannya. Pusat perbelanjaan tidak perlu tahu detail implementasi kasir itu, cukup tahu bahwa ada “layanan kasir” yang bisa dipakai.

Secara teknis, Webpack Module Federation memungkinkan:

Ini semua terjadi pada runtime, bukan pada waktu build. Artinya, Anda bisa mendeploy setiap micro-frontend secara independen, dan aplikasi host akan memuatnya sesuai kebutuhan tanpa perlu di-rebuild. Sangat fleksibel!

3. Memahami Komponen Utama: Host, Remote, dan Shared Modules

Untuk mengimplementasikan Module Federation, kita perlu memahami tiga peran kunci ini dalam konteks konfigurasi Webpack:

Host Application (Konsumen)

Ini adalah aplikasi “induk” yang akan memuat dan merender modul-modul dari aplikasi lain. Dalam skenario Micro-Frontends, ini bisa menjadi shell aplikasi utama atau dashboard yang mengintegrasikan berbagai fitur.

Remote Application (Penyedia)

Ini adalah aplikasi “anak” yang mengekspos modul-modulnya agar bisa digunakan oleh aplikasi lain. Setiap fitur atau bagian aplikasi yang independen dapat bertindak sebagai Remote.

Shared Modules

Ini adalah bagian terpenting untuk optimasi performa dan konsistensi. Modul bersama adalah dependensi (misalnya, React, Vue, Material-UI) atau kode kustom (misalnya, komponen Design System, utilitas) yang ingin Anda pastikan hanya di-load sekali dan dibagi pakai antar Host dan Remote. Ini mencegah duplikasi bundle dan memastikan semua bagian aplikasi menggunakan versi dependensi yang sama.

🎯 Contoh Konfigurasi Webpack (Dasar):

Misalkan kita punya dua aplikasi: app1 (Host) dan app2 (Remote).

app2 (Remote) - webpack.config.js:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');

module.exports = {
  mode: 'development',
  devServer: {
    port: 8081, // Port untuk Remote
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'app2', // Nama unik aplikasi ini
      filename: 'remoteEntry.js', // Nama file manifest yang akan di-load Host
      exposes: {
        './Button': './src/Button.jsx', // Modul yang diekspos
        './Header': './src/Header.jsx',
      },
      shared: {
        react: { singleton: true, eager: true }, // Membagikan React
        'react-dom': { singleton: true, eager: true },
      },
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
  // ... loader dan konfigurasi lainnya
};

app1 (Host) - webpack.config.js:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');

module.exports = {
  mode: 'development',
  devServer: {
    port: 8080, // Port untuk Host
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'app1', // Nama unik aplikasi ini
      remotes: {
        app2: 'app2@http://localhost:8081/remoteEntry.js', // Mengimpor dari app2
      },
      shared: {
        react: { singleton: true, eager: true }, // Membagikan React
        'react-dom': { singleton: true, eager: true },
      },
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
  // ... loader dan konfigurasi lainnya
};

Dengan konfigurasi ini, app1 dapat mengimpor Button atau Header dari app2 seolah-olah itu adalah modul lokal:

// app1/src/App.jsx
import React from 'react';
// Import Button dari app2 (nama remote yang didefinisikan di webpack.config.js)
const RemoteButton = React.lazy(() => import('app2/Button'));
const RemoteHeader = React.lazy(() => import('app2/Header'));

function App() {
  return (
    <div>
      <h1>Aplikasi Host</h1>
      <React.Suspense fallback="Loading Button...">
        <RemoteButton />
      </React.Suspense>
      <React.Suspense fallback="Loading Header...">
        <RemoteHeader />
      </React.Suspense>
    </div>
  );
}

export default App;

⚠️ Penting: Gunakan React.lazy dan React.Suspense saat memuat modul dari Remote, karena modul-modul ini dimuat secara asynchronous pada runtime.

4. Strategi Berbagi Dependensi (Shared Modules)

Fitur shared adalah jantung dari efisiensi Module Federation. Tanpa ini, setiap Remote akan mem-bundle dependensinya sendiri, menghilangkan sebagian besar manfaat Micro-Frontends.

shared: {
  react: {
    singleton: true, // Hanya satu instance React yang akan di-load
    eager: true,     // Load React segera (tidak lazy)
    requiredVersion: '^18.0.0', // Versi minimum yang dibutuhkan
  },
  'react-dom': { singleton: true, eager: true, requiredVersion: '^18.0.0' },
  // ... dependensi lain
}

Mari kita bedah opsi-opsi penting dalam shared:

Best Practice: Selalu bagikan dependensi inti seperti React, ReactDOM, router, dan state management library dengan singleton: true dan eager: true. Ini akan secara drastis mengurangi ukuran bundle dan memastikan konsistensi lingkungan runtime.

5. Manfaat dan Use Cases Module Federation

Module Federation bukan hanya tentang memecah monolit, tetapi juga tentang menciptakan ekosistem pengembangan yang lebih efisien.

Manfaat Utama:

  1. Deployment Independen: Setiap Micro-Frontend dapat di-deploy secara terpisah. Ini mempercepat siklus rilis dan mengurangi risiko.
  2. Skalabilitas Tim: Tim yang berbeda dapat bekerja pada Micro-Frontends yang berbeda tanpa saling mengganggu.
  3. Berbagi Kode Efisien: Menghindari duplikasi dependensi dan komponen inti, menghemat ukuran bundle dan waktu loading.
  4. Fleksibilitas Teknologi: Meskipun Webpack-specific, Module Federation tidak membatasi Anda pada satu framework JavaScript. Anda bisa memiliki Micro-Frontends yang dibangun dengan React, Vue, atau Angular, asalkan mereka bisa di-bundle oleh Webpack dan mengekspos modul yang kompatibel.
  5. Hot-Reloading antar Aplikasi: Dalam pengembangan, perubahan pada Remote bisa langsung terlihat di Host tanpa perlu me-refresh seluruh aplikasi.

Use Cases Nyata:

6. Tantangan dan Best Practices

Meskipun Module Federation menawarkan banyak keuntungan, ada beberapa tantangan yang perlu Anda pertimbangkan.

Tantangan:

Best Practices:

  1. Definisikan Kontrak API yang Jelas: Pastikan modul yang diekspos oleh Remote memiliki “kontrak” yang jelas (props, event, dll.) untuk dihindari breaking changes.
  2. Gunakan singleton: true dan eager: true untuk Dependensi Kritis: Ini adalah kunci untuk performa dan konsistensi.
  3. Terapkan Strategi Versioning yang Solid: Gunakan semantic versioning untuk modul yang diekspos dan dependensi bersama. Pertimbangkan strictVersion: true untuk lingkungan produksi.
  4. Isolasi Gaya (CSS): Gunakan CSS-in-JS, CSS Modules, atau scoped CSS untuk mencegah konflik gaya antar Micro-Frontends.
  5. Observability: Implementasikan logging, monitoring, dan distributed tracing yang baik untuk memecahkan masalah di lingkungan terdistribusi.
  6. Gunakan Lazy Loading: Selalu gunakan React.lazy (atau padanannya di framework lain) untuk memuat Remote agar aplikasi utama tetap ringan.
  7. Sediakan Fallback: Selalu siapkan UI fallback (misalnya, dengan React.Suspense) jika Remote gagal dimuat.
  8. Pikirkan Komunikasi Antar Micro-Frontends: Untuk komunikasi yang kompleks, pertimbangkan menggunakan Event Bus, custom events, atau state management terpusat (jika memungkinkan dan tidak melanggar kemandirian).

Kesimpulan

Webpack Module Federation adalah alat yang sangat powerful untuk membangun arsitektur Micro-Frontends yang modern dan skalabel. Dengan kemampuannya untuk berbagi kode secara dinamis dan memungkinkan deployment independen, ia memecahkan banyak masalah yang secara historis menghantui pengembangan aplikasi frontend yang besar dan kompleks.

Meskipun ada tantangan, dengan pemahaman yang tepat tentang konsep Host, Remote, Shared Modules, serta penerapan best practices, Anda dapat membangun aplikasi web yang lebih modular, lebih mudah dikelola oleh tim yang berbeda, dan lebih cepat untuk di-deliver. Ini adalah langkah besar menuju masa depan pengembangan web yang lebih efisien dan fleksibel. Jadi, apakah Anda siap untuk mengadopsi kekuatan federasi modul ini dalam proyek Anda berikutnya?

🔗 Baca Juga