Personal tools
Plone e risorse JavaScript/CSS: alcuni consigli per buone prestazioni

Quando le prestazioni sono tutto...

Jun 24, 2014

Plone e risorse JavaScript/CSS: alcuni consigli per buone prestazioni

L'analisi di un sito relativamente alle prestazioni di front-end ci ha portato ad alcune considerazioni interessanti su come registrare risorse aggiuntive

Di recente siamo stati incaricati di occuparci dell'ottimizzazione di front-end di un sito Plone. Il lavoro è stato svolto sotto molti aspetti, ma nel seguito di questo articolo mi occuperò solo di uno dei recenti mantra che sta imperversando nel web relativamente all'ottimizzazione del front-end: limitare il numero di connessioni HTTP della pagina.

Perché? In poche parole: per quanto la risorsa sia piccola o grande, il problema è la connessione alla risorsa e i tempi di latenza che questa introduce.

Stato del sito

Il sito in questione ha una storia piuttosto lunga, è in produzione da anni; questo si traduce spesso in una lunga lista di prodotti aggiuntivi installati e modifiche varie effettuate al tema grafico o ai prodotti aggiuntivi stessi.

Altra caratteristica importante: è un Plone 4.2, ma la sua storia è iniziata con la versione 3.3. Si è passati attraverso un processo di migrazione della versione di Plone.

Infine: il tema grafico, anche se migrato a Plone 4, è fondamentalmente fedele al vecchio stile della realizzazione Plone 3 (in due parole: no Diazo).

Strumenti utilizzati

Per testare le prestazioni di front-end di un sito (qualunque sia la tecnologia) ci sono vari strumenti disponibili sia come estensioni dei più noti browser (YSlow, Google PageSpeed), sia come strumenti online (GTMetrix, PageSpeed Insights).
Il primo consiglio che posso darvi è: provateli tutti, e magari utilizzatene più di uno.

In forma diversa, tutti questi strumenti testano più o meno le stesse best practice, indicando un voto per ognuno dei punti verificati e fornendo delle spiegazioni sul problema rilevato e su come affrontarlo.
Solitamente alcuni punti sono considerati ad alta priorità (quindi errori gravi o accorgimenti che possono dare grandi benefici), mentre altri possono essere considerati peccati veniali.

Tornando all'argomento di questo articolo: questi strumenti avevano individuato un problema relativo all'eccessiva presenza di risorse CSS e JavaScript caricate.
Stiamo parlando di:

  • 22 CSS
  • 14 JavaScript.

ResourceRegistries

Che siano amati od odiati (varie persone nella comunità Plone pensano che la loro introduzione non sia stata una grandissima idea), ad oggi l'uso dei tool portal_css e portal_javascript è il metodo principale per permettere a prodotti aggiuntivi e temi grafici di registrare risorse.

L'uso di Diazo dovrebbe mitigare notevolmente questa necessità, ma credo che nel futuro prossimo questi due tool rimarranno comunque qualcosa con cui dovremmo convivere.

Il loro lavoro è piuttosto importante:

  1. raccolgono tutti i JavaScript/CSS registrati, rispettando un dato ordine
  2. permettono di includere delle condizioni di inclusione basate sullo stato di autenticazione dell'utente ("Restrict to authenticated users?")
  3. permettono di inserire condizioni di inclusione basate su un'espressione ("Condition")
  4. permettono di fornire i commenti di inclusione condizionali (funzionalità utilizzabile solo da Internet Explorer)
  5. permettono di specificare se la risorsa può essere messa nella cache del browser utente ("Caching allowed")
  6. effettuano una minificazione della risorsa ("Compression type", seppur non ottimale se confrontata con altri servizi)
  7. permettono di specificare il tipo di media e il rel type (solo CSS)
  8. permettono di specificare la modalità di inclusione nella pagina ("Render type" per CSS e flag "Inline rendering" per JavaScript)
  9. raggruppano più risorse per poter fornire un'unica risorsa da scaricare, riducendo le connessioni HTTP effettuate (flag "Merging allowed")
  10. Permettono di definire dei "bundle" logici di risorse ("Bundle").

Configurazione del portal_cssConfigurazione del portal_javascript

