Yazılarımız

Veri Akademi

ANGULAR LAZY LOADİNG NEDİR? MODÜLER MİMARİ VE BUNDLE OPTİMİZASYONU

Angular uygulaması büyüdükçe “ilk açılış” süresi genellikle sessizce uzar: daha fazla ekran, daha fazla bileşen, daha fazla bağımlılık… Kullanıcı ise yalnızca ana sayfayı görmek isterken tüm uygulamanın kodunu indirmek zorunda kalır. İşte burada Angular lazy loading, uygulamanın ihtiyaç duyduğu parçaları doğru zamanda getirerek yükü dengeler.

Bu yazıda lazy loading’in ne olduğunu, modüler mimari ile nasıl daha doğal hale geldiğini ve bundle optimizasyonu açısından hangi kazanımları sunduğunu adım adım ele alacağız. Ayrıca Router yapılandırması, preloading stratejileri, modern Angular yaklaşımları (standalone) ve sahada sık görülen hatalar için pratik öneriler bulacaksın.

Hedefimiz “tek bir ayar yaptım, bitti” yerine; doğru modül sınırları, rota tasarımı ve izlenebilir performans metrikleriyle sürdürülebilir bir yapı kurmak. Eğer daha kapsamlı bir yol haritası istersen, Angular Eğitimi sayfasına da göz atabilirsin.

Angular Lazy Loading Kavramı ve Neden Önemli?

Lazy loading, uygulamanın tüm kodunu başlangıçta indirmek yerine, kullanıcı belirli bir rotaya gittiğinde ilgili parçayı getirme yaklaşımıdır. Angular tarafında bu, Router ile route bazlı code splitting üreterek gerçekleşir. Sonuç: daha küçük initial bundle, daha hızlı ilk render ve daha iyi algılanan performans.

Özellikle çok sayfalı kurumsal paneller, e-ticaret yönetim ekranları ve mikro-frontend’e giden yolun ilk adımlarında lazy loading ciddi fark yaratır. Buradaki kritik nokta, yalnızca “yüklemesi geciken modüller” değil; aynı zamanda net sınırlarla ayrılmış feature alanları tasarlamaktır.

Eager Loading ve Lazy Loading Arasındaki Fark

Eager loading’de (varsayılan yaklaşım) uygulama derlenirken ana pakete çok şey eklenebilir. Lazy loading ise modülü ayrı bir parça (chunk) olarak üretir ve Router gerekli gördüğünde indirir. Bu sayede kritik yol (critical path) sadeleşir.

Hangi Senaryolarda Lazy Loading Daha Etkili?

Her şeyi lazy yapmak iyi bir hedef değildir. Kullanıcının çoğu zaman ziyaret ettiği ekranları bölmek yerine, “seyrek ziyaret edilen” veya “ağır bağımlılık taşıyan” alanları ayırmak daha verimlidir. Örneğin raporlama ekranları, yönetim bölümü, ayarlar, gelişmiş filtreleme modülleri gibi.

Rota geçişlerinde yalnızca ilgili modülün indirildiği bir Angular proje akışı örneği

Modüler Mimari: Feature Module Tasarımı ve Sınırlar

Lazy loading’in gerçek gücü, modüler mimari ile birleştiğinde ortaya çıkar. Feature module tasarımında amaç; aynı iş alanına ait bileşenleri, servisleri ve rotaları birlikte tutmak, dışarıya yalnızca gerekli yüzeyi açmaktır. Böylece hem bakım maliyeti düşer hem de bağımlılık grafiği temiz kalır.

Feature Module ve Shared Module Dengesini Kurmak

Shared module, tekrar eden UI parçalarını ve ortak direktifleri taşıyabilir; fakat “her şeyi shared’e atmak” bağımlılıkları şişirir. Lazy yüklenen bir feature module’ün, gereksiz shared bağımlılıkları yüzünden ağırlaşması initial kazancı azaltır. Ortak parçaları seçici kullanmak, UI kütüphanelerini kapsüllemek ve büyük bağımlılıkları ihtiyaç bazlı taşımak önemli.

