
Gestore globale degli errori in Vue 3: cosa intercetta app.config.errorHandler e cosa gli sfugge
- vuetelemetry
- Guide
- 8 min di lettura
app.config.errorHandler si installa in tre righe. Il lavoro vero è conoscere le sette sorgenti che copre, capire perché il suo terzo argomento diventa un codice in produzione, come onErrorCaptured può zittirlo e quali errori ti segnalerà soltanto il browser.
Un componente solleva un'eccezione dentro un watcher, sul telefono di un cliente. In sviluppo lo stesso guasto avrebbe riempito lo schermo con uno stack trace. In una build di produzione, per impostazione predefinita, Vue scrive l'errore in una console che nessuno sta guardando, e l'applicazione prosegue nello stato in cui il guasto l'ha lasciata. Un gestore globale degli errori è il pezzo che trasforma quella riga silenziosa in qualcosa che si può ricevere, contare e correggere.
Vue 3 ne fornisce uno per tutta l'applicazione: app.config.errorHandler. Il riferimento ufficiale dell'API lo descrive come un gestore globale per gli errori non intercettati che si propagano dall'interno dell'applicazione. Installarlo richiede tre righe. Il lavoro vero è sapere che cosa copre, che cosa lascia fuori e che cosa contengono i suoi argomenti una volta compilato il codice per la produzione.
Cosa intercetta app.config.errorHandler

