Ön yüz geliştirme ortamının değişen yapısında, monolitik uygulamalar büyük mühendislik ekipleri için sıkça darboğaz haline gelir. Uygulamalar büyüdükçe, bağımlılık yönetimi, dağıtım döngüleri ve kod sahipliği karmaşıklığı da artar. İşte tam da bu noktada Mikro-Frontend mimarisi ön plana çıkar; ekiplerin bağımsız ön yüz uygulamaları oluşturmasına, test etmesine ve dağıtmasına olanak tanır. Erken dönem uygulamalar karmaşık iframe taklitleri veya çalışma zamanı paketleme çözümlerine dayanırken, Webpack 5 yerel ve sağlam bir çözüm sunar: Module Federation.
Bu yazıda, Webpack 5'in Module Federation Plugin'ini kullanarak, geleneksel ek yük olmadan farklı uygulamalar arasında paylaşılabilir ve tüketilebilen gerçekten ölçeklenebilir, bağımsız mikro-frontend'ler nasıl oluşturulacağını keşfedeceğiz.
Module Federation Nedir?
Module Federation, JavaScript uygulamalarının çalışma zamanında (runtime) diğer çalışma ortamlarından (tarayıcılar, sunucular veya Web Workers) kodu dinamik olarak içe aktarmasına olanak tanıyan bir kavramdır. Geleneksel paketleyiciler bağımlılıkları derleme zamanında çözerken, Module Federation bunları yürütme zamanında çözer. Bu, Uygulama A'nın, her iki uygulama da çalıştığı sürece, Uygulama B'de yazılmış kodu sanki yerelmiş gibi çalıştırabileceği anlamına gelir.
Temel avantajlar şunlardır:
- Bağımsız Dağıtımlar: Ekipler, ana uygulamaya dokunmadan kendi spesifik mikro-frontend'lerini güncelleyebilir ve dağıtabilir.
- Paylaşılan Bağımlılıklar: React veya Redux gibi kritik kütüphaneler, paket boyutunu azaltmak ve tutarlılığı sağlamak amacıyla uygulamalar arasında paylaşılabilir.
- Teknoloji Bağımsızlığı: Webpack birincil araç olsa da, protokol diğer derleme sistemleriyle entegrasyona izin verir; ancak Webpack en olgun uygulamayı sunar.
Host ve Remote Uygulamaların Kurulumu
Module Federation'ı göstermek için iki uygulamalı bir senaryo varsayalım:
- Host App (Ana Uygulama): Arayüzü koordine eden ana kabuk uygulaması.
- Remote App (Uzak Uygulama): Host tarafından tüketilecek, belirli bir özelliğe sahip modül (örneğin, bir kullanıcı panosu veya sohbet bileşeni).
Adım 1: Remote App'te Modülleri Açığa Çıkarma
İlk olarak, Remote App'i bileşenlerini açığa çıkarmak için yapılandırmamız gerekir. Uzak uygulamanın webpack.config.js dosyasında ModuleFederationPlugin'i içe aktarır ve exposes alanını tanımlarız.
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
// ... diğer yapılandırmalar
plugins: [
new ModuleFederationPlugin({
name: 'remoteApp',
filename: 'remoteEntry.js',
exposes: {
'./UserProfile': './src/components/UserProfile',
},
shared: {
react: { singleton: true, requiredVersion: '^18.0.0' },
'react-dom': { singleton: true, requiredVersion: '^18.0.0' }
}
}),
new HtmlWebpackPlugin({
template: './public/index.html'
})
]
};
Burada ./UserProfile'ü açığa çıkarıyoruz. Ayrıca shared bağımlılıklarını yapılandırıyoruz. singleton: true ayarını yaparak, React'in her iki uygulamada da yalnızca bir örneğinin yüklenmesini sağlıyoruz; bu durum durum tutarsızlıklarını önler ve yük boyutunu azaltır.
Adım 2: Host App'te Modüllerin Tüketilmesi
Ardından, Host App'i açığa çıkarılan modülü tüketmek için yapılandırıyoruz. Ana uygulamanın ModuleFederationPlugin'inde remote yapılandırmasını ekliyoruz.
new ModuleFederationPlugin({
name: 'hostApp',
remotes: {
remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js',
},
shared: {
react: { singleton: true, requiredVersion: '^18.0.0' },
'react-dom': { singleton: true, requiredVersion: '^18.0.0' }
}
})
remotes alanı, Webpack'e uzak giriş dosyasını nerede bulacağını söyler. Statik bir URL veya ortama göre yapılandırmayı döndüren dinamik bir uç nokta kullanabilirsiniz. Uyumluluğu sağlamak için shared yapılandırmasının uzak uygulama ile eşleştiğine dikkat edin.
React'te Dinamik İçe Aktarma
Yapılandırma tamamlandığında, uzak bileşeni System.import API'sini (Webpack tarafından polifilleştirilmiştir) veya standart dinamik içe aktarmaları kullanarak dinamik olarak içe aktarabilirsiniz. İşte bir React bileşeninde örnek:
import React, { lazy, Suspense } from 'react';
// Uzak bileşeni tembelce yükle
const UserProfile = lazy(() => import('remoteApp/UserProfile'));
const HostComponent = () => {
return (
Loading... }>