İçeriğe atla
Ayhan Sipahi Ayhan Sipahi

Sunucu Tarafı Micro-Frontend Kompozisyonu: Tek Sayfa, Birçok Ekip

Sunucu tarafı micro-frontend kompozisyonu, bağımsız ekiplerin tek bir sayfanın parçalarını sahiplenmesini sağlar. Zor kısım sahiplik sınırı ve sürümlenmiş tutarlılık sözleşmesidir.

Checkout ya da vitrin gibi tek bir yüksek trafikli sayfa, çoğu zaman bağımsız teslimat yapması gereken birçok ekibin katkısına ihtiyaç duyar. Frontend monolit, bu ekipleri tek bir sürüm trenine bindirir; böylece bir ekibin yavaş derlemesi veya bozuk testi diğer tüm ekiplerin deploy’unu engeller. Sayfayı birleştiren mekanizma kolay kısımdır; asıl zor problem, sahiplik sınırı ile birçok ekibi koordineli bir sürüm olmadan görsel ve davranışsal olarak hizalı tutan sürümlenmiş tutarlılık sözleşmesidir. Bu yazı şunu savunur: çok ekipli, SEO’ya duyarlı ve ilk boyamanın önemli olduğu bir sayfada varsayılan seçenek sunucu tarafı kompozisyondur; istemci tarafı kompozisyon ile iframe’lerin nerede daha iyi olduğunu da gösterir.

Bu yazı, mevcut istemci tarafı seriye sunucu tarafından bakan bir tamamlayıcıdır. Module Federation mekaniğine, event-bus bağlantılarına ve çalışma zamanı hata ayıklamasına ihtiyacınız varsa Micro Frontend Mimari Temelleri ve Uygulama Desenleri ile başlayın. Buradaki odak, sunucu tarafı birleştirme modeli ve onu bir arada tutan sözleşmedir.

Küçük Bir Tam-Yığın Uygulama Olarak Parça

Sunucu tarafı kompozisyonda sahiplik birimi parçadır (fragment): kendi sunucu tarafında render edilen HTML’i, hidrasyonu yapan kendi istemci paketi ve kendi durumu olan bağımsız bir uygulama. Bir ekip parçayı baştan sona sahiplenir. Kompozisyon katmanı parçanın içine asla erişmez; yalnızca parçanın render edilmiş işaretlemesini URL üzerinden çeker.

micro-frontends.org topluluk rehberi bunu somutlaştırır. Her ekip kendi sunucusunu çalıştırır ve render edilen çıktıya düz bir URL ile erişilir: /blue-buy?sku=t_porsche isteği, sayfaya yerleştirilmeye hazır, tamamen render edilmiş bir <button> döndürür. Podium aynı biçimi kullanır ve buna “podlet” adını verir: bir podlet sunucusu, “daha sonra tam bir HTML sayfası oluşturmak için bir [layout] sunucusunda kullanılabilecek HTML parçaları üretmekten sorumludur.” Desen framework’ten bağımsızdır ve Express birinci sınıf bir entegrasyon olarak desteklenir.

Node ile minimal bir parça sunucusu şöyle görünür. Kendi React alt ağacını sunucu tarafında render eder ve işaretlemeyi bir URL’de sunar.

// mini-cart parçası: kendi sunucusu, kendi React ağacı
import express from "express";
import { renderToString } from "react-dom/server";
import { MiniCart } from "./MiniCart";

const app = express();

app.get("/fragment/mini-cart", async (req, res) => {
  const cart = await loadCart(req.query.userId as string);
  const html = renderToString(<MiniCart cart={cart} />);

  // Bu parçanın varlıklarının nerede olduğunu kompozisyon katmanına bildir
  res.setHeader("Link", '</assets/mini-cart.js>; rel="fragment-script"');
  res.send(html);
});

app.listen(3002);

Kompozisyon katmanı bu URL’i çeker. Parça kendi render’ını, kendi veri çekme işlemini ve kendi varlıklarını sahiplenir. Sepetin iç yapısına dair hiçbir şey host’a sızmaz.

Kompozisyon Katmanı

