Jelajahi arsitektur micro-frontend tingkat lanjut menggunakan JavaScript Module Federation dengan Webpack 5. Pelajari cara membangun aplikasi yang dapat diskalakan, mudah dipelihara, dan independen.
JavaScript Module Federation dengan Webpack 5: Arsitektur Micro-Frontend Tingkat Lanjut
Dalam lanskap pengembangan web yang berkembang pesat saat ini, membangun aplikasi yang besar dan kompleks bisa menjadi tantangan yang signifikan. Arsitektur monolitik tradisional sering kali menghasilkan basis kode yang sulit dipelihara, diskalakan, dan diterapkan. Micro-frontend menawarkan alternatif yang menarik dengan memecah aplikasi besar ini menjadi unit-unit yang lebih kecil dan dapat diterapkan secara independen. JavaScript Module Federation, sebuah fitur canggih yang diperkenalkan di Webpack 5, menyediakan cara yang elegan dan efisien untuk mengimplementasikan arsitektur micro-frontend.
Apa itu Micro-Frontend?
Micro-frontend merupakan pendekatan arsitektur di mana satu aplikasi web terdiri dari beberapa aplikasi yang lebih kecil dan independen. Setiap micro-frontend dapat dikembangkan, diterapkan, dan dipelihara oleh tim yang terpisah, memungkinkan otonomi yang lebih besar dan siklus iterasi yang lebih cepat. Pendekatan ini mencerminkan prinsip-prinsip microservices di dunia backend, membawa manfaat serupa ke front-end.
Karakteristik utama micro-frontend:
- Dapat Diterapkan Secara Independen: Setiap micro-frontend dapat diterapkan secara independen tanpa memengaruhi bagian lain dari aplikasi.
- Keberagaman Teknologi: Tim yang berbeda dapat memilih teknologi dan kerangka kerja yang paling sesuai dengan kebutuhan mereka, mendorong inovasi dan memungkinkan penggunaan keahlian khusus.
- Tim Otonom: Setiap micro-frontend dimiliki oleh tim yang berdedikasi, mempromosikan kepemilikan dan akuntabilitas.
- Isolasi: Micro-frontend harus diisolasi satu sama lain untuk meminimalkan ketergantungan dan mencegah kegagalan beruntun.
Memperkenalkan JavaScript Module Federation
Module Federation adalah fitur Webpack 5 yang memungkinkan aplikasi JavaScript untuk secara dinamis berbagi kode dan dependensi saat runtime. Ini memungkinkan aplikasi yang berbeda (atau micro-frontend) untuk mengekspos dan mengonsumsi modul satu sama lain, menciptakan pengalaman integrasi yang mulus bagi pengguna.
Konsep kunci dalam Module Federation:
- Host: Aplikasi host adalah aplikasi utama yang mengatur micro-frontend. Aplikasi ini mengonsumsi modul yang diekspos oleh aplikasi remote.
- Remote: Aplikasi remote adalah micro-frontend yang mengekspos modul untuk dikonsumsi oleh aplikasi lain (termasuk host).
- Modul Bersama (Shared Modules): Modul yang digunakan oleh aplikasi host dan remote. Webpack dapat mengoptimalkan modul bersama ini untuk mencegah duplikasi dan mengurangi ukuran bundel.
Menyiapkan Module Federation dengan Webpack 5
Untuk mengimplementasikan Module Federation, Anda perlu mengonfigurasi Webpack di aplikasi host dan remote. Berikut adalah panduan langkah demi langkah:
1. Instal Webpack dan dependensi terkait:
Pertama, pastikan Anda telah menginstal Webpack 5 dan plugin yang diperlukan di proyek host dan remote Anda.
npm install webpack webpack-cli webpack-dev-server --save-dev
2. Konfigurasi Aplikasi Host:
Di file webpack.config.js aplikasi host, tambahkan ModuleFederationPlugin:
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const path = require('path');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: './src/index',
output: {
publicPath: 'http://localhost:3000/',
},
devServer: {
port: 3000,
hot: true,
historyApiFallback: true, // For single page application routing
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [
new ModuleFederationPlugin({
name: 'Host',
filename: 'remoteEntry.js',
remotes: {
// Define remotes here, e.g., 'RemoteApp': 'RemoteApp@http://localhost:3001/remoteEntry.js'
'RemoteApp': 'RemoteApp@http://localhost:3001/remoteEntry.js'
},
shared: {
react: { singleton: true, requiredVersion: '^17.0.0' },
'react-dom': { singleton: true, requiredVersion: '^17.0.0' },
// Add other shared dependencies here
},
}),
// ... other plugins
],
};
Penjelasan:
name: Nama aplikasi host.filename: Nama file yang akan mengekspos modul host. BiasanyaremoteEntry.js.remotes: Pemetaan nama aplikasi remote ke URL mereka. Formatnya adalah{NamaAplikasiRemote: 'NamaAplikasiRemote@URL/remoteEntry.js'}.shared: Daftar modul yang harus dibagikan antara aplikasi host dan remote. Menggunakansingleton: truememastikan bahwa hanya satu instance dari modul bersama yang dimuat. MenentukanrequiredVersionmembantu menghindari konflik versi.
3. Konfigurasi Aplikasi Remote:
Serupa dengan itu, konfigurasikan file webpack.config.js aplikasi remote:
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const path = require('path');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: './src/index',
output: {
publicPath: 'http://localhost:3001/',
},
devServer: {
port: 3001,
hot: true,
historyApiFallback: true, // For single page application routing
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [
new ModuleFederationPlugin({
name: 'RemoteApp',
filename: 'remoteEntry.js',
exposes: {
'./Widget': './src/Widget',
// Add other exposed modules here
},
shared: {
react: { singleton: true, requiredVersion: '^17.0.0' },
'react-dom': { singleton: true, requiredVersion: '^17.0.0' },
// Add other shared dependencies here
},
}),
// ... other plugins
],
};
Penjelasan:
name: Nama aplikasi remote.filename: Nama file yang akan mengekspos modul remote.exposes: Pemetaan nama modul ke path filenya di dalam aplikasi remote. Ini mendefinisikan modul mana yang dapat dikonsumsi oleh aplikasi lain. Contohnya,'./Widget': './src/Widget'mengekspos komponenWidgetyang terletak di./src/Widget.js.shared: Sama seperti di konfigurasi host.
4. Buat Modul yang Diekspos di Aplikasi Remote:
Di aplikasi remote, buat modul yang ingin Anda ekspos. Misalnya, buat file bernama src/Widget.js:
import React from 'react';
const Widget = () => {
return (
Remote Widget
This is a widget from the RemoteApp.
);
};
export default Widget;
5. Konsumsi Modul Remote di Aplikasi Host:
Di aplikasi host, impor modul remote menggunakan impor dinamis. Ini memastikan bahwa modul dimuat saat runtime.
import React, { useState, useEffect } from 'react';
const RemoteWidget = React.lazy(() => import('RemoteApp/Widget'));
const App = () => {
const [isWidgetLoaded, setIsWidgetLoaded] = useState(false);
useEffect(() => {
setIsWidgetLoaded(true);
}, []);
return (
Host Application
This is the host application.
{isWidgetLoaded ? (
Loading Widget... }>
) : (
Loading...
)}
Penjelasan:
React.lazy(() => import('RemoteApp/Widget')): Ini secara dinamis mengimpor modulWidgetdariRemoteApp. NamaRemoteAppsesuai dengan nama yang didefinisikan di bagianremotespada konfigurasi Webpack host.Widgetsesuai dengan nama modul yang didefinisikan di bagianexposespada konfigurasi Webpack remote.React.Suspense: Ini digunakan untuk menangani pemuatan asinkron dari modul remote. Propertifallbackmenentukan komponen yang akan dirender saat modul sedang dimuat.
6. Jalankan Aplikasi:
Mulai aplikasi host dan remote menggunakan npm start (atau metode pilihan Anda). Pastikan aplikasi remote berjalan *sebelum* aplikasi host.
Anda sekarang seharusnya melihat widget remote dirender di dalam aplikasi host.
Teknik Lanjutan Module Federation
Di luar penyiapan dasar, Module Federation menawarkan beberapa teknik lanjutan untuk membangun arsitektur micro-frontend yang canggih.
1. Manajemen Versi dan Berbagi:
Menangani dependensi bersama secara efektif sangat penting untuk menjaga stabilitas dan menghindari konflik. Module Federation menyediakan mekanisme untuk menentukan rentang versi dan instance singleton dari modul bersama. Menggunakan properti shared dalam konfigurasi Webpack memungkinkan Anda mengontrol bagaimana modul bersama dimuat dan dikelola.
Contoh:
shared: {
react: { singleton: true, requiredVersion: '^17.0.0' },
'react-dom': { singleton: true, requiredVersion: '^17.0.0' },
lodash: { eager: true, version: '4.17.21' }
}
singleton: true: Memastikan bahwa hanya satu instance modul yang dimuat, mencegah duplikasi dan mengurangi ukuran bundel. Ini sangat penting untuk pustaka seperti React dan ReactDOM.requiredVersion: Menentukan rentang versi yang dibutuhkan oleh aplikasi. Webpack akan mencoba memuat versi modul yang kompatibel.eager: true: Memuat modul dengan segera, bukan secara malas (lazy). Ini dapat meningkatkan kinerja dalam beberapa kasus, tetapi juga dapat meningkatkan ukuran bundel awal.
2. Module Federation Dinamis:
Alih-alih melakukan hardcoding URL aplikasi remote, Anda dapat memuatnya secara dinamis dari file konfigurasi atau endpoint API. Ini memungkinkan Anda untuk memperbarui arsitektur micro-frontend tanpa menerapkan ulang aplikasi host.
Contoh:
Buat file konfigurasi (misalnya, remote-config.json) yang berisi URL aplikasi remote:
{
"RemoteApp": "http://localhost:3001/remoteEntry.js",
"AnotherRemoteApp": "http://localhost:3002/remoteEntry.js"
}
Di aplikasi host, ambil file konfigurasi dan secara dinamis buat objek remotes:
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const path = require('path');
const fs = require('fs');
module.exports = {
// ... other configurations
plugins: [
new ModuleFederationPlugin({
name: 'Host',
filename: 'remoteEntry.js',
remotes: new Promise(resolve => {
fs.readFile(path.resolve(__dirname, 'remote-config.json'), (err, data) => {
if (err) {
console.error('Error reading remote-config.json:', err);
resolve({});
} else {
try {
const remotesConfig = JSON.parse(data.toString());
resolve(remotesConfig);
} catch (parseError) {
console.error('Error parsing remote-config.json:', parseError);
resolve({});
}
}
});
}),
shared: {
react: { singleton: true, requiredVersion: '^17.0.0' },
'react-dom': { singleton: true, requiredVersion: '^17.0.0' },
// Add other shared dependencies here
},
}),
// ... other plugins
],
};
Catatan Penting: Pertimbangkan untuk menggunakan metode yang lebih kuat untuk mengambil konfigurasi remote di lingkungan produksi, seperti endpoint API atau layanan konfigurasi khusus. Contoh di atas menggunakan fs.readFile untuk kesederhanaan, tetapi ini umumnya tidak cocok untuk penerapan produksi.
3. Strategi Pemuatan Kustom:
Module Federation memungkinkan Anda untuk menyesuaikan cara modul remote dimuat. Anda dapat mengimplementasikan strategi pemuatan kustom untuk mengoptimalkan kinerja atau menangani skenario spesifik, seperti memuat modul dari CDN atau menggunakan service worker.
Webpack mengekspos hook yang memungkinkan Anda untuk mencegat dan memodifikasi proses pemuatan modul. Ini memungkinkan kontrol yang lebih rinci atas bagaimana modul remote diambil dan diinisialisasi.
4. Menangani CSS dan Gaya:
Berbagi CSS dan gaya antara micro-frontend bisa jadi rumit. Module Federation mendukung berbagai pendekatan untuk menangani gaya, termasuk:
- CSS Modules: Gunakan CSS Modules untuk mengenkapsulasi gaya di dalam setiap micro-frontend, mencegah konflik dan memastikan konsistensi.
- Styled Components: Manfaatkan styled components atau pustaka CSS-in-JS lainnya untuk mengelola gaya di dalam komponen itu sendiri.
- Gaya Global: Muat gaya global dari pustaka bersama atau CDN. Hati-hati dengan pendekatan ini, karena dapat menyebabkan konflik jika gaya tidak diberi namespace dengan benar.
Contoh menggunakan CSS Modules:
Konfigurasikan Webpack untuk menggunakan CSS Modules:
module: {
rules: [
{
test: /\.module\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]--[hash:base64:5]',
},
importLoaders: 1,
},
},
'postcss-loader',
],
},
// ... other rules
],
}
Impor CSS Modules di komponen Anda:
import React from 'react';
import styles from './Widget.module.css';
const Widget = () => {
return (
Remote Widget
This is a widget from the RemoteApp.
);
};
export default Widget;
5. Komunikasi Antar Micro-Frontend:
Micro-frontend sering kali perlu berkomunikasi satu sama lain untuk bertukar data atau memicu tindakan. Ada beberapa cara untuk mencapai ini:
- Event Bersama (Shared Events): Gunakan event bus global untuk mempublikasikan dan berlangganan event. Ini memungkinkan micro-frontend berkomunikasi secara asinkron tanpa ketergantungan langsung.
- Event Kustom: Manfaatkan event DOM kustom untuk komunikasi antar micro-frontend di dalam halaman yang sama.
- Manajemen State Bersama: Gunakan pustaka manajemen state bersama (misalnya, Redux, Zustand) untuk memusatkan state dan memfasilitasi berbagi data.
- Impor Modul Langsung: Jika micro-frontend sangat terikat, Anda dapat mengimpor modul secara langsung satu sama lain menggunakan Module Federation. Namun, pendekatan ini harus digunakan dengan hemat untuk menghindari menciptakan ketergantungan yang merusak manfaat micro-frontend.
- API dan Layanan: Micro-frontend dapat berkomunikasi satu sama lain melalui API dan layanan, memungkinkan loose coupling dan fleksibilitas yang lebih besar. Ini sangat berguna ketika micro-frontend diterapkan di domain yang berbeda atau memiliki persyaratan keamanan yang berbeda.
Manfaat Menggunakan Module Federation untuk Micro-Frontend
- Peningkatan Skalabilitas: Micro-frontend dapat diskalakan secara independen, memungkinkan Anda mengalokasikan sumber daya di tempat yang paling dibutuhkan.
- Peningkatan Kemudahan Pemeliharaan: Basis kode yang lebih kecil lebih mudah dipahami dan dipelihara, mengurangi risiko bug dan meningkatkan produktivitas pengembang.
- Siklus Penerapan yang Lebih Cepat: Micro-frontend dapat diterapkan secara independen, memungkinkan siklus iterasi yang lebih cepat dan rilis fitur baru yang lebih cepat.
- Keberagaman Teknologi: Tim dapat memilih teknologi dan kerangka kerja yang paling sesuai dengan kebutuhan mereka, mendorong inovasi dan memungkinkan penggunaan keahlian khusus.
- Peningkatan Otonomi Tim: Setiap micro-frontend dimiliki oleh tim yang berdedikasi, mempromosikan kepemilikan dan akuntabilitas.
- Onboarding yang Disederhanakan: Pengembang baru dapat dengan cepat beradaptasi dengan basis kode yang lebih kecil dan lebih mudah dikelola.
Tantangan Menggunakan Module Federation
- Peningkatan Kompleksitas: Arsitektur micro-frontend bisa lebih kompleks daripada arsitektur monolitik tradisional, membutuhkan perencanaan dan koordinasi yang cermat.
- Manajemen Dependensi Bersama: Mengelola dependensi bersama bisa menjadi tantangan, terutama ketika micro-frontend yang berbeda menggunakan versi yang berbeda dari pustaka yang sama.
- Overhead Komunikasi: Komunikasi antar micro-frontend dapat menimbulkan overhead dan latensi.
- Pengujian Integrasi: Menguji integrasi micro-frontend bisa lebih kompleks daripada menguji aplikasi monolitik.
- Overhead Penyiapan Awal: Mengonfigurasi Module Federation dan menyiapkan infrastruktur awal dapat memerlukan upaya yang signifikan.
Contoh Dunia Nyata dan Kasus Penggunaan
Module Federation sedang digunakan oleh semakin banyak perusahaan untuk membangun aplikasi web yang besar dan kompleks. Berikut adalah beberapa contoh dunia nyata dan kasus penggunaan:
- Platform E-commerce: Platform e-commerce besar sering menggunakan micro-frontend untuk mengelola berbagai bagian situs web, seperti katalog produk, keranjang belanja, dan proses checkout. Misalnya, sebuah ritel Jerman mungkin menggunakan micro-frontend terpisah untuk menampilkan produk dalam bahasa Jerman, sementara ritel Prancis menggunakan micro-frontend yang berbeda untuk produk berbahasa Prancis, keduanya terintegrasi ke dalam satu aplikasi host tunggal.
- Institusi Keuangan: Bank dan lembaga keuangan menggunakan micro-frontend untuk membangun aplikasi perbankan yang kompleks, seperti portal perbankan online, platform investasi, dan sistem perdagangan. Sebuah bank global mungkin memiliki tim di berbagai negara yang mengembangkan micro-frontend untuk wilayah yang berbeda, masing-masing disesuaikan dengan peraturan lokal dan preferensi pelanggan.
- Sistem Manajemen Konten (CMS): Platform CMS dapat menggunakan micro-frontend untuk memungkinkan pengguna menyesuaikan tampilan dan fungsionalitas situs web mereka. Misalnya, sebuah perusahaan Kanada yang menyediakan layanan CMS mungkin memungkinkan pengguna untuk menambah atau menghapus micro-frontend (widget) yang berbeda ke situs web mereka untuk menyesuaikan fungsionalitasnya.
- Dasbor dan Platform Analitik: Micro-frontend sangat cocok untuk membangun dasbor dan platform analitik, di mana tim yang berbeda dapat menyumbangkan widget dan visualisasi yang berbeda.
- Aplikasi Kesehatan: Penyedia layanan kesehatan menggunakan micro-frontend untuk membangun portal pasien, sistem rekam medis elektronik (EHR), dan platform telemedicine.
Praktik Terbaik untuk Mengimplementasikan Module Federation
Untuk memastikan keberhasilan implementasi Module Federation Anda, ikuti praktik terbaik berikut:
- Rencanakan dengan Cermat: Sebelum Anda mulai, rencanakan arsitektur micro-frontend Anda dengan cermat dan definisikan batasan yang jelas antara aplikasi yang berbeda.
- Bangun Saluran Komunikasi yang Jelas: Bangun saluran komunikasi yang jelas antara tim yang bertanggung jawab atas micro-frontend yang berbeda.
- Otomatiskan Penerapan: Otomatiskan proses penerapan untuk memastikan bahwa micro-frontend dapat diterapkan dengan cepat dan andal.
- Pantau Kinerja: Pantau kinerja arsitektur micro-frontend Anda untuk mengidentifikasi dan mengatasi setiap hambatan.
- Implementasikan Penanganan Kesalahan yang Kuat: Implementasikan penanganan kesalahan yang kuat untuk mencegah kegagalan beruntun dan memastikan bahwa aplikasi tetap tangguh.
- Gunakan Gaya Kode yang Konsisten: Terapkan gaya kode yang konsisten di semua micro-frontend untuk meningkatkan kemudahan pemeliharaan.
- Dokumentasikan Semuanya: Dokumentasikan arsitektur, dependensi, dan protokol komunikasi Anda untuk memastikan bahwa sistem dipahami dengan baik dan dapat dipelihara.
- Pertimbangkan Implikasi Keamanan: Pertimbangkan dengan cermat implikasi keamanan arsitektur micro-frontend Anda dan terapkan langkah-langkah keamanan yang sesuai. Pastikan kepatuhan terhadap peraturan privasi data global seperti GDPR dan CCPA.
Kesimpulan
JavaScript Module Federation dengan Webpack 5 menyediakan cara yang kuat dan fleksibel untuk membangun arsitektur micro-frontend. Dengan memecah aplikasi besar menjadi unit-unit yang lebih kecil dan dapat diterapkan secara independen, Anda dapat meningkatkan skalabilitas, kemudahan pemeliharaan, dan otonomi tim. Meskipun ada tantangan yang terkait dengan penerapan micro-frontend, manfaatnya sering kali lebih besar daripada biayanya, terutama untuk aplikasi web yang kompleks. Dengan mengikuti praktik terbaik yang diuraikan dalam panduan ini, Anda dapat berhasil memanfaatkan Module Federation untuk membangun arsitektur micro-frontend yang kuat dan dapat diskalakan yang memenuhi kebutuhan organisasi dan pengguna Anda di seluruh dunia.