L
Vue.js • Literally Web ID

Arsitektur Micro-Frontend Skala Enterprise dengan Vue.js 3 dan Module Federation

⏱️ 18 menit baca • 📅 20 Oct 2026 • 👁️ 2 views
Arsitektur Micro-Frontend Skala Enterprise dengan Vue.js 3 dan Module Federation

Arsitektur Micro-Frontend Skala Enterprise dengan Vue.js 3 dan Module Federation

1. Konteks Industri & Analisis Akar Masalah

Di era modern, organisasi enterprise sering kali terjebak dalam perangkap arsitektur Monolithic Frontend. Sebuah aplikasi web tunggal yang dikembangkan menggunakan Vue.js atau React, seiring berjalannya waktu, akan membengkak hingga mencapai ratusan ribu baris kode. Monolit ini memicu berbagai masalah krusial di tingkat operasional maupun pengembangan:

  • Bottleneck Tim (Team Coupling): Puluhan atau ratusan engineer harus bekerja di atas repositori yang sama. Konflik merge request (git conflicts) menjadi makanan sehari-hari, dan siklus rilis (release cycle) melambat drastis.
  • Ketergantungan Rilis (Release Bottleneck): Jika tim pembayaran melakukan perubahan kecil, seluruh aplikasi monolitik harus di-build, diuji secara end-to-end (E2E), dan di-deploy ulang. Risiko regression bugs pada modul lain sangat tinggi.
  • Bloating & Degradasi Performa: Ukuran bundle size JavaScript membengkak melampaui batas wajar (> 5MB). Waktu muat awal (First Contentful Paint dan Time to Interactive) meroket, berdampak langsung pada metrik Core Web Vitals dan konversi bisnis.
  • Legacy Lock-in: Migrasi teknologi atau pembaruan framework menjadi mustahil dilakukan secara bertahap karena keterikatan antarmodul yang terlalu erat.

Sebelum vs Sesudah Penerapan Micro-Frontend

Metrik / Aspek Monolithic Frontend Micro-Frontend (Module Federation)
Ukuran Bundle Awal Sangat Besar (> 3 MB) Sangat Ringan (< 200 KB untuk Shell)
Waktu Build & CI/CD 15 - 45 Menit 2 - 5 Menit per Modul (Independen)
Frekuensi Rilis Mingguan / Bulanan Beberapa kali sehari per tim
Skalabilitas Tim Rendah (Konflik Git Tinggi) Tinggi (Tim otonom per repositori)
Isolasi Kegagalan Seluruh aplikasi down jika ada error fatal Hanya modul terkait yang gagal (graceful degradation)

2. Konsep Inti & Deep Dive Arsitektur

Webpack 5 memperkenalkan Module Federation, sebuah terobosan revolusioner yang memungkinkan aplikasi JavaScript (disebut Host atau Container) untuk memuat kode dari aplikasi lain (Remote) secara dinamis pada runtime di browser. Berbeda dengan teknik tradisional seperti iframe atau npm package dependencies, Module Federation memungkinkan berbagi modul (shared modules) secara langsung tanpa duplikasi aset.

Alur Eksekusi & Data Flow

+-------------------------------------------------------------+
|                   Browser / Client Layer                    |
+-------------------------------------------------------------+
                               ||
                               /
+-------------------------------------------------------------+
|               Host Application (Shell / Core)               |
|   - Mengatur Layout Global & Routing Utama                  |
|   - Menyediakan Shared Dependencies (Vue 3, Pinia, Vue Router)| 
+-------------------------------------------------------------+
        || (Dynamic Remote Import via Module Federation)
        /                                             \        
+-----------------------+                   +-----------------------+
| Remote App A (Cart)   |                   | Remote App B (Catalog)|
| - Vue 3 Components    |                   | - Vue 3 Components    | 
| - Local State         |                   | - Local State         |
+-----------------------+                   +-----------------------+

Pada arsitektur ini, Host bertindak sebagai App Shell yang memuat layout utama, autentikasi global, dan router. Remote adalah aplikasi Vue 3 terpisah yang dikembangkan oleh tim independen dan di-deploy ke URL penyimpanan mereka sendiri (misalnya S3/CDN). Ketika pengguna mengakses rute tertentu, Host secara asinkron mengambil file remoteEntry.js dari server Remote, lalu merender komponen Vue 3 tersebut di dalam container DOM lokal.