İstek anında bir layout host’u her parçanın işaretlemesini çeker ve yanıtları, tarayıcıya akış halinde gönderilen tek bir dokümana diker. Kanonik, düşük teknolojili mekanizma Server Side Includes’tır; burada host, sayfayı göndermeden önce <!--#include virtual="/blue-buy?sku=t_porsche" --> gibi yer tutucuları çözer. Cam Jackson’ın Martin Fowler makalesi aynı fikri bir Nginx ssi on; direktifiyle gösterir ve sunucu tarafı şablon kompozisyonunu daha düşük bir seçenek olarak değil, “sıradan” ama meşru bir temel olarak konumlandırır.

Bir şablon host’u ham SSI’dan daha fazla kontrol sağlar. Arşivlenmiş ama iyi belgelenmiş bir OSS projesi olan Tailor (2022’den beri salt-okunur), bu biçim için net bir önceki örnektir: parçalar özel elemanlar olarak tanımlanır ve kompozisyon anında host’un dikkate aldığı öznitelikler taşır. Podium ise aynı fikir üzerine kurulu, aktif olarak bakımı yapılan bir alternatiftir.

<!-- Kompozisyon host'u tarafından çözülen layout şablonu -->
<html>
  <head><title>Checkout</title></head>
  <body>
    <fragment src="https://header.internal/fragment"></fragment>

    <fragment
      src="https://cart.internal/fragment/mini-cart"
      primary
      timeout="2000"
      fallback-src="https://cart.internal/fragment/mini-cart-empty">
    </fragment>

    <fragment
      src="https://reco.internal/fragment/recommended"
      async>
    </fragment>
  </body>
</html>

Öznitelikler operasyonel sözleşmeyi taşır. Tailor’da timeout varsayılan olarak 3000 ms’dir, primary bir parçanın sayfa yanıt kodunu belirlemesini sağlar, async bir parçayı body’nin sonuna erteler ve fallback-src, parça zaman aşımına uğradığında veya hata verdiğinde sunulacak bir URL belirtir. En önemlisi bu son özniteliktir: yavaş bir ekibin tüm sayfayı durdurmasını engelleyen, parça başına devre kesicidir.

İstek anındaki akış bir dağıtım (fan-out) ve bir dikiştir.

Reco fragmentMini-cart fragmentHeader fragmentComposition layerBrowserReco fragmentMini-cart fragmentHeader fragmentComposition layerBrowserpar[Parallel fan-out]GET /checkoutGET /fragmentGET /fragment (timeout 2000, fallback set)GET /fragment (async)header HTMLcart HTML (or fallback on timeout)stream stitched documentreco HTMLappend async fragment

Note

Akışlı bir host, yavaş parçalar çözülmeden önce doküman head’ini ve erken parçaları göndermeye başlayabilir; böylece en yavaş parça ilk byte’ı değil yalnızca kendi bölgesini geciktirir. Pahalı parçaları async ile işaretlemek ve onları ilk boyamanın ötesine ertelemek buradaki ana koldur.

Her Parçanın Sahiplendiği Kesişen Sorumluluklar

Uluslararasılaştırma, kimlik doğrulama token’ları, gözlemlenebilirlik ve para biçimlendirme her parçanın kendi sorumluluğundadır, host tarafından enjekte edilmez. Parçaların paylaşılan bir DOM’da çakışmasını önlemek için micro-frontends.org’un “Ekip Önekleri Belirle” kuralı geçerlidir: CSS sınıflarını, özel olayları, local storage anahtarlarını ve çerezleri ekip bazında isim alanına alın. Sınıflarda cart- öneki ve olaylarda cart: öneki, sahipliği okunabilir kılar ve bir ekibin global seçicisinin başka bir ekibin işaretlemesini yeniden biçimlendirmesini önler.

Host’un ince kalmasının nedeni de budur. Host bir parçanın iç yapısı hakkında ne kadar çok şey bilirse, o kadar çok bağımlılık yeniden devreye girer. Host’un işi çekmek, dikmek, zaman aşımı uygulamak ve geri düşmektir (fallback); geri kalan her şey parçayı sahiplenen ekibe aittir.

Tutarlılık Sözleşmesi

Mimarinin gerçek ekiplerle temas ettiğinde ayakta kalıp kalmayacağını asıl belirleyen kısım budur. Bağımsız render, yukarıdaki parça modeliyle çözülür. Onunla çözülmeyen şey görsel ve davranışsal tutarlılıktır: bir şey onları bir arada tutmadıkça her ekibin butonları, boşlukları, odak halkaları ve para biçimlendirmesi birbirinden uzaklaşır. O “şey” tutarlılık sözleşmesidir ve iki yarısı vardır.