... aspettate! Ma quindi dove starebbe il problema? Non basta verificare che il flag "Merging allowed" sia sempre attivo? Fantastico!

Limiti dei ResourceRegistries

Com'era possibile che, seppur utilizzando questi due tool, le risorse richieste dalla home page del sito fossero così tante? Il raggruppamento quindi non funziona?

Risorse facilmente raggruppateIl problema nasce da alcune delle funzionalità che portal_javascript e portal_css offrono e che ho messo in evidenza nelle immagini sopra, aggiungendovi un numero in rosso. Chiamiamole "configurazioni cruciali" da qui nel seguito, e con questo intendiamo che tali configurazioni possono influire sul numero di risorse fornite.
Vediamo come.

La regola principale di questi due tool sta nel rispettare l'ordine delle risorse fornite: che siano fogli di stile o sorgenti JavaScript, l'ordine di esecuzioni conta (soprattutto per gli script, dove la questione diventa delicata).

Preview risorse perfettamente accorpateIn una situazione semplice/ideale, quando abbiamo qualcosa come cinque risorse tutte egualmente configurate, il raggruppamento funziona senza problemi.
E' sempre possibile tenere sotto controllo lo stato del raggruppamento dal tab "Merged CSS Composition" e "Merged JS compisition" dei due tool.

La logica del raggruppamento è però applicabile solo se c'è eguaglianza delle condizioni delle risorse registrate. Se, all'interno della sequenza di risorse fornita, una di queste ha una delle configurazioni cruciali differente, la sequenza viene spezzata.

Facciamo un esempio: se una risorsa è definita come non gestibile dalla cache del browser (ma lo stesso vale per tutte le altre configurazioni cruciali), questa dovrà essere inviata al browser con un header HTTP differente dalla sequenza di risorse che la precedono o che la seguono. Questo spezza la sequenza.
Ammettendo di avere una serie di 5 risorse come in figura, se la risorsa numero 3 ha una configurazione differente dalle altre quattro presenti, ResourceRegistries non potrà fare altro che generare ben 3 risorse differenti:

  • una prima risorsa contenente l'unione tra 1 e 2
  • una seconda risorsa contenente la sola 3
  • una terza risorsa contenente 4 e 5.

Risorse non ben raggruppatePreview risorse non ben accorpate

Da qui è facile capire come si possa arrivare a un alto livello di frammentazione, visto l'alto numero di configurazioni cruciali presenti e le loro possibili combinazioni.

Problemi comuni riscontrati

Dei molti possibili scenari che l'analisi sopra può avervi suggerito, vale la pena sottolinearne alcuni che reputo quantomeno interessanti.

Risorse per utenti autenticati o con condizioni

In linea di principio la restrizione delle risorse dovrebbe migliorare le performance: sembrerebbe logico supporre che sia inutile fornire a un utente anonimo un pezzo di codice JavaScript/CSS (che il suo browser interpreterà), se questo poi non verrà effettivamente utilizzato.

Eppure questo può non essere vero e può addirittura peggiorare le performance per utenti anonimi e autenticati!

Tornando alle 5 risorse dell'esempio sopra, se ammettiamo che la ricorsa C abbia il flag per la restrizione a utenti autenticati attivo, gli utenti autenticati otterranno 3 risorse differenti... e gli utenti anonimi 2.
Perché gli anonimi non ricevono una sola risorsa? Il ResourceRegistries non è così avanzato da "unire" due gruppi (AB + DE) se la risorsa che ha spezzato il flusso non viene nei fatti fornita; questo significherebbe avere configurazioni differenti potenzialmente per ogni utente.

Fate quindi attenzione: non sempre vale la pena impostare condizioni per evitare che la risorsa arrivi all'utente finale. Tenete presente sempre che la risorsa potrebbe essere compressa e accorpata con altre risorse e l'effettivo guadagno sarebbe quindi minimo, estremamente inferiore al dover scaricare una risorsa aggiuntiva (ricordate che la latenza è il nemico).

  • Se la risorsa è un CSS: forse vale la pena scrivere un CSS sempre incluso, ma con delle regole tanto specifiche da applicarsi solo ai template corretti (le classi aggiuntive aggiunte al tag BODY aiutano moltissimo).
  • Se la risorsa è un JavaScript la questione è più delicata, ma si potrebbe lavorare per interrompere in fretta l'esecuzione di codice costoso se non applicabile alla pagina corrente, o usare altri meccanismi di lazy loading.

