
Bir süredir hem bir blog sitesi yapmak hem de Angular, AWS Lambda & serverless ve Azure AKS gibi teknolojileri denemek istiyordum. Bu teknolojileri denerken de blog' umun ilk yazı serisinin konusu çıkmış oldu. Bu seriye de şu dört başlık ile devam edeceğim.
- WebSite - 1: Şablon & Angular Kurulum & Component' lerin oluşturulması
- WebSite - 2: API Bağlantısı & AWS Lambda ile Yayına Alma
- Azure AKS ile .Net Core API
- Veri tabanı & MongoDB Atlas
Yazıya başlamadam önce bu uygulamının tüm kodlarına 35HaRRy/hayrihabip.com repository' sinden erişebilirsiniz.
Şablon
Bu şablonu projeye dahil ettim. Asıl halini bozmamak için "DevBlog Theme Parsed" klasörü altında bir kopyasını oluşturdum. Kopya altındaki html içeriğini de kendi bilgilerime ve ihtiyacıma göre güncelledim.
Angular Kurulum
"Setup Angular Universal on AWS Lambda from scratch" yazısı ile ilk Angular projemin kurulumuna başladım.

Bu yazıdaki adımları takip ederek veya ngx-serverless-starter projesini alarak geliştirmeye hemen başlayabilirsiniz. Bu yazıda Angular 12 ile çalışan server-side-rendering SSR özelliğine sahip uygulamının nasıl oluşturulacağını anlatıyor. Yazının devamında bahsettiği "Configure Angular Universal to support Lambda" başlığını "WebSite - 2: API Bağlantısı & AWS Lambda ile Yayına Alma" yazımda detaylandıracağım.
Component' lerin oluşturulması
Gelelim bu yazının odak noktasına. Burada kabaca şunu yaptım. Sayfaları ve sayfalarda ayrı fonksiyonları olan veya tekrar eden html' leri component' lere çevirdim. İlk olarak şablondaki "index.html" i parçalamaya başladım.
"Getting started with Angular" sayfası ile Angular geliştirmeye giriş yaptıktan sonra "Creating a component" sayfası ile de component oluşturmayı öğrenerek ilk component' im "Header" ı oluşturdum.
"Angular router", "Current Route" ve "Navigation End" yazılarından yönlendirme ile ilgili (bulunulan sayfanın ismi sayfa değiştiğinde geçilen sayfanın ismi gibi) ihtiyacım olan bilgileri aldım. Header component' indeki "route" alma şu şekilde
export class HeaderComponent implements OnInit {
currentRoute = '/';
constructor(private route: Router) {
}
ngOnInit(): void {
this.route.events.forEach(event => {
if(event instanceof NavigationEnd)
this.currentRoute = event.url;
});
}
}Tasarımla ilgili olarak koşullu "class" kullanımı için aşağıdaki 4 yol epey kullanışlı oldu. 2. yolun benzerini React' da da kullandığım için sol menüde bulunulan sayfayı işaretlemek için bu yolu kullandım.