İlk yarı sürümlenmiş paylaşılan bir tasarım sistemidir. Tutarlılık paylaşılan bir kod tabanından değil, sürümlenmiş paylaşılan paketlerden oluşan bir kayıttan (registry) gelir: bir UI bileşen kütüphanesi ile bir tasarım-token paketi, her biri semver üzerinden tüketilir; böylece ekipler kendi temposunda yükseltme yapar. Cam Jackson bunu doğrudan destekler. Paylaşılan bileşen kütüphaneleri “kodun yeniden kullanımıyla azaltılmış efor ve görsel tutarlılık” sağlar ve “yaşayan bir stil rehberi” görevi görür. Aynı zamanda bir Foundation Platform’u çok erken kurmaya karşı uyarır; bunun yerine “ekiplerin kendi bileşenlerini oluşturmasına izin verin … bu bir miktar tekrara yol açsa bile” der, kanıtlanmış olanları ise daha sonra paylaşılan kütüphaneye taşıyın. Paylaşılacak ilk en iyi adaylar basit görsel ilkellerdir: ikonlar, etiketler, butonlar.

İkinci yarı kompozisyon protokolünün kendisidir: parça URL biçimi, öznitelik kuralları (timeout, primary, async, fallback-src) ve isim alanı kuralları. Bu, host ile her parça arasındaki arayüzdür ve yeni bir parçanın host değişmeden sayfaya katılmasını sağlayan şeydir.

own upgrade cadence

own upgrade cadence

own upgrade cadence

Shared registry: UI lib + design tokens (semver)

Header fragment: ui@^2.3

Mini-cart fragment: ui@^2.4

Reco fragment: ui@^2.1

Burada adı konması gereken gerçek bir gerilim var. micro-frontends.org “Ekip Kodunu İzole Et: tüm ekipler aynı framework’ü kullansa bile çalışma zamanını paylaşma ve paylaşılan duruma ya da global değişkenlere güvenme” der. Paylaşılan bir UI kütüphanesi ise tanımı gereği paylaşılan koddur. Her iki konum da farklı katmanlarda doğrudur. Çözüm nettir: semver üzerinden tüketilen derleme zamanı paketlerini paylaşın, ancak parçalar arasında asla bir çalışma zamanı singleton’u veya global durum paylaşmayın. Token’lar ve bileşenler her ekibin sabitlediği sürümlenmiş npm paketleri olarak gönderilir; tarayıcıda canlı bir paylaşılan nesneye dönüşmezler.

Bunu yanlış yapmanın bedeli tam olarak Cam Jackson’ın uyardığı şeydir. Ortak bağımlılıkları dışsallaştırmak “bir miktar derleme zamanı bağımlılığını yeniden devreye sokar … örtük bir sözleşme … hepimiz bu tam sürümleri kullanmalıyız … Kırıcı bir değişiklik olursa … büyük bir koordineli yükseltme çabası ve tek seferlik bir lockstep sürüm olayı. Bu, kaçınmaya çalıştığımız her şeydir …” Yani sunucu tarafı kompozisyonu çalışır kılan mühendislik disiplini SSI dikişi değildir. Sözleşme yönetimidir: semver disiplini, yalnızca ekleyen (additive) token değişiklikleri ve ekiplerin lockstep yerine kendi takvimlerinde yükseltme yapmasına yetecek kadar uzun kullanımdan kaldırma pencereleri.

Sunucu, İstemci ve Iframe Karşılaştırması

Kompozisyon stili bir karardır ve modadan değil sayfadan çıkar. Sunucu tarafı kompozisyon, ilk boyamanın ve SEO’nun önemli olduğu çok ekipli bir sayfanın varsayılanıdır. SEO’nun anlamsız olduğu ve tarayıcı içi rota geçişlerinin ilk byte’tan daha önemli olduğu, kimlik doğrulamalı bir uygulama kabuğu söz konusu olduğunda istemci tarafı çalışma zamanı kompozisyonuna geçin. İçeriğin güvenilmez üçüncü taraf kodu ya da DOM’u paylaşmasına güvenemeyeceğiniz eski (legacy) kod olduğu, sert izolasyon durumlarında iframe’leri saklayın.