Domain Odaklı Klasörleme Önerisi

“components/services/utils” gibi teknik klasörler büyüdükçe proje içinde gezinmeyi zorlaştırır. Domain odaklı (products, orders, reports gibi) bir düzen, hem rotalarla uyumludur hem de feature module sınırlarını daha net gösterir.

Angular Router ile Lazy Loading: loadChildren Kullanımı

Angular Router, modül bazlı lazy loading için yıllardır stabil bir yaklaşım sunar: loadChildren. Bu yapı, ilgili modül derleme sırasında ayrı bir chunk’a ayrılır ve rota tetiklendiğinde yüklenir.

Rota Yapılandırması: Temel Örnek

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./features/admin/admin.module')
      .then(m => m.AdminModule)
  },
  {
    path: 'reports',
    loadChildren: () => import('./features/reports/reports.module')
      .then(m => m.ReportsModule)
  },
  { path: '', pathMatch: 'full', redirectTo: 'home' }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {}

Bu yaklaşımın avantajı, modül sınırını açıkça göstermesidir. Dezavantaj ise kötü tasarlanmış modüllerde “devasa feature module” oluşabilmesidir. O yüzden modül içindeki rotaları da alt parçalara ayırmak (ör. reports/advanced, reports/export gibi) gerektiğinde ikinci seviye lazy loading düşünülebilir.

Guard ve Resolver’larla Birlikte Kullanım

Lazy yüklenen bir alana girmeden önce yetkilendirme (AuthGuard), rol kontrolü veya veri hazırlığı (Resolver) yapmak yaygındır. Burada dikkat edilmesi gereken, guard’ın ağır bağımlılık taşımaması ve mümkünse minimal kalmasıdır; aksi halde “modül yüklemeden önce” bile büyük kod indirebilirsin.

Uygulama derlemesinde oluşan farklı chunk dosyalarının boyut karşılaştırmasını gösteren rapor görünümü

Bundle Optimizasyonu: Initial Bundle, Cache ve Kullanıcı Deneyimi

Lazy loading’in ölçülebilir çıktısı genellikle üç alanda görülür: initial bundle küçülür, ağ istekleri daha stratejik hale gelir ve kullanıcı kritik ekrana daha hızlı ulaşır. Ancak “daha çok chunk” her zaman “daha iyi” demek değildir; çok fazla küçük chunk, aşırı istek ve overhead yaratabilir. Burada hedef, dengeyi kurmaktır.

Initial Bundle’ı Küçültürken Aşırı Bölmeyi Önlemek

Büyük bir UI kütüphanesini her modüle taşımak yerine, gerektiği yerde import etmek daha sağlıklıdır. Ayrıca büyük tablo/çizim bileşenleri, editörler veya harita kütüphaneleri gibi ağır parçaları ayrı bir feature’a almak, başlangıç paketini net şekilde rahatlatır.

Preloading Strategy ile Akıllı Isınma

Lazy loading “sonra yükle” demektir; ama kullanıcı akışını biliyorsan bazı modülleri arka planda önceden getirmek daha iyi bir deneyim sağlar. Angular’ın PreloadAllModules stratejisi basit bir seçenek olsa da, çoğu projede rota meta verileriyle seçici preloading daha verimli olur.

Modern Angular: Standalone Route’larda Lazy Loading

Modern Angular sürümlerinde standalone bileşenler ve route seviyesinde yapılandırma daha fazla öne çıktı. Bu yaklaşımda modül yerine bileşen/rota düzeyinde lazy loading yapmak mümkün. Uygulamanın mimari hedeflerine göre, feature module ile standalone yaklaşımı hibrit şekilde de kullanılabilir.

loadComponent ile Bileşen Bazlı Lazy Loading

import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: 'settings',
    loadComponent: () => import('./features/settings/settings.page')
      .then(c => c.SettingsPage)
  },
  {
    path: 'checkout',
    loadComponent: () => import('./features/checkout/checkout.page')
      .then(m => m.CheckoutPage)
  }
];