Ve olmazsa olmaz muhteşem FontAwesome.Maalesef app.module.ts' in içerisinde şöyle pek sevimli olmayan bir tanımlama yapmak gerekiyor.
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
import { faHome, faUser, faBookmark, faLongArrowAltLeft, faLongArrowAltRight } from '@fortawesome/free-solid-svg-icons';
import { faTwitter, faGithub, faLinkedin } from '@fortawesome/free-brands-svg-icons';
export class AppModule {
constructor(private library: FaIconLibrary) {
library.addIcons(faHome, faUser, faBookmark, faLongArrowAltLeft, faLongArrowAltRight, faTwitter, faGithub, faLinkedin);
}
}Neyseki html şablonun içerisindeki kullanımı daha kolay
<fa-icon [icon]="['fab', 'twitter']" class="fa-fw"></fa-icon>BlogList (index) sayfası ve liste elemanları
Blog listesindeki post kartları için "blog-list-item" component' ini oluşturdum. Bu component' lere değer geçmek için kullanılan @Input decorator' ını Component interaction dokümanı ile keşfetmiş oldum. @Input un yardımıcı ile değer geçtiğim post kartlarını dizmek için ngFor kullandım. blog-list sayfası da şu hale gelmiş oldu.
<section class="blog-list px-3 py-5 p-md-5">
<div class="container">
<ng-template ngFor let-post [ngForOf]="posts">
<app-blog-list-item [data]="post"></app-blog-list-item>
</ng-template>
<app-blog-navigator [pager]="pager" [isForList]="true"></app-blog-navigator>
</div>
</section>
<footer class="footer text-center py-2 theme-bg-dark"></footer>Navigator
Blog listesinin ve postların altında kullanmak üzere "blog-navigator" component' ini oluşturdum. List ve post ayrımını yapabilmek için "isForList" boolean değerini ve ng-container *ngIf / ng-template yapısını kullandım. Örnek yapı şu şekilde
<ng-container *ngIf="isForList; then list else page"></ng-container>
<ng-template #list>
Liste
</ng-template>
<ng-template #page>
Sayfa
</ng-template>Blog Post Sayfası
Bütün sitede haliyle her şeyin olduğu sayfa burası. Bu sayfayı da şu şekilde böldüm.
- Başlık alanı ve içerisinde "blog-post-info" component' i ile ufak bilgilendirme alanı
- Yazı alanı ve içerisinde "blog-post-item" component' i ile yazının bileşenleri
- Son olarak yorumlar alanı ve içerisinde "disqus" component' i
blog-post-item
Bu component ile ufaktan bir şablon yapısı kurdum. Belki de biraz overengineering oldu. Angular tarafında her biri bir html elemana veya component' e denk gelecek şu yapıda json objeleri oluşturdum.
interface BlogPostItem {
id?: string;
blogPostId?: string;
component: string;
attributes?: {
[key: string]: any;
};
children?: (string | BlogPostItem)[];
sortIndex?: number;
}"component"değeri türünü, "attributes"değeri de özelliklerini ve "children" da bu component' in tag' leri içerisine gelecek diğer component' i belirtiyor. JSON değerleri ile component' leri eşlemek için container-element [ngSwitch] / *ngSwitchCase yapısını kullandım. Burada eşleşen component' in içerisinde tekrar "children" değeri ile tekrar "blog-post-item" component' ini çağırarak recursive bir yapı oluşturdum. Kod örneği şu şekilde
<ng-template ngFor let-item [ngForOf]="data">
<ng-container *ngIf="typeOf(item) == 'string'; then text else component"></ng-container>
<ng-template #text>
{{ item }}
</ng-template>
<ng-template #component>
<container-element [ngSwitch]="$any(item).component">
<a *ngSwitchCase="'a'" [class]="$any(item).attributes?.className" [href]="$any(item).attributes?.href" [target]="$any(item).attributes?.target">
<app-blog-post-item [data]="$any(item).children"></app-blog-post-item>
</a>
<img *ngSwitchCase="'img'" [class]="$any(item).attributes?.className" [src]="$any(item).attributes?.src" [alt]="$any(item).attributes?.alt">
<p *ngSwitchCase="'p'" [class]="$any(item).attributes?.className">
<app-blog-post-item [data]="$any(item).children"></app-blog-post-item>
</p>
<h1 *ngSwitchCase="'h1'" [class]="$any(item).attributes?.className">
<app-blog-post-item [data]="$any(item).children"></app-blog-post-item>
</h1>
<div *ngSwitchDefault>
{{ $any(item).component }}
</div>
</container-element>
</ng-template>
</ng-template>Tabi bu component' i oluşturmak için kullandığım 2 tane de yardımcı component kütüphanesi var. İlki paylaştığım kod örneklerini güzelleştiren ngx-highlightjs diğeri de tweet paylaşmak için kullanacağım ngx-tweet İkisi de kullanımı güzel component' ler.
Buraya kadar sitenin statik yapısını hazırlamış olduk. Bu yazım burada bitiyor ancak yazı serim devam ediyor. API Bağlantısı & AWS Lambda ile Yayına Alma yazımda görüşmek üzere.