Nessuna delle regole sopra va presa come oro colato... la valutazione dei costi e benefici dipende dalla vostra installazione e dalle risorse in esame.

Uso di "import" come "Render type"

I tutorial in rete che dicono di non usare la direttiva @import per includere i CSS si sprecano. Per ragioni che si perdono nelle nebbie del tempo, Plone 3 utilizzava massivamente questo modo di includere CSS, mentre recenti prodotti aggiuntivi e versioni di Plone preferiscono (giustamente) link.

Come già detto, il sito in esame veniva da una migrazione da Plone 3. Ci si è quindi accorti che la migrazione non aveva modificato il render type: ci siamo trovati con un uso massiccio di @import... Anche ignorando i consigli di evitare l'uso di @import, ricordate che il rendering type è una delle configurazioni cruciali!
Quindi, non mischiate import e link: l'unico effetto che otterrete è quello di spezzare la sequenza.

Risolvere i problemi del sito

Il lavoro svolto per ridurre quel grande numero di connessioni è stato prettamente manuale e di analisi:

  • si è tentato di ridurre al minimo le condizioni di inclusione
  • si è tentato di riordinare le risorse (con le dovute attenzioni) perché ci fossero due blocchi di risorse: una per tutti e una per gli autenticati
  • altre condizioni di inclusione particolari sono state valutate meglio, ed eliminate
  • sono stati modificati i render type dal misto di @import e link al solo uso di link.

Il risultato finale? Riferendosi alla sola homepage del sito sì è passati da 22 a 2 CSS, e da 14 a 2 JavaScript!

Ma un Plone "base" come si comporta?

Ci si potrebbe aspettare che i problemi del sito in esame fossero dovuti alla sua lunga storia e all'alto numero di prodotti aggiuntivi, e questo è innegabile.
Un Plone 4.3 "base", appena uscito dalla fabbrica, sarà ovviamente tutt'altro che mal configurato, giusto?

Eppure anche qui non mancano le sorprese!

CSS

Stato CSS Plone base

Come si vede nella figura precedente, ci sono 7 CSS... eppure sarebbe possibile fare di meglio!

  • Se member.css fosse incluso prima del reset.css, quest'ultimo si accorperebbe col blocco che segue
  • plone.app.jquerytools.dateinput.css delle jQueryTools usa il metodo di inclusione import e non link
  • ploneCustom.css deve sempre essere l'ultimo della sequenza... ma se non lo usate (non avete modifiche TTW attive): perché non disattivarlo?
  • RTL.css è il supporto per le lingue arabe e si attiva solo in ben determinati casi, ma verificare che venga incluso dopo plone.app.jquerytools.dateinput.css così da non interrompere il suo accorpamento
  • IEFixes.css: verificate che non rompa nessuna sequenza.

Così facendo potremmo migliorare la situazione come segue:

Stato CSS Plone base (ottimizzato)

JavaScript

La situazione dei JavaScript di un sito Plone 4.3 base è già ottimale!

Stato JavaScript Plone base

Dall'accorpamento otteniamo solo due JavaScript, col secondo blocco riservato agli utenti autenticati, ma i problemi potrebbero iniziare molto presto, non appena l'installazione dei prodotti aggiuntivi ha inizio.
Se un prodotto registra un nuovo JavaScript lo metterà probabilmente in fondo (comportamento di default) e se questo fosse ad uso di tutti gli utenti, verremmo a creare un terzo blocco. In questo caso andrebbe invece spostato alla fine del primo blocco.

Conclusione

L'ottimizzazione di front-end di un sito Plone è un'attività tutto sommato semplice, ma come avrete capito è qualcosa che va mantenuto e monitorato nel tempo.

Spero di avervi incuriosito abbastanza da farvi correre a controllare lo stato del vostro sito! Potreste individuare in fretta ampi margini di miglioramento :)

comments powered by Disqus