3. Perbandingan Komparatif / Analisis Pendekatan

Untuk memilih pendekatan arsitektur micro-frontend yang paling optimal di tingkat enterprise, mari bandingkan tiga metode utama yang sering dipertimbangkan:

Fitur / Parameter Webpack 5 Module Federation Iframe-based Micro-Apps Build-time Integration (NPM Packages)
Runtime Integration Ya (Dinamis di Browser) Ya (Isolasi Penuh) Tidak (Statis saat Build)
Shared Dependencies Ya (Singleton Vue, Pinia, dll) Tidak (Setiap iframe muat ulang library) Ya (Tetapi rentan konflik versi)
Komunikasi Antar-App Event Bus, Pinia, Custom Events window.postMessage React/Vue Props & Context
Overhead Performa Rendah (Shared chunk loading) Tinggi (Memory footprint besar) Sedang (Bundle monolitik tetap besar)
Complexitas Setup Sedang - Tinggi Rendah Rendah - Sedang
Konsistensi UI/UX Tinggi (Desain sistem bersama) Sulit dijaga Tinggi

[!IMPORTANT] Pemilihan Webpack 5 Module Federation adalah standar emas bagi ekosistem Vue.js 3 karena kemampuannya berbagi instance Vue (Singleton) yang mencegah masalah multiple Vue instances error pada memori browser.


4. Prasyarat Sistem & Persiapan Lingkungan

Sebelum menyelami kode implementasi, pastikan infrastruktur dan lingkungan pengembangan Anda memenuhi spesifikasi berikut:

  • Node.js: Versi 18.x LTS atau 20.x LTS.
  • Package Manager: Pnpm (disarankan untuk efisiensi monorepo atau manajemen peer dependencies) atau npm v9+.
  • Web Server / Storage: Nginx untuk reverse proxy atau AWS S3 + Cloudflare CDN untuk penyimpanan aset statis.
  • Struktur Proyek:
    • enterprise-host (Aplikasi Utama / Shell)
    • enterprise-remote-catalog (Modul Katalog Produk)
    • enterprise-remote-cart (Modul Keranjang Belanja)

5. Panduan Implementasi Langkah demi Langkah

Langkah 1: Konfigurasi Host Application (enterprise-host)

Buat file konfigurasi vue.config.js atau integrasikan dengan Vite menggunakan plugin module federation (pada contoh ini kita gunakan Webpack 5 via Vue CLI / @vue/cli-service atau Rspack/Webpack configuration langsung).

// /enterprise-host/vue.config.js
const { defineConfig } = require('@vue/cli-service');
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = defineConfig({
  publicPath: 'auto',
  transpileDependencies: true,
  configureWebpack: {
    optimization: {
      splitChunks: false,
    },
    plugins: [
      new ModuleFederationPlugin({
        name: 'host',
        filename: 'remoteEntry.js',
        remotes: {
          catalogApp: 'catalogApp@http://localhost:8081/remoteEntry.js',
          cartApp: 'cartApp@http://localhost:8082/remoteEntry.js',
        },
        shared: {
          vue: {
            singleton: true,
            requiredVersion: '^3.3.4',
            eager: true,
          },
          pinia: {
            singleton: true,
            requiredVersion: '^2.1.7',
            eager: true,
          },
        },
      }),
    ],
  },
  devServer: {
    port: 8080,
    cors: true,
  },
});

Buat komponen utama di Host untuk memuat remote component secara dinamis:

<!-- /enterprise-host/src/views/HomeView.vue -->
<template>
  <div class="host-container">
    <h1>Enterprise Dashboard Shell</h1>
    <div class="micro-frontend-wrapper">
      <Suspense>
        <template #default>
          <RemoteCatalogComponent />
        </template>
        <template #fallback>
          <div class="skeleton-loader">Memuat Katalog Produk...</div>
        </template>
      </Suspense>
    </div>
  </div>
</template>

<script setup>
import { defineAsyncComponent } from 'vue';

// Memuat remote component menggunakan defineAsyncComponent
const RemoteCatalogComponent = defineAsyncComponent(() =>
  import('catalogApp/CatalogWidget')
);
</script>

