Performance
Regressioni di performance in CI: il controllo che costa 70 ms
Settanta file di build, 172 KB di JavaScript compresso e 36 KB di CSS: il controllo di budget li legge in 61-77 ms e blocca il merge quando il peso cresce.
In sintesi
- Un budget di peso in CI costa 61-77 ms su 70 file: si può mettere su ogni push.
- Il JavaScript della build misura 511 KB non compressi e 172 KB dopo gzip.
- Due chunk superano i 44 KB compressi: sono i primi da guardare quando il totale cresce.
- Il budget sul peso non misura il tempo di esecuzione: una regressione di CPU passa lo stesso.
Una regressione di performance si blocca in CI con un budget sul peso degli asset, non con un test Lighthouse a ogni push. Su 70 file di build il controllo legge tutto in 61-77 ms e fallisce se il JavaScript compresso supera la soglia. La build attuale misura 172 KB di JavaScript gzip e 36 KB di CSS.
Il budget, con i numeri di oggi
| Voce | Misurato | Soglia | Cosa blocca |
|---|---|---|---|
| JavaScript totale, gzip | 172 KB | 200 KB | un import pesante in più |
| CSS totale, gzip | 36 KB | 50 KB | un tema o un framework intero |
| Chunk singolo, gzip | 44 KB | 50 KB | una libreria che finisce nel chunk vendor |
| Tempo del controllo | 61-77 ms | 2 s | nulla: è solo il costo del gate |
Il budget su 200 KB lascia 28 KB di margine, cioè circa un componente pesante o due piccoli. Non è una soglia arbitraria: è il numero misurato più il margine che vuoi concedere alla prossima feature. Un budget senza margine si rompe alla prima settimana e viene disattivato.
Il controllo
const fs = require("fs"), zlib = require("zlib"), path = require("path");
const walk = (d, acc = []) => {
for (const e of fs.readdirSync(d, { withFileTypes: true })) {
const f = path.join(d, e.name);
e.isDirectory() ? walk(f, acc) : acc.push(f);
}
return acc;
};
let js = 0, worst = 0;
for (const f of walk("client/dist")) {
const gz = zlib.gzipSync(fs.readFileSync(f)).length;
if (f.endsWith(".js")) { js += gz; worst = Math.max(worst, gz); }
}
console.log(Math.round(js / 1024) + " KB JS gzip, chunk peggiore " + Math.round(worst / 1024) + " KB");
if (js > 200 * 1024 || worst > 50 * 1024) process.exit(1);
Lo script richiede solo Node e la cartella client/dist già costruita: nessuna dipendenza, nessun browser. Esce con codice 1 quando supera una soglia, e in una pipeline questo ferma il merge. Mettilo dopo il passo di build e prima del deploy: un budget che gira sul codice vecchio non serve.
Cosa il budget non vede
Il peso non è il tempo: un chunk da 44 KB può diventare tre volte più lento senza cambiare dimensione, se cambia il lavoro che fa al primo render. Il budget intercetta la causa più comune, la dipendenza in più, e lascia passare la regressione più insidiosa, quella algoritmica. Per quella servono i dati di campo o una traccia in CI, che costano minuti invece di millisecondi.
Il limite da dichiarare
I 172 KB sono la somma di tutti i chunk, non quello che una singola pagina scarica: il caricamento reale dipende dal routing e dal code splitting. Un budget per rotta è più preciso e più difficile da mantenere, perché richiede di sapere quali chunk carica ogni pagina. In più gzip non è brotli: con brotli i numeri assoluti scendono, il confronto tra due build resta valido.
Dove continuare
Il catalogo EneUI indicizza 111.985 componenti, 1.556 blocchi e il record splite, un componente che si installa con le sue dipendenze e si vede subito nel budget. Per le soglie in pipeline leggi Lighthouse CI con soglie, per il peso delle librerie UI bundle size delle UI library, per caricare meno codice code splitting per route, e per il confronto tra architetture framework frontend a confronto.
Domande frequenti
Meglio un budget sul peso o Lighthouse CI?
Il budget sul peso costa millisecondi e intercetta la causa più comune, una dipendenza in più. Lighthouse CI costa minuti e vede anche il tempo, ma è rumoroso su runner condivisi. Insieme coprono cause diverse.
Quanto margine lascio sopra il valore misurato?
Tra il 10% e il 20%, abbastanza per una feature piccola e non abbastanza per una libreria intera. Un budget senza margine fallisce su ogni modifica e viene disattivato.
Il budget deve essere per file o per pagina?
Per pagina è più preciso, perché misura quello che l'utente scarica. Per file è più semplice e stabile: si calcola sulla build senza sapere quali chunk carica il routing.
Gzip o brotli nel budget?
Quello che serve davvero ai client. Brotli comprime meglio e dà numeri più bassi; l'importante è usare lo stesso algoritmo per la soglia e per la misura, altrimenti il confronto tra build non vale.
Come evito che il budget blocchi un hotfix urgente?
Con un'eccezione esplicita e registrata, non disattivando il controllo. Alza la soglia in una pull request a parte, con la data e il motivo, e riportala giù dopo il rilascio.