Angular Standalone Components (SC) Genel Bakış

Erman Enginler
HAVELSAN
Published in
5 min readMar 24, 2023
Image by rawpixel.com on Freepik

Merhaba,
Angular 15'in yayınlanması ve kullanılmaya başlamasıyla birlikte artık Standalone Component için tam olarak destek gelmiş oldu. Peki nedir bu standalone componentlar ve ne için kullanacağız?

Çok Uzun Özet Geç!
Standalone Componentlarla birlikte artık NgModule ihtiyacı kalmadı mı? Bir Angular Library içerisinde standalone component nasıl tanımlanır? Nasıl expose edilir ve proje içerisinde nasıl tüketilir? Bunları göreceğiz.

Standart bir Angular projesinde tüm componentlar bir NgModule’e bağlıdır. Bu modüllerde de bağlı componentlar için providerlar ve importlar yer almaktadır. Ayrıca encapsulation için de bu modüller kullanılır. Bir modülden neyi export ederseniz bu modülü import eden diğer modül de sadece export edilen nesneleri kullanır fakat bu durum deep import (tavsiye edilmez) yapılarak aşılabilir. Bu duruma ileride değineceğim.

Standart Basit NgModule Şeması

Yukarıdaki şemaya baktığımızda NgModül’ün kullanacağı diğer modülleri import ettiğini; component, directive ve pipeları declare ettiğini ve bir component ile directive’i export ettiğini görüyoruz.

Standart Basit Standalone Component Şeması

Yukarıdaki şemaya baktığımızda da bir SC’nin (Standalone Component) ihtiyaç duyduğu diğer nesneleri import ederek kullanabildiğini görüyoruz. Kısaca söylemek gerekirse SC, ngModül katmanını aradan çıkarmış oluyor.

Angular’ın core geliştircilerinden biri olan Igor Minar 2021 yılında bir Tweet serisinde ngModüllerle ilgili olarak ilk başta AngularJS’in modül sisteminden esinlenerek işleri kolaylaştırmak için yaratılmış olsa da uzun vadede işleri daha da kompleksleştirdiğinden bahsetmiştir. 2016'da bir konferansta bu durumdan bahsetmiş ve ngModüllerin bir gün opsiyonel olacağını umduğunu belirtmiştir.

Standalone Componentlar sayesinde NgModül katmanı opsiyonel hale gelmiştir.Peki ngModül gerçekten gerekli mi?

NgNodüller aslında sadece 3 tip nesneyi (component, pipe, directive) enkapsüle etmeye yarayan yapılardır. Bunun dışında componentların depend ettiği diğer modülleri import etme ve servisleri provide etme işlevleri vardır.

Modüle import edilen diğer modüller de aslında kendi nesnelerini export etmektedir. Bu durumda araya bir modül koymadan da bu nesneler SC sayesinde kullanılacak component içine direk import edilebilir.

Servislerin durumu özeldir. Injectable oldukları için bir modüle ihtiyaç duymadan da componentlarda provide edilerek ya da dependency injection ile kullanılabilir. Peki modüldeki ya da AppModule’deki providelar ne olacak? Servislerin içinde Injectable dekoratörü içerisinde bulunan providedIn property’si ile bu servislerin providelarını ilgili modüllere çekebiliriz. Örnek: providedIn:root ile bir servisin tüm projede provide edilmesini sağlayabiliriz.

Şimdi standalone component’ın Angular projemizde nasıl bir library içerisinden kullanılacağını inceleyelim.

Örnek proje kaynak dosyalarına GitHub üzerinden ulaşabilirsiniz.

ng generate library my-lib

komutu ile yeni bir library oluşturuyoruz.

Bu oluşturduğumuz library’de src/lib klasöründe my-lib.module.ts dosyasını siliyoruz ve public-api.ts ‘den de module için olan export satırını siliyoruz. my-lib.component.ts dosyasının içinde @Component dekoratörünün içine standalone:true parametresi ekliyoruz. Daha sonra

ng build my-lib

komutu ile library’mizi build ediyoruz.

Standalone Component içeren basit bir Library scaffoldu

lib klasörümüzün içi ve my-lib.component.ts dosyasının içi yukarıdaki görseldeki gibi olmalıdır.

Peki standalone olan bu my-lib componentini nasıl import edip kullanacağız?

