Especialização em Front-End com Angular • Demonstrações Práticas Compiláveis


💻 Código de Exemplo 01 — Standalone Architecture e Bootstrap com Angular 18+

Este exemplo demonstra a criação e inicialização canônica de uma aplicação corporativa em Angular 18/19 baseada 100% em Standalone Architecture (eliminando a necessidade de NgModule), com configuração moderna de providers via bootstrapApplication.

1. Ponto de Entrada da Aplicação: src/main.ts

// src/main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter, withComponentInputBinding } from '@angular/router';
import { provideHttpClient, withFetch } from '@angular/common/http';
import { AppComponent } from './app/app.component';
import { appRoutes } from './app/app.routes';

bootstrapApplication(AppComponent, {
  providers: [
    // Roteamento moderno com injeção de parâmetros direto nas inputs
    provideRouter(appRoutes, withComponentInputBinding()),
    // Cliente HTTP nativo com API Fetch para alta performance e suporte a SSR
    provideHttpClient(withFetch())
  ]
}).catch((err) => console.error('[Bootstrap Error] Falha ao inicializar o Angular:', err));

2. Componente Raiz Standalone: src/app/app.component.ts

// src/app/app.component.ts
import { Component, signal } from '@angular/core';
import { RouterOutlet, RouterLink } from '@angular/router';
import { CommonModule } from '@angular/common';

interface ClusterNode {
  id: string;
  name: string;
  region: string;
  status: 'HEALTHY' | 'DEGRADED' | 'DOWN';
  activePods: number;
}

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, RouterOutlet, RouterLink],
  template: `
    <div class="min-h-screen bg-slate-100 flex flex-col font-sans">
      <!-- Barra Superior de Navegação -->
      <header class="bg-white border-b px-6 py-4 flex items-center justify-between shadow-sm">
        <div class="flex items-center gap-3">
          <span class="w-3.5 h-3.5 rounded-full bg-red-600 animate-pulse"></span>
          <h1 class="font-extrabold text-xl text-slate-900 tracking-tight">
            Angular 18 Enterprise • Standalone Architecture
          </h1>
        </div>
        <div class="flex items-center gap-2">
          <span class="text-xs px-2.5 py-1 bg-slate-100 rounded-md font-mono text-slate-600">
            Ambiente: <strong>Production-Edge</strong>
          </span>
          <button
            type="button"
            (click)="simulateHealthCheck()"
            class="text-xs font-semibold px-3 py-1.5 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors"
          >
            Executar Health Check
          </button>
        </div>
      </header>

      <!-- Painel de Telemetria do Cluster -->
      <main class="flex-1 max-w-5xl w-full mx-auto p-6 space-y-6">
        <div class="bg-white border rounded-2xl p-6 shadow-sm space-y-4">
          <div class="flex items-center justify-between">
            <div>
              <h2 class="text-lg font-bold text-slate-800">Cluster de Microsserviços</h2>
              <p class="text-xs text-slate-500">Arquitetura sem NgModule compilada via esbuild/Vite</p>
            </div>
            <span class="text-xs font-bold text-slate-400 font-mono">
              Total de Nós: {{ nodes().length }}
            </span>
          </div>

          <!-- Grade de Nós -->
          <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
            <div
              *ngFor="let node of nodes()"
              class="border rounded-xl p-4 bg-slate-50 space-y-2 hover:border-slate-300 transition-colors"
            >
              <div class="flex items-center justify-between">
                <span class="text-xs font-mono font-bold text-slate-700">{{ node.id }}</span>
                <span
                  class="text-[10px] font-extrabold uppercase px-2 py-0.5 rounded-full"
                  [ngClass]="{
                    'bg-emerald-100 text-emerald-800': node.status === 'HEALTHY',
                    'bg-amber-100 text-amber-800': node.status === 'DEGRADED',
                    'bg-red-100 text-red-800': node.status === 'DOWN'
                  }"
                >
                  {{ node.status }}
                </span>
              </div>
              <h3 class="font-bold text-slate-900 text-sm">{{ node.name }}</h3>
              <div class="flex justify-between items-center text-xs text-slate-500 pt-1 border-t">
                <span>Região: {{ node.region }}</span>
                <span class="font-mono font-bold text-slate-700">{{ node.activePods }} pods</span>
              </div>
            </div>
          </div>
        </div>

        <router-outlet></router-outlet>
      </main>
    </div>
  `
})
export class AppComponent {
  // Estado local gerenciado com Angular Signals nativo
  nodes = signal<ClusterNode[]>([
    { id: 'node-us-01', name: 'Auth & Security Gateway', region: 'us-east-1', status: 'HEALTHY', activePods: 24 },
    { id: 'node-sa-02', name: 'Transactional Payment Core', region: 'sa-east-1', status: 'HEALTHY', activePods: 42 },
    { id: 'node-eu-03', name: 'Audit & Compliance Collector', region: 'eu-west-1', status: 'DEGRADED', activePods: 18 }
  ]);

  simulateHealthCheck(): void {
    const updated = this.nodes().map((node) => ({
      ...node,
      status: Math.random() > 0.15 ? ('HEALTHY' as const) : ('DEGRADED' as const),
      activePods: Math.floor(Math.random() * 30) + 15
    }));
    this.nodes.set(updated);
  }
}

3. Rotas Básicas: src/app/app.routes.ts

// src/app/app.routes.ts
import { Routes } from '@angular/router';

export const appRoutes: Routes = [
  {
    path: '',
    pathMatch: 'full',
    redirectTo: 'overview'
  },
  {
    path: 'overview',
    loadComponent: () =>
      import('./pages/overview/overview.component').then((m) => m.OverviewComponent)
  }
];

🖥️ Saída / Comportamento Esperado

Ao inicializar via Angular CLI (ng serve):

Application bundle generation complete. [0.428 seconds]
Watch mode enabled. Ready for changes...
➜  Local:   http://localhost:4200/

Estado Inicial:
Header: "Angular 18 Enterprise • Standalone Architecture"
Painel com 3 cards:
Card 1: node-us-01 | [HEALTHY] verde | 24 pods
Card 2: node-sa-02 | [HEALTHY] verde | 42 pods
Card 3: node-eu-03 | [DEGRADED] âmbar | 18 pods

Ao clicar no botão "Executar Health Check":
O método simulateHealthCheck() muta o signal nodes.set(...).
Os status e números de pods são atualizados reativamente sem necessidade de Zone.js forçar verificação pesada.

🔍 Destaques da Implementação

  1. standalone: true como Padrão: Não há arquivos app.module.ts; cada componente declara suas dependências pontuais em imports: [...].
  2. bootstrapApplication: Inicializa o runtime com providers funcionais (provideRouter, provideHttpClient), diminuindo o bundle inicial do esbuild.
  3. withFetch(): Ativa a API Fetch nativa do navegador no HttpClient, garantindo compatibilidade imediata com Cloudflare Workers e Node SSR.