Angular Senza Cerimonia
Ho usato Angular fin dalle sue prime versioni. Nel tempo ho visto il framework accumularsi di cerimonia — NgModules, catene di provider complesse, librerie di gestione dello stato che richiedono la loro propria curva di apprendimento solo per memorizzare un semplice flag. Per la maggior parte delle applicazioni, è troppo.
Il frontend di RAD-System è il mio tentativo di usare Angular moderno nel modo in cui era destinato a essere usato: snello, modulare e senza dipendenze da librerie che risolvono problemi che non ho. Il codice è su GitHub.
1. Configurazione Runtime: Costruisci Una Volta, Deploya Ovunque
Questo è uno dei pattern di cui sono più orgoglioso in questo sistema. I file di ambiente incorporati di Angular vengono compilati nella build — se hai bisogno di cambiare l'URL dell'API dopo la build, ribuild. In una configurazione multi-ambiente (sviluppo, staging, produzione) questo non è accettabile.
La mia soluzione: carica app-config.json prima che l'applicazione si avvii. Lo stesso bundle compilato si deploya in qualsiasi ambiente. Cambi gli ambienti scambiando un file JSON.
// Carica la configurazione prima dell'avvio
const loadConfig = async () => {
try {
const dt = new Date().getMilliseconds();
// Cache-busting per garantire config fresco
const response = await fetch(`./assets/config/app-config.json?ver=${dt}`);
const config = await response.json();
// Memorizza config sincronamente per accesso globale
StoreService.setConfig(config);
bootstrapApplication(AppComponent, {
...appConfig,
providers: [provideZoneChangeDetection(), ...appConfig.providers],
});
} catch (error) {
console.error("Application cannot start without configuration:", error);
}
};
loadConfig();
2. Gestione dello Stato Senza NgRx: StoreService
Ho provato NgRx su diversi progetti. Per la maggior parte delle applicazioni la sua complessità è sproporzionata al problema che risolve. Ho costruito StoreService come alternativa leggera — supportato da BehaviorSubject, usando browser storage per la persistenza, e accessibile come classe statica ovunque nell'applicazione incluso al di fuori del sistema DI di Angular.
@Injectable({ providedIn: "root" })
export abstract class StoreService {
private static PREFIX: string = "RAD.";
// L'accesso statico consente l'utilizzo al di fuori del DI di Angular (ad es., nelle funzioni)
static set(key: string, value: any, persistent: boolean = false) {
const storage = persistent ? localStorage : sessionStorage;
storage.setItem(this.PREFIX + key, value);
}
static getApiUrl(): string {
return this.CONFIG.apiUrl;
}
}
Per le applicazioni che hanno veramente bisogno di uno stato reattivo su molti componenti, NgRx o Signals sono la risposta giusta. Per il restante 80% dei casi, questo è sufficiente e non costa nulla da capire.
3. Gestione Centralizzata dell'API
Ogni chiamata HTTP nell'applicazione passa attraverso un singolo ApiService. Aggiunge automaticamente l'URL API runtime da StoreService, imposta gli intestazioni standard (Authorization, Content-Type), e centralizza la gestione degli errori. Nessuna chiamata HttpClient sparsa nei componenti — un punto di ingresso, un luogo per cambiare il comportamento globalmente.
4. Componenti Costruiti per Essere Riutilizzati
Il sistema include una serie di componenti funzionali pronti all'uso in src/app/Features:
- Dynamic Menu — costruisce l'albero di navigazione al runtime, filtrando gli elementi in base al ruolo dell'utente (ACL) e alla configurazione corrente. Aggiungi un nuovo modulo, aggiungi una voce di menu nella configurazione — nessun cambio di codice.
- Token Status — un watchdog della sessione che mostra la validità del JWT e avvisa l'utente prima che il suo token scada. Mi stanco di vedere gli utenti disconnessi a metà lavoro senza preavviso.
- Lang Picker — cambio istantaneo della lingua dell'interfaccia usando
Transloco. Aggiungi un file di traduzione, il picker si aggiorna automaticamente.