Standalone Componentlar sadece başka Standalone Componentların (standalone:true olanlar) içine direk olarak import edilip kullanılabilir. NgModül yapısında olan compoenentlarda kullanılması için ilgili modülüne import edilmesi gereklidir.

Biz, örneğimizde app.component içerisine my-lib ‘den MyLibComponent ‘ı import edip kullanacağız.

Öncelikle app.component’ı da standalone haline getirmemiz gerekiyor. Bunun için app.component içerisinde @Component dekoratörünün içine standalone:true parametresi ekliyoruz. Yine aynı dekoratör içerisine imports parametresi ekleyip daha önce app.module.ts de kullandığımız importları ekliyoruz ve importların en sonuna MyLibComponent ‘ı import ediyoruz. MyLibComponent library içerisinde olduğu ve public-api.ts ile export edildiği için import {MyLibComponent} from 'my-lib' şeklinde import edilebiliyor. public-api.ts ‘den sadece export edilen dosyalar kullanılabildiği için (barrel-file) encapsulation işini (servisler de dahil) gerçekleştirmiş oluyor.

import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { MyLibComponent } from 'my-lib';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
standalone: true,
imports: [CommonModule, MyLibComponent],

})
export class AppComponent {}

Yukarıdaki kod bloğu app.component.ts içini göstermektedir. Bu şekilde artık bir library’de bulunan standalone component’ı ngModül olmadan başka bir component içerisinden rahatlıkla kullanabiliyoruz.

AppComponent’ı standalone yaptım projem artık compile olmuyor.
AppComponent’ı standalone yaptığınızda projeniz doğal olarak compile olamayacaktır çünkü main.ts’de bootstrap kısmında app.module’ü aramaktadır.
main.ts içerisini aşağıdaki şekilde değiştirdiğinizde projeniz tekrar çalışır hale gelecektir.

import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';

bootstrapApplication(AppComponent);

Soru: Standalone Componentlar ile NgModule yapısını aynı anda kullanabilir miyim?

Cevap: Evet. SC kullanmak için bütün yapıyı değiştirmeye gerek yok. İhtiyaç duyulan yerlerde SC kullanılabilir. Var olan projedeki NgModule yapısı zamana yayılarak migrate edilebilir.

Soru: NgModule’den SC’ye kolay migrate edebileceğim bir yapı var mı?

Cevap: Öncelikle sıfır bir projeye başlanacaksa ngModule kullanmadan da başlanabilir ve SC’ler ile ilerlenebilir. Var olan karmaşık bir proje varsa öncelikle NgModule yapıları S.C.A.M yapısına geçirilmelidir.
S.C.A.M yapısında her bir komponent için bir modül tanımlanmaktadır ve böylece modüllerin paylaşımı daha kolay olmaktadır. SCAM yapısına geçirilen bir modül-komponent yapısından da Standalone Component’a geçmek için sadece modüldeki importları component içerisine taşıyıp NgModule’ü silmek kalıyor.

Bu makalede Standalone Componentların yapısına kısaca değindim.
Standalone Componentların avantajlarına değinecek olursak

  • Eğer bir modül birden çok komponent deklare ediyorsa modülün hangi import’u hangi komponent için yaptığı belli olmayan karmaşık bir yapıya dönüşüyor. Bir komponentin hangi nesnelere (component, directive, pipe) dependency’si olduğu SC sayesinde daha rahat görülebiliyor.
  • Bir komponent içerisinde kullanılacak diğer komponentı import etmek daha kolay ve örneğin sadece 1 komponent kullanmak için bütün bir modülü import etmek gerekmiyor.
  • SC kullanımı implicit import olmamasını sağlıyor. Bu anlamda da bazı noktalarda tree-shaking ihtiyacı doğmuyor çünkü component, ihtiyacı olduğu nesneleri direk olarak component içerisinde belirtmiş oluyor.
  • Daha az modül olması daha az dosya anlamına geliyor. Bu da hem klasör yapısının daha düzenli olmasını sağlıyor hem de bundle size’a etki ediyor.

Daha detaylı bilgi için: Angular — Getting started with standalone components

Örnek Github projesine buradan erişebilirsiniz.

İyi çalışmalar keyifli okumalar
ermaneng

--

--