Un Resource Manager molto fluent per migliorare le performance

Ormai, al giorno d’oggi, se non si sviluppa un qualcosa che offra un utilizzo Fluent allora vuol dire che il codice non è figo :D. Ovviamene in Dexter non potevamo rimanere indietro, per cui, per seguire questa “moda”, ho deciso di sviluppare un Resource Manager per effettuare il combine ed il minifier dei javascript e dei css.

Proprio osservando la mia skin mi rendo conto di avere un numero piuttosto alto di includes al suo interno (css del sito, css del codehightlither, shadowbox, etc), e la stessa cosa vale per i js (in realtà sono anche di più dei css). Già in passato (vedi qui) avevo parlato dei vantaggi che si hanno nel ridurre al minimo le chiamate del browser verso il client, ma purtroppo l’approccio mostrato in quel post non era utilizzabile in ASP.NET MVC.

Il goal che mi ero proposto era creare un qualcosa di molto semplice che permettesse di accorpare il numero di files js/css in un unico file e di restituire quest’ultimo effettuando un minify (quindi rimuovendo gli spazi inutili), mettendo in cache il riusultato, con dipendenza sui files in uso.

Ovviamente mi sono dovuto munire di alcuni strumenti che mi rendessero più agevoli alcune operazioni come il minify. Su consiglio di Alessandro, ho deciso di appoggiarmi alla libreria offerta da Yahoo, che svolge il suo lavoro egregiamente. Per il resto, con un paio di handlers, alcune interfacce, una classe ed alcuni extension methods ho raggiunto questo risultato:

<%= ResourceManager.Js()
        .Combine()
        .Minify()
        .Add(SkinJs("codeHighlither/shCore.js"))
        .Add(SkinJs("codeHighlither/shBrushCSharp.js"))
        .Add(SkinJs("codeHighlither/shBrushXml.js"))
        .Add(SkinJs("XFNHighlighter.js"))
        .Add(SkinJs("jquery.cookie.js"))
        .Add(SkinJs("jquery.highlight-3.yui.js"))
        .Add(SkinJs("customFunction.js"))
        .Add(SkinJs("xVal.jquery.validate.js"))
        .Add(SkinJs("shadowbox.js"))
        .Render()
%>

<%= ResourceManager.Css()
        .Combine()
        .Minify()
        .Add(SkinCss("Site.css"))
        .Add(SkinCss("XFNHighlighter.css"))
        .Add(SkinCss("shCore.css"))
        .Add(SkinCss("shThemeDefault.css"))
        .Add(SkinCss("shadowbox.css"))
        .Add(SkinCss("CodeSnippets.css"))
        .Render()
%>

A pagina renderizzata si ha una chiamata all’handler in cui i files da comprimere vengono passati in querystring (ho dovuto comprimere il risultato per evitare di eccedere nella lunghezza massima utilizzabile da una querystring), che svolgerà il resto del lavoro.

La cosa che mi è piaciuta di più è che, con questa classe, anche se non si vuole effettuare né il combine né il minify, quindi renderizzare i semplici tag per i css e js come nelle normali pagine, il risultato è più comodo e veloce; di fatto il seguente snippet:

<%= ResourceManager.Js()
        .DoNotCombine()
        .DoNotMinify()
        .Add(SkinJs("codeHighlither/shCore.js"))
        .Add(SkinJs("codeHighlither/shBrushCSharp.js"))
        .Render()
%>

renderizza il seguente markup:

<script src="/codeHighlither/shCore.js" type="text/javascript"></script>
<script src="/codeHighlither/shBrushCSharp.js" type="text/javascript"></script>

Giusto per aggiungere un po’ di numeri al post, nella mia skin sono riuscito ad accorpare 9 files javascript in un un’unico file, riducendo il peso da 79kb a 60kb; inoltre, accorpando 6 files css, ho ottenuto una riduzione quasi del 30% (53kb contro i 38kb del minify).

Un paio di screenshot per mostrare il fantaggio tratto da tale approccio.

notCombined

Combined

A breve il codice sorgente sia dell’interfaccia fluent che degli httphandler per il minify.

Stay tuned.


Comments