Il gestore è una proprietà dell'istanza dell'applicazione: app.config.errorHandler = (err, instance, info) => { ... }. Va collocato tra createApp() e app.mount(). La guida di Vue è esplicita sull'ordine: tutte le configurazioni dell'applicazione vanno applicate prima di montarla. Il motivo qui si vede bene, perché il primo rendering e il setup() del componente radice vengono eseguiti entrambi al momento del montaggio.
Il riferimento elenca sette sorgenti da cui il gestore può intercettare errori: i rendering dei componenti, i gestori di eventi, gli hook del ciclo di vita, la funzione setup(), i watcher, gli hook delle direttive personalizzate e gli hook di transizione. Conviene leggere quell'elenco come un contratto. Descrive il codice che Vue chiama per conto tuo. Il codice che gira senza alcuna chiamata di Vue sopra di sé nello stack è un'altra faccenda, e ha una sezione tutta sua più sotto.
Tre argomenti e la trappola della produzione
Il gestore riceve tre argomenti. Il primo è l'errore, tipizzato unknown nella firma TypeScript, perché JavaScript permette di lanciare qualsiasi cosa: una stringa, un oggetto semplice, undefined. Verifica che sia un'istanza di Error prima di leggerne il messaggio o lo stack. Il secondo è l'istanza del componente che ha scatenato l'errore, oppure null. Il terzo, info, è una stringa specifica di Vue che indica il tipo di sorgente, per esempio in quale hook del ciclo di vita è stato lanciato l'errore.
- app.config.errorHandler riceve (err, instance, info) e si imposta prima di app.mount()
- Sette sorgenti documentate: rendering dei componenti, gestori di eventi, hook del ciclo di vita, setup(), watcher, hook delle direttive personalizzate, hook di transizione
- Nelle build di produzione info è un codice breve; la pagina Production Error Code Reference lo riporta al testo
- Comportamento predefinito: rilancio in sviluppo, scrittura in console in produzione; throwUnhandledErrorInProduction (3.5+) cambia il secondo
- Un hook onErrorCaptured() che restituisce false ferma l'errore prima del gestore globale
- Fuori da Vue: l'evento error di window per gli errori di script sincroni, unhandledrejection per le promise
Quel terzo argomento riserva una sorpresa a chi apre per la prima volta un report di produzione. Nelle build di produzione info è un codice abbreviato al posto della stringa completa. La documentazione di Vue mantiene una pagina Production Error Code Reference che riporta ogni codice di runtime al suo testo originale. Invia il valore grezzo così come arriva e fai la ricerca quando leggi il report. Una logica che confronta info con una stringa vista in sviluppo smette di corrispondere una volta compilata l'applicazione.
Sviluppo e produzione non si comportano allo stesso modo
Senza un gestore, quello che fa Vue dipende dalla build. Secondo il riferimento, il gestore predefinito rilancia gli errori in sviluppo e li registra in produzione. La metà dello sviluppo è voluta. La documentazione dice che l'errore viene lanciato, e può anche mandare in crash l'applicazione, per renderlo più evidente e far sì che venga notato e corretto.
La metà della produzione ha un effetto collaterale che conta per il monitoraggio. Un errore che viene soltanto scritto nella console non viene lanciato, e la documentazione stessa osserva che questo può impedire ai servizi di monitoraggio degli errori di catturare quelli che si verificano solo in produzione. Da Vue 3.5 esiste un interruttore per questo caso: app.config.throwUnhandledErrorInProduction, un booleano che vale false per impostazione predefinita. Impostato a true, gli errori non gestiti vengono lanciati anche in modalità produzione.
onErrorCaptured: barriere locali prima del gestore globale
Il gestore globale è l'ultima fermata. Prima di lui, qualunque componente può intercettare gli errori che arrivano dai suoi discendenti con onErrorCaptured(), o errorCaptured nella Options API. L'hook riceve gli stessi tre argomenti ed è lo strumento per una barriera d'errore: cambiare uno stato, mostrare un contenuto di ripiego. Il riferimento aggiunge un avvertimento. Lo stato di errore non deve renderizzare il contenuto originale che ha causato l'errore, altrimenti il componente finisce in un ciclo di rendering infinito.
La propagazione segue quattro regole documentate. Per impostazione predefinita, gli errori intercettati vengono comunque inviati ad app.config.errorHandler, se è definito, così da poterli segnalare in un unico punto. Se sulla catena dei genitori ci sono più hook errorCaptured, vengono invocati tutti, dal basso verso l'alto, in modo simile al bubbling degli eventi DOM. Se un hook lancia a sua volta un errore, sia quello sia l'originale vanno al gestore globale. E un hook può restituire false per fermare l'errore lì: per quell'errore non verrà invocato nessun altro hook né il gestore globale. Quest'ultima regola è di solito la spiegazione di un errore che mostra un contenuto di ripiego a schermo e non compare mai in un report.
Quello che il gestore globale non vede mai
Ora la parte fuori dal contratto. Una callback passata a setTimeout, un listener agganciato a mano con addEventListener, una catena di promise avviata in un modulo di utilità, uno script di terze parti: nessuno di questi è una delle sette sorgenti. Il browser ha due eventi per loro. Secondo MDN, l'evento error scatta su window quando una risorsa non è stata caricata o non ha potuto essere usata, per esempio quando uno script ha un errore di esecuzione, e viene generato solo per gli errori di script lanciati in modo sincrono. Una promise rifiutata senza un gestore del rifiuto, il che include un throw non intercettato dentro una funzione async, fa scattare invece unhandledrejection.
Una configurazione completa ha quindi tre ascoltatori che alimentano una sola funzione: app.config.errorHandler per il codice che Vue chiama, un listener error su window per i guasti sincroni avvenuti altrove e un listener unhandledrejection per le promise che nessuno ha intercettato. Se ne manca uno, un'intera classe di guasti resta invisibile.
Segnalare senza peggiorare le cose
Quello che la funzione fa con un errore decide se il gestore serve a qualcosa. Tienila piccola e difensiva: normalizza l'errore, allega info, la rotta corrente e la versione rilasciata, poi invialo al tuo endpoint. Racchiudi il corpo in un try e un catch, perché una funzione di segnalazione che fallisce aggiunge soltanto un secondo guasto al primo. Elimina i duplicati prima dell'invio, dato che un errore di rendering dentro una lista può ripetersi a ogni riga. E conserva una chiamata a console.error nel gestore mentre sviluppi: una volta installato il tuo, quello predefinito di Vue, che in sviluppo rilancia l'errore, non viene più eseguito.
Gli errori rispondono a una sola domanda: che cosa si è rotto. Non dicono quanto l'utente ha aspettato prima del guasto, né quale richiesta era in corso in quel momento. Quello è il territorio delle tracce, trattato in OpenTelemetry in un'app Vue. Comincia comunque dal gestore. Sono poche righe senza alcuna dipendenza, e segnala i problemi che non sapevi di dover cercare.
FAQ
Dove si imposta il gestore globale degli errori in Vue 3?
Sull'istanza dell'applicazione, tra createApp() e app.mount(): app.config.errorHandler = (err, instance, info) => { ... }. La guida di Vue chiede di applicare tutte le configurazioni dell'applicazione prima di montarla.
app.config.errorHandler intercetta tutti gli errori della pagina?
No. Il riferimento di Vue elenca sette sorgenti: rendering dei componenti, gestori di eventi, hook del ciclo di vita, setup(), watcher, hook delle direttive personalizzate e hook di transizione. Gli errori che nascono al di fuori vengono segnalati dal browser, tramite l'evento error di window per gli errori di script sincroni e tramite unhandledrejection per le promise rifiutate senza gestore.
Perché in produzione l'argomento info è un codice e non una stringa leggibile?
Nelle build di produzione Vue passa un codice abbreviato come terzo argomento di app.config.errorHandler e di onErrorCaptured. La pagina Production Error Code Reference della documentazione di Vue associa ogni codice di runtime alla sua stringa informativa originale.
Che differenza c'è tra onErrorCaptured e app.config.errorHandler?
onErrorCaptured è un hook di componente che intercetta gli errori dei componenti discendenti, ed è quindi lo strumento per un contenuto di ripiego locale. app.config.errorHandler vale per tutta l'applicazione e riceve comunque quegli errori per impostazione predefinita, a meno che un hook restituisca false per fermare la propagazione.



Una configurazione completa ha quindi tre ascoltatori che alimentano una sola funzione: app.config.errorHandler per il codice che Vue chiama, un listener error su window per i guasti sincroni avvenuti altrove e un listener unhandledrejection per le promise che nessuno ha intercettato. Se ne manca uno, un'intera classe di guasti resta invisibile.