Frontend Angular 19: Moderne Architektur für eine komplexe App
Das Frontend von Spielen Sie das Event und eine Angular 19-Anwendung, die 27 Funktionsmodule verwaltet, unterstützt es 21 Sprachen und integriert erweiterte Bibliotheken wie Univerjs, Konva, D3.js und MapLibre. In diesem Artikel untersuchen wir die architektonischen Entscheidungen, die Machen Sie all dies möglich, ohne Einbußen bei Leistung und Wartbarkeit hinnehmen zu müssen.
Was Sie in diesem Artikel finden werden
- Eigenständige Architektur ohne NgModules
- Zustandsverwaltung mit Signals und BaseStore
- Serverseitiges Rendering mit Express
- 27 moduli lazy-loaded e design responsive
- Librerie UI avanzate: Univerjs, Konva, D3.js, MapLibre, Chart.js
- Interceptor HTTP, guard premium e accessibilità
Standalone Components: Addio NgModules
Die gesamte Anwendung nutzt eigenständige Komponenten, NgModules vollständig eliminieren. Jede Komponente deklariert ihre eigene Abhängigkeiten direkt im Dekorator, wodurch der Code expliziter wird und effektiveres Baumrütteln.
@Component({
selector: 'app-event-dashboard',
standalone: true,
imports: [
CommonModule,
TranslateModule,
ChartComponent,
ExpenseSummaryComponent,
GuestListComponent
],
templateUrl: './event-dashboard.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EventDashboardComponent {
private readonly store = inject(EventStore);
event = this.store.currentEvent;
guests = this.store.guests;
expenses = this.store.expenses;
isLoading = this.store.isLoading;
}
Der Hauptvorteil und die Klarheit: Das Betrachten eines Bauteils genau worauf es ankommt. Sie müssen nicht durch Formulare navigieren verschachtelt, um zu verstehen, was in der Vorlage verfügbar ist.
Zustandsverwaltung mit Signalen: Das BaseStore-Muster
Für die Zustandsverwaltung verwendet Play The Event ein Muster angepasst basierend auf Winkelsignale. Der BaseStore bietet allen gemeinsame Funktionalität die Anwendungsspeicher.
export abstract class BaseStore<T> {
// Stato interno con signals
protected readonly _data = signal<T | null>(null);
protected readonly _isLoading = signal(false);
protected readonly _error = signal<string | null>(null);
protected readonly _lastFetch = signal<number>(0);
// Cache TTL configurabile (default: 5 minuti)
protected readonly cacheTTL = 5 * 60 * 1000;
// Selettori pubblici (readonly)
readonly data = this._data.asReadonly();
readonly isLoading = this._isLoading.asReadonly();
readonly error = this._error.asReadonly();
// Computed signals
readonly hasData = computed(() => this._data() !== null);
readonly isStale = computed(() => {
const elapsed = Date.now() - this._lastFetch();
return elapsed > this.cacheTTL;
});
// Fetch con cache intelligente
async loadIfNeeded(): Promise<void> {
if (this.hasData() && !this.isStale()) {
return; // Dati freschi in cache, skip
}
await this.forceLoad();
}
protected abstract fetchData(): Observable<T>;
}
Warum BaseStore und nicht NgRx?
- Einfachheit: NgRx erfordert Aktionen, Reduzierer, Effekte und Selektoren. Der BaseStore ist eine einzelne Datei.
- Leistung: Die Signale stammen ursprünglich aus Angular und sind für die OnPush-Änderungserkennung optimiert.
- Integrierter Cache: TTL vermeidet redundante API-Aufrufe ohne zusätzliche Bibliotheken.
- Typisierung: Jeder Store ist dank TypeScript-Generika stark typisiert.
Serverseitiges Rendering mit Express
SSR ist entscheidend für die wahrgenommene Leistung und SEO. Spielen Sie das Event verwendet Angular Universal mit einem Express-Server, der das Rendering übernimmt serverseitig.
Der Express-Server ist nicht auf das Rendern beschränkt: Er übernimmt auch die Komprimierung, Statisches Seiten-Caching und URL-Umschreiben zur Unterstützung mehrsprachig. Öffentliche Seiten (Landing, Preise, Blog) werden vorgerendert und zwischengespeichert, während authentifizierte Seiten bei Bedarf gerendert werden.
27 Moduli Lazy-Loaded
Die Anwendung ist unterteilt in 27 Funktionsmodule, jeweils bei Bedarf per Lazy Loading geladen werden. Dies bedeutet, dass der Benutzer lädt nur den Code herunter, der für die von Ihnen besuchte Seite benötigt wird.
export const routes: Routes = [
{
path: 'events',
loadComponent: () =>
import('./features/events/event-list.component')
.then(m => m.EventListComponent),
canActivate: [authGuard]
},
{
path: 'events/:id/expenses',
loadComponent: () =>
import('./features/expenses/expense-dashboard.component')
.then(m => m.ExpenseDashboardComponent),
canActivate: [authGuard, premiumGuard('PRO')]
},
{
path: 'events/:id/seating',
loadComponent: () =>
import('./features/seating/seating-chart.component')
.then(m => m.SeatingChartComponent),
canActivate: [authGuard, premiumGuard('ENTERPRISE')]
},
// ... altri 24 moduli
];
Design Responsive: Mobile-First
L'interfaccia e progettata con approccio mobile-first e utilizza tre breakpoint principali.
/* Breakpoint */
--breakpoint-mobile: 320px; /* Smartphone */
--breakpoint-tablet: 768px; /* Tablet */
--breakpoint-desktop: 1024px; /* Desktop */
/* Typography: Montserrat + Lato */
--font-heading: 'Montserrat', sans-serif;
--font-body: 'Lato', sans-serif;
/* Layout responsive */
.event-grid {
display: grid;
grid-template-columns: 1fr; /* Mobile: 1 colonna */
}
@media (min-width: 768px) {
.event-grid {
grid-template-columns: repeat(2, 1fr); /* Tablet: 2 colonne */
}
}
@media (min-width: 1024px) {
.event-grid {
grid-template-columns: repeat(3, 1fr); /* Desktop: 3 colonne */
}
}
21 Sprachen mit TranslateService
Die Internationalisierung wird durch a gesteuert TranslateService angepasst, das 21 Sprachen unterstützt. Die Übersetzungsdateien sind JSON geordnet nach Funktionsmodulen, die bei Bedarf zusammen mit dem geladen werden entsprechendes Formular.
i18n-Herausforderungen in 21 Sprachen
Das Verwalten von 21 Sprachen bedeutet nicht nur das Übersetzen von Zeichenfolgen. Es muss berücksichtigt werden Textrichtung (LTR/RTL für Arabisch), Datumsformate und lokale Währungen, Pluralisierung (die zwischen den Sprachen enorm variiert), und die variable Länge der Texte, die sich auf das Layout auswirkt.
Librerie UI Avanzate
Play The Event integriert fünf spezialisierte UI-Bibliotheken, jeweils für einen konkreten Anwendungsfall.
Librerie Integrate
- Universitäten: Tabellenkalkulation im Browser für gemeinsame Budgets und Tabellenkalkulationen
- Konva: 2D-Canvas für den Grundriss- und Tischlayout-Editor
- D3.js: Diagramme von Teilnehmerbeziehungen und komplexe Datenvisualisierungen
- MapLibre GL: Interaktive Karten für Reiserouten und Veranstaltungsorte
- Chart.js: Diagramme für Analysen, statistische Dashboards und Finanzberichte
HTTP Interceptors
Zwei HTTP-Interceptoren wickeln API-Aufrufe flächendeckend ab.
Auth Interceptor mit Token-Aktualisierung
Der Authentifizierungs-Interceptor fügt jeder Anfrage automatisch das JWT-Token hinzu. Wenn das Token abläuft (401-Antwort), versucht der Abfangjäger a automatische Aktualisierung Wiederholen Sie den Vorgang mithilfe des Aktualisierungstokens ursprüngliche Anfrage mit dem neuen Token und, falls auch die Aktualisierung fehlschlägt, leitet zur Anmeldeseite weiter.
Error Interceptor
Der Fehler-Interceptor zentralisiert die HTTP-Fehlerbehandlung: show Toastbenachrichtigungen für Clientfehler (4xx), Fehlerseiten für Fehler Server (5xx) und Protokollfehler zum Debuggen.
Premium Feature Guards
Einige Funktionen stehen nur Abonnementbenutzern zur Verfügung PRO oder ENTERPRISE. DER sehen Überprüfen Sie den Füllstand Abonnement abschließen, bevor Sie den Zugriff auf die Route zulassen.
export function premiumGuard(requiredLevel: 'PRO' | 'ENTERPRISE') {
return () => {
const auth = inject(AuthStore);
const router = inject(Router);
const userLevel = auth.subscriptionLevel();
const levels = { 'BASIC': 0, 'PRO': 1, 'ENTERPRISE': 2 };
if (levels[userLevel] >= levels[requiredLevel]) {
return true;
}
return router.createUrlTree(['/pricing'], {
queryParams: { upgrade: requiredLevel }
});
};
}
Accessibilita WCAG 2.1 AA
Barrierefreiheit ist keine späte Ergänzung: Sie ist in den Prozess integriert der Entwicklung. Jede Komponente wird auf WCAG 2.1 AA-Konformität getestet.
Barrierefreiheitspraktiken
- Mindestfarbkontrast 4,5:1 für normalen Text, 3:1 für großen Text
- Vollständige Tastaturnavigation mit sichtbaren Fokussen
- ARIA-Attribute für benutzerdefinierte interaktive Komponenten
- Screenreader-Anzeigen für dynamische Aktien
- Unterstützung
prefers-reduced-motionum Animationen zu reduzieren - Automatisierte Tests mit Axtkern in der CI-Pipeline
Testing: Jest, Playwright e axe-core
Die Teststrategie ist in drei Ebenen unterteilt.
Unit e Component Test
- Scherz: Unit-Tests für Dienste, Pipes und Geschäftslogik
- Komponententests mit TestBed für Angular-Komponenten
- Schein-HTTP-Dienste für isolierte Tests
E2E e Accessibilita
- Playwright: Test end-to-end cross-browser (Chrome, Firefox, Safari)
- Axtkern: Automatische Barrierefreiheitstests integriert in E2E-Tests
- Visuelle Regressionstests für kritische Komponenten
Punti Chiave
- Eigenständige Komponenten für maximale Klarheit und effektives Baumrütteln
- BaseStore mit Signalen und TTL-Cache für reaktionsfähigen und performanten Zustand
- SSR mit Express für SEO und wahrgenommene Leistung
- 27 Lazy-Loaded-Module für optimale Bundle-Größe
- 5 librerie UI specializzate integrate armoniosamente
- HTTP-Interceptor für automatische Authentifizierung und zentralisierte Fehlerbehandlung
- Testing a tre livelli: unit, E2E e accessibilità
Der Frontend-Quellcode ist verfügbar unter GitHub. Besuchen www.playtheevent.com um das Endergebnis zu sehen.