<style scoped>
.host-container {
  padding: 2rem;
  font-family: 'Inter', sans-serif;
}
.micro-frontend-wrapper {
  border: 2px dashed #42b883;
  padding: 1.5rem;
  margin-top: 1rem;
  border-radius: 8px;
}
.skeleton-loader {
  color: #666;
  font-style: italic;
}
</style>

Langkah 2: Konfigurasi Remote Application (enterprise-remote-catalog)

// /enterprise-remote-catalog/vue.config.js
const { defineConfig } = require('@vue/cli-service');
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = defineConfig({
  publicPath: 'http://localhost:8081/',
  transpileDependencies: true,
  configureWebpack: {
    optimization: {
      splitChunks: false,
    },
    plugins: [
      new ModuleFederationPlugin({
        name: 'catalogApp',
        filename: 'remoteEntry.js',
        exposes: {
          './CatalogWidget': './src/components/CatalogWidget.vue',
        },
        shared: {
          vue: {
            singleton: true,
            requiredVersion: '^3.3.4',
            eager: true,
          },
          pinia: {
            singleton: true,
            requiredVersion: '^2.1.7',
            eager: true,
          },
        },
      }),
    ],
  },
  devServer: {
    port: 8081,
    cors: true,
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
});

Buat komponen yang akan diekspos oleh Remote:

<!-- /enterprise-remote-catalog/src/components/CatalogWidget.vue -->
<template>
  <div class="catalog-widget">
    <h2>Katalog Produk (Micro-App A)</h2>
    <div class="product-grid">
      <div v-for="product in products" :key="product.id" class="product-card">
        <h3>{{ product.name }}</h3>
        <p>Rp {{ product.price.toLocaleString() }}</p>
        <button @click="addToCart(product)">Tambah ke Keranjang</button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useCartStore } from '@/store/cartStore'; // Atau menggunakan global event bus

const cartStore = useCartStore();

const products = ref([
  id: 1, name: 'Enterprise Cloud Server vCPU 8', price: 1500000 },
  id: 2, name: 'Managed Kubernetes Cluster', price: 4500000 },
]);

const addToCart = (product) => {
  cartStore.addItem(product);
  alert(`${product.name} berhasil ditambahkan!`);
};
</script>

<style scoped>
.catalog-widget {
  background: #f8f9fa;
  padding: 1rem;
  border-radius: 6px;
}
.product-grid {
  display: flex;
  gap: 1rem;
}
.product-card {
  background: white;
  padding: 1rem;
  border: 1px solid #dee2e6;
  border-radius: 4px;
}
</style>

6. Bedah Kode & Penjelasan Detail Baris Kunci

  1. publicPath: 'auto' (Host & Remote): Sangat krusial untuk memastikan bahwa Webpack secara dinamis menentukan jalur absolut URL aset (chunks) berdasarkan asal domain tempat remoteEntry.js dimuat. Tanpa ini, aset gambar atau async chunk dari remote akan gagal dimuat (404 Not Found).
  2. shared: { vue: { singleton: true, eager: true } }: Pengaturan ini memaksa Host dan seluruh Remote menggunakan instance Vue yang persis sama di memori browser. singleton: true mencegah bentrokan hook siklus hidup (lifecycle hooks), sedangkan eager: true memastikan dependensi inti tidak dimuat dua kali secara terpisah.
  3. Suspense & defineAsyncComponent: Karena remote dimuat secara asinkron lewat jaringan (network request), Vue 3 mewajibkan penggunaan tag <Suspense> untuk menangani status pending dan fallback UI dengan elegan.

7. Skenario Produksi & Studi Kasus Dunia Nyata

Pada lingkungan enterprise dengan jutaan active users (misalnya platform e-commerce skala regional), arsitektur ini diterapkan bersama infrastruktur Nginx dan Cloudflare CDN:

# /etc/nginx/conf.d/enterprise-host.conf
server {
    listen 443 ssl http2;
    server_name app.enterprise.com;

    ssl_certificate /etc/letsencrypt/live/app.enterprise.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/app.enterprise.com/privkey.pem;

    root /var/www/enterprise-host/dist;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
        add_header Cache-Control "no-cache, no-store, must-revalidate";
    }

    # Konfigurasi khusus untuk Remote entry agar caching optimal namun tetap fresh
    location ~* \.js$ {
        expires 1h;
        add_header Cache-Control "public, no-transform";
        add_header Access-Control-Allow-Origin "*";
    }
}