FaktörSunucu tarafı kompozisyonİstemci tarafı (Module Federation / single-spa)Iframe
SEO / ilk boyamaGüçlü (HTML render edilmiş gelir)SSR ile eşlenmedikçe zayıfZayıf
Tarayıcı içi rota geçişleriVarsayılan olarak tam yeniden yüklemeGüçlü (SPA kabuğu)Zayıf
Stil / çalışma zamanı izolasyonuManuel (önekler, kapsamlı CSS)Manuel (paylaşılan singleton’lar sapma riski)Güçlü (yerel)
Ekip bağımlılığıDüşük (URL + öznitelik sözleşmesi)Derleme / çalışma zamanı sürüm sözleşmesiEn düşük
Hata yayılma alanıParça başına timeout + fallback-srcPaylaşılan bağımlılık kırılması yayılabilirSınırlı
Derin sayfa entegrasyonuİyiEn iyiZayıf (history, duyarlı yerleşim)

İstemci tarafı geçişi mevcut seri tarafından iyi karşılanır. Module Federation 2.0, Webpack 5’in yerleşik sürümünün üzerine bir Federation Runtime, bir Manifest, dinamik tip ipuçları ve bir çalışma zamanı eklenti sistemi ekler; büyük ölçekli tarayıcı içi kompozisyon için konumlanmıştır. single-spa, uygulamaları tarayıcıda bir root-config ile import map üzerinden birleştirir, modülleri bir orgName ile isim alanına alır ve Layout Engine’i üzerinden isteğe bağlı olarak SSR ekleyebilir. Her ikisi de sayfa giriş arkasındaki bir uygulama kabuğu olduğunda doğru araçtır.

Yes

No

Yes

No

Yes

No

Multi-team page to compose

SEO / first paint critical?

Untrusted or legacy content?

In-browser route transitions dominate?

Server-side composition (default)

Client-side (Module Federation / single-spa)

Iframe isolation

Trade-off’lar

Sunucu tarafı kompozisyon güçlü yanlarının bedelini öder. En önemli maliyet gecikme bağımlılığıdır: micro-frontends.org’un ifadesiyle, “en yavaş parça tüm sayfanın yanıt süresini belirler.” Hafifletmeler sözleşmenin zaten sağladıklarıdır: parça yanıtlarını önbelleğe alın, parça başına bir timeout ile bir fallback-src ayarlayın ve pahalı parçaları async ile işaretleyerek ilk boyamanın ötesine erteleyin ve istemci tarafında yükletin. Ayrıca her parça kompozisyon host’unun yanında kendi sunucusu olduğu için daha fazla altyapı işletirsiniz.

İstemci tarafı kompozisyon bunu farklı bir maliyetle takas eder. Her micro-frontend kendi React kopyasını gönderebilir; bu yüzden Cam Jackson’ın deyimiyle “müşteriler React’i n kez indirir.” Paylaşılan bağımlılıkları dışsallaştırmak yükü düzeltir ama yukarıda anlatılan derleme zamanı bağımlılığını ve lockstep yükseltme riskini yeniden devreye sokar. Iframe’ler en güçlü izolasyonu yerel olarak verir ama yönlendirme ve history, duyarlı yerleşim ve derin entegrasyon zordur; Cam Jackson onları kullanma konusundaki çekincenin kısmen estetik, kısmen haklı olduğunu belirtir.

Sık Yapılan Hatalar

Micro-frontend’leri organizasyonel bir seçim yerine bir render teknolojisi seçimi olarak görmek temel hatadır. Sayfa, ekipler bölündüğü için bölünür; tasarım, organizasyon sınırıdır. Team Topologies aynı fikri, bir platformu X-as-a-Service etkileşim modu üzerinden tüketen akış-hizalı (stream-aligned) ekipler olarak çerçeveler ve kompozisyon katmanı tam olarak o platform hizmetidir. Ekip sınırları sayfa bölgeleriyle hizalanmazsa hiçbir render teknolojisi mimariyi kurtaramaz.