Bileşen bazlı lazy loading, özellikle “tek sayfa = tek feature” yaklaşımında temiz bir okuma sunar. Buna rağmen servis kapsamı, route provider’lar ve shared bağımlılıkların nerede tanımlandığı iyi düşünülmelidir.

Seçici Preloading için Rota Verisi Kullanımı

import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';

export class SelectivePreloadStrategy implements PreloadingStrategy {
  preload(route: Route, load: () => Observable<unknown>): Observable<unknown> {
    return route.data?.['preload'] ? load() : of(null);
  }
}

// routes örneği:
// { path: 'reports', loadChildren: () => import('./features/reports/reports.module').then(m => m.ReportsModule), data: { preload: true } }

Bu stratejiyle, kullanıcı ana sayfadayken “bir sonraki olası adım” olan modülleri arka planda hazırlayabilirsin. Böylece hem initial bundle küçük kalır hem de navigasyon anında bekleme azalır.

Tarayıcı ağ sekmesinde rota değişimi sonrası yeni bir chunk dosyasının indirildiğini gösteren kayıt

Sık Yapılan Hatalar ve Debug İpuçları

Lazy loading uygulandığında bazı problemler daha görünür hale gelir: yanlış import’lar, paylaşımlı servislerin kapsam hataları, döngüsel bağımlılıklar ve build çıktısında beklenmedik şişmeler. Bu bölümü, sahada en çok karşılaşılan durumlara göre düşün.

Döngüsel Bağımlılık ve Yanlış Shared Kullanımı

Feature module’ler birbirine doğrudan import etmeye başladığında bağımlılık grafiği karışır. Bunun sonucu olarak bir modül başka bir modülü “istemeden” eager hale getirebilir ya da chunk’lar birleşebilir. Çözüm; ortak parçaları daha küçük, amaç odaklı paketlemek ve feature’lar arası iletişimi net bir sözleşmeyle (ör. facade servisler) yönetmektir.

Network ve Bundle Analizi ile Görünürlük Kazanmak

Tarayıcı devtools ağ sekmesinde rota geçişlerinde hangi dosyaların indiğini izlemek hızlı bir kontroldür. Build raporları ve chunk boyutları ise daha yapısal içgörü sağlar. Amaç, “performans hissi” değil, ölçülebilir metriklerle karar vermektir.

Uygulama Tasarımı: Pratik Bir Kontrol Listesi

Lazy loading’i proje standartlarına bağlamak, uzun vadede ekip içi tutarlılığı artırır. Aşağıdaki maddeler, modüler mimari ve bundle optimizasyonu için iyi bir başlangıç noktasıdır.

Uygulanabilir Prensipler

  • Feature sınırlarını iş alanına göre çiz: raporlar, siparişler, ayarlar gibi.
  • Nadiren ziyaret edilen alanları lazy yap; ana akış ekranlarını gereksiz bölme.
  • Ağır kütüphaneleri (editör, grafik, harita) ayrı feature içinde konumlandır.
  • Shared içeriğini minimal tut; ortak olanı seçici şekilde paylaştır.
  • Preloading kararını kullanıcı akışına göre ver; her şeyi arka planda indirme.
  • Chunk boyutlarını düzenli takip et; sürüm ilerledikçe regresyonları yakala.

Sonuç: Lazy Loading ile Daha Hızlı Açılış, Daha Temiz Mimari

Angular lazy loading, doğru modül sınırları ve iyi rota tasarımıyla birleştiğinde yalnızca performans değil, bakım kolaylığı da sağlar. Başlangıç paketini küçültmek, kullanıcıya hızlı bir ilk yanıt vermek ve ağır alanları kontrollü şekilde yüklemek; özellikle büyüyen projelerde sürdürülebilirlik açısından kritiktir.

Bir sonraki adım olarak, kendi uygulamanda “en ağır feature”ı seçip onu lazy hale getir; ardından chunk boyutlarını, rota geçişindeki ağ isteklerini ve kullanıcı hissini birlikte değerlendir. Böylece optimizasyonu tahmine değil, veriye dayandırmış olursun.

 VERİ AKADEMİ