[!TIP] Gunakan Cloudflare Page Rules atau Edge Workers untuk melakukan cache purging otomatis pada file remoteEntry.js setiap kali pipeline CI/CD menyelesaikan deployment versi baru dari micro-app remote.


8. Common Pitfalls, Anti-Patterns & Solusi

  • Anti-Pattern 1: Berbagi State Global Secara Brutal (Tight Coupling): Masalah: Menggunakan satu store Pinia tunggal yang dikelola bersama oleh semua micro-app. Solusi: Terapkan Isolated Local State pada masing-masing micro-app, dan gunakan Custom Event Bus (window.CustomEvent) atau Context Injection terstandarisasi hanya untuk komunikasi antar-app yang esensial (misalnya jumlah keranjang belanja).
  • Anti-Pattern 2: Perbedaan Versi Dependencies (Version Mismatch): Masalah: Remote A menggunakan Vue 3.3.4 sedangkan Remote B menggunakan 3.4.0 dengan konfigurasi non-singleton. Solusi: Selalu definisikan versi shared secara ketat di dalam file vue.config.js dan gunakan alat seperti Pnpm Workspaces untuk menyeragamkan versi dependensi lintas repositori.
  • Pitfall 3: CORS Policy Blocking pada Remote Entry: Masalah: Browser menolak memuat remoteEntry.js karena perbedaan domain/port. Solusi: Pastikan server Nginx atau Webpack Dev Server pada aplikasi remote menyertakan header HTTP Access-Control-Allow-Origin: *.

9. Benchmark, Metrik Kinerja & Tuning Performa

Untuk menguji ketahanan dan performa arsitektur Micro-Frontend di produksi, jalankan pengujian beban menggunakan perangkat seperti k6 atau pengujian Lighthouse CI pada pipeline deployment:

// load-test-k6.js
import http from 'k6/http';
import { check, sleep } from 'fs';

export const options = {
  stages: [
    { duration: '1m', target: 500 }, // Ramp-up ke 500 pengguna
    { duration: '3m', target: 2000 }, // Pertahankan beban 2000 concurrent users
    { duration: '1m', target: 0 },   // Ramp-down
  ],
};

export default function () {
  const res = http.get('https://app.enterprise.com/');
  check(res, {
    'status is 200': (r) => r.status === 200,
    'load time < 500ms': (r) => r.timings.duration < 500,
  });
  sleep(1);
}

Hasil Optimasi Tuning:

  • Dengan memecah monolit menjadi 5 micro-app, ukuran Initial JavaScript Payload pada Host turun dari 3.2 MB menjadi 140 KB.
  • Metrik Largest Contentful Paint (LCP) meningkat drastis dari 3.8 detik menjadi 0.9 detik di jaringan seluler 4G.

10. Checklist Penerapan Produksi & Kesimpulan

Sebelum meluncurkan arsitektur Micro-Frontend Vue 3 Anda ke lingkungan Production, pastikan checklist berikut terpenuhi:

  • Konfigurasi singleton: true pada seluruh shared libraries (Vue, Pinia, Vue Router).
  • Header CORS (Access-Control-Allow-Origin) aktif pada semua server penyimpanan remote micro-apps.
  • Mekanisme Error Boundary atau Vue onErrorCaptured terpasang di Host untuk mencegah kegagalan satu remote app merusak seluruh halaman.
  • Pipeline CI/CD independen untuk setiap repositori micro-app telah diuji dengan pengujian smoke test otomatis.
  • Strategi Cache Busting pada remoteEntry.js dikonfigurasi dengan benar di Cloudflare/CDN.

Arsitektur Micro-Frontend berbasis Vue.js 3 dan Module Federation memberikan solusi elegan bagi organisasi enterprise yang ingin melepaskan diri dari belenggu monolit. Dengan otonomi tim yang tinggi, ukuran bundle yang optimal, dan performa runtime yang superior, enterprise Anda siap menghadapi skala bisnis digital masa depan.

🏷️ Tags: #Webpack #Micro-Frontend #Module Federation #Vue.js #Enterprise Architecture