Diğer tekrarlayan başarısızlıkların tümü sözleşmeyi atlamaya işaret eder:

  • Paylaşılan tasarım sistemi olmaması ya da bir Foundation Platform’u çok erken kurmak. İlki görsel sapmaya, ikincisi gereksiz yenilemeye yol açar. Baştan tek bir sistem dayatmak yerine kanıtlanmış ilkelleri daha sonra paylaşılan kütüphaneye taşıyın.
  • Parça başına zaman aşımı veya geri düşme olmadan eşzamanlı dağıtım. O zaman yavaş bir ekip tüm sayfayı durdurur. Her parçanın bir timeout ve bir fallback-src’ye ihtiyacı vardır.
  • Parçalar arasında global durum veya kopyalanmış framework örnekleri paylaşmak. Bu, micro-frontend’lere geçerken kaçındığınız çalışma zamanı bağımlılığını geri getirir. Ekip kodunu izole edin ve ekip önekleriyle isim alanına alın.
  • Paylaşılan UI kütüphanesi sürümünü “herkes birlikte yükseltir” olarak görmek. Bu, kaçmaya çalıştığınız lockstep sürümdür. Sözleşme, semver aralıkları ve kullanımdan kaldırma pencereleri aracılığıyla bağımsız yükseltme temposuna izin vermelidir.

Kapanış

İlk boyamanın önemli olduğu çok ekipli, SEO’ya duyarlı bir sayfada varsayılan seçenek sunucu tarafı kompozisyondur: parçalar küçük tam-yığın uygulamalardır, host onların işaretlemesini parça başına zaman aşımları ve geri düşmelerle çeker ve diker, sürümlenmiş paylaşılan bir tasarım sistemi ile kararlı bir kompozisyon protokolü ekipleri lockstep bir sürüm olmadan hizalı tutar. Sınır nettir. Sayfa, tarayıcı içi rota geçişlerinin ilk boyamadan daha önemli olduğu, kimlik doğrulamalı bir uygulama kabuğu olduğunda Module Federation veya single-spa ile istemci tarafı kompozisyona geçin; içerik güvenilmez ya da güvenilemeyecek eski kod olduğunda yerel izolasyon için bir iframe kullanın. Bir render mekanizması seçmeden önce ekip ve sahiplik sınırlarının nereye düştüğüne ve tasarım sistemi sözleşmesinin nasıl sürümleneceğine karar verin. Mimarinin ayakta kalıp kalmayacağını belirleyen karar SSI dikişi değil, işte bu karardır.

Kaynaklar

  • Micro Frontends (micro-frontends.org) - Kanonik topluluk rehberi: ekip kodunu izole et, evrensel render, ekip önekleri ve SSI ile özel-eleman parça örnekleri.
  • Cam Jackson, “Micro Frontends” (martinfowler.com) - Sunucu tarafı şablon kompozisyonu, paylaşılan bileşen kütüphaneleri ve paylaşılan bağımlılıkların derleme zamanı maliyeti üzerine temel makale.
  • @podium/podlet API - Bir layout sunucusu tarafından birleştirilen sayfa-parça sunucusu olarak podlet; framework’ten bağımsız, Express birinci sınıf entegrasyon.
  • Tailor (GitHub) - <fragment> özniteliklerini (timeout, primary, async, fallback-src) gösteren OSS akışlı layout hizmeti. 2022’den beri arşivlenmiş/salt-okunur (son sürüm 3.9.2, 2018); bakımı yapılan bir bağımlılık değil, sözleşmenin net bir örneği olarak anılıyor. Bakımı yapılan seçenek için Podium kullanın.
  • single-spa Getting Started - Root-config ile import map üzerinden istemci tarafı kompozisyon ve isteğe bağlı SSR Layout Engine.
  • Module Federation - Büyük ölçekli istemci tarafı kompozisyon için Federation Runtime, Manifest ve çalışma zamanı eklentileri. Hızlı ilerliyor; ayrıntılara güvenmeden önce sürüm çerçevesini doğrulayın.
  • Team Topologies — Key Concepts - Sahiplik-sınırı argümanını temellendiren akış-hizalı ile platform ekipleri ve X-as-a-Service etkileşim modu.
  • Micro Frontend Mimari Temelleri - Dört kompozisyon türünü ve ekip yapısı ön koşullarını kapsayan tamamlayıcı seri.
  • Micro Frontend Uygulama Desenleri - Module Federation kurulumu, çapraz uygulama iletişimi ve istemci tarafı kompozisyon için yönlendirmeyi kapsayan tamamlayıcı seri.

İlgili yazılar