Optimering af Javascript og CSS
aug 16
Udvikling cache, Closure Compiler, css, javascript, jquery, minify 3 Comments
Jeg er forholdsvis flitting bruger af bookmark servicen Delicious.com, og det hænder da også at jeg rent faktisk kommer tilbage til nogle af de links jeg er faldet over i løbet af tiden … i dag var sådan en dag, og emnet handler om en måde hvorpå man kan optimere sin sides brug af Javascript og CSS. Følgende post kræver en stor tak og 100% kredit til Niels Leenheer.
Flere filer = flere requests = ventetid =
Jeg synes at støde ind i dette scenarie mere og mere på det sidste, og som billederne herunder viser, skal grunden meget ofte findes i brugen af JQuery og ikke mindst plugins dertil.
Følgende eksempel screenshots er alle taget fra en lokal version af sitet www.usgreencardoffice.com, som er et projekt jeg har været en del af gennem det sidste års tid. Som det ses benytter vi en del forskellige JQuery plugins (hvilket, som sagt ikke længere er unormalt), men fordelen ved at kunne hente og lave disse enekltstående plugins så let, kan hurigt gå hen og blive en ulempe, eller i hvert fald mindre fordelagtigt.
På et tidspunkt, vil man komme op på så mange filer, at ens browser ikke længere kan hente dem alle på én gang, hvorfor den besøgende bliver nød til at hente dem lidt efter lidt, for endelig at kunne se resultatet — Ventetid!
Følgende screenshots er alle taget efter at have tømt min browsers cache (hvilket undre mig lidt, at Firebug stadig siger 22.3 KB from cache?!), og er altså resultater ved første besøge på sitet.
Javascripts (172.9 KB — 2.32 sek.)
CSS (10.9 KB — 637 msek.)
Optimering
Tricket til at komme ovenstående til livs, er faktisk rimelig simpelt, men kan gøres på flere planer. Flere og flere plugins (foruden JQuery biblioteket selv), kommer i en “minifyed” version, som jeg klart vil anbefale at benytte i produktion frem for den “originale kildekode”. Med “minifyed” forståes at alle funktioner og deklerationer er “rykket sammen” (variabler kan forkortes m.m.) på én laaaang linie, samt at alt whitespace er fjernet for at mindske filstørrelsen — og der kan hutigt sparres en del KB allerede der!
Næste skridt vi kan tage, og det er hele tricket ved dette, er at kombinerer de mange filer til én. Der findes flere måder at gøre dette på, bl.a. “Googles Closure Compiler“. En bonus ved Closure Compiler er at denne også udfører “minifying” af den endelige kombinerede Javascript fil. En ulempe, i min optik, er at dette ellers fantastiske værktøj, kræver at man manuelt skal compile alle sine Javascripts efter redigering, via en terminal — det er selvfølgelig til at overleve, men kunne jeg blive fri, valgte jeg helst det… og det kan jeg
Og det er netop dérfor jeg er så glad for denne metode, Niels har præsenteret mig for her i weekenden, da den vha. lidt URL-rewriting gør hele optimerings-processen automatisk! Ydermere er denne løsning designet til at kunne genererer cache-version af dine kombinerede filer, hvorefter der næsten ingen “overhead” er tilbage.
Kombinering af filer
Ideen er, at du på din server har én mappe til CSS og én mappe til Javascripts. Vha. følgende .htaccess-regl, kan vi fortælle vores script (combine.php), at dette skal kombinerer en “kæde” af filer til én:
RewriteEngine On RewriteBase / RewriteRule ^css/(.*\.css) /combine.php?type=css&files=$1 RewriteRule ^javascript/(.*\.js) /combine.php?type=javascript&files=$1
I vores <head>-sektion, hvor vi normalt ville have en masse links som dette:
<link rel="stylesheet" type="text/css" href="http://www.usgreencardoffice.com/css/ui.core.css," /> <link rel="stylesheet" type="text/css" href="http://www.usgreencardoffice.com/css/ui.dialog.css" /> <link rel="stylesheet" type="text/css" href="http://www.usgreencardoffice.com/css/ui.theme.css" /> <link rel="stylesheet" type="text/css" href="http://www.usgreencardoffice.com/css/prettyPhoto.css" /> <link rel="stylesheet" type="text/css" href="http://www.usgreencardoffice.com/css/jquery.Jcrop.css" /> <link rel="stylesheet" type="text/css" href="http://www.usgreencardoffice.com/css/style.css" />
kan vi nu nøjes med at linke dem komma-separeret, som her:
<link rel="stylesheet" type="text/css" href="http://www.usgreencardoffice.com/css/ui.core.css,ui.dialog.css,ui.theme.css,prettyPhoto.css,jquery.Jcrop.css,style.css" />
Det samme trick gør sig selvfølgelig gældende for Javascript-filerne. For at få løsningen til at fungerer helt optimalt, skal du oprette en skrivbar mappe kaldet “cache”.
Resultatet
Screenshots er igen alle taget efter at have tømt min browsers cache, svarende til at besøge sitet for første gang — Dvs. at du højst sansynligt vil spare endnu mere trafik ved andet besøg, da caching herefter vil træde i kræft
Javascripts (156.3 KB — 1.48 sek.)
CSS (8.8 KB — 10 msek.)
Download
Mere om minifying — forbedringer
Efter at have implementeret ovenstående, og set nærmere på nogle af de plugins jeg benytter (samt de scripts jeg selv har måtte tilføje), tænkte jeg at det ville være interessant at udvide løsningen med automatisk “minifying”. Dette er stadig en “todo” for mig, men måske du har samme tanker? I så fald vil følgende link måske have interesse: http://github.com/rgrove/jsmin-php/blob/master/jsmin.php
RSS
Twitter
Flickr
Facebook










sep 15, 2010 @ 10:04:17
Det var et overbevisende indlæg, super godt illustreret! Så er det igang med oprydningen..
maj 15, 2011 @ 17:56:12
Super godt indlæg – noget der virkelig mangler fokus på! Nu henter langt de færreste browsere alle filer hver gang – de fleste henter kun js/css 1 gang om dagen eller lign, men ikke desto mindre er dette et vigtigt emne.
Lige et par små tilføjelser:
Browserne kan godt hente alle filerne på samme tid – hvis de sættes op til det! Hele problemet ligger i at browsere som standard max henter (hæng mig ikke op på tallet) 8 requests pr. domæne af gangen (og de 8 requests skal allesammen hentes færdigt før de næste 8 påbegyndes for det domæne).
Dvs. har du en side med mange billeder, css-filer og js-filer fx (som langt de fleste har), så kan man snildt nå op over 20 filer i alt, hvilket resultere i at siden hentes i minimum 3 omgange.
Når man ved hvordan det her fungere, kan man gøre flere ting for at forbedre det.
1. Man kan samle filer (som denne artikel giver et shortcut til)
1.a CCS og JS filer samles let i 1 fil hver
1.b Billeder kan i nogle tilfælde samles i færre filer (især små billeder som “ikoner”/”knapper” og deres mouse-over-version osv.). Brug simpel CSS background-position til at bestemme hvilken del af billedet i billedet der skal vises.
2. Man kan placere filerne på forskellige domæner
Mange af de store tjenester som Facebook osv. bruger denne teknik. Antallet af samtidige connections er kun restriktivt for et domæne – så har man subdomæner eller flere domæner, kan man i teorien undgå denne begrænsning ved at sprede filerne ud (domain til php/html/aspx siden, subdomain til css+js, minimum et subdomain til billeder).
3. Man kan placere filerne strategisk i koden
Vel vidende at en browser sætter 8 connections i gang og venter på svar fra alle, er det eksempelvist dumt at lave 3 x 1 stor og 7 små filer.. Har man i stedet 3 store + 5 små efterfulgt af 8 små og sidst 8 små, så vil man samle de store i starten og de vil naturligt vente på hinanden imens de bliver downloaded – hvilket typisk i dette scenarie måske ville kunne halvere loadtiden ved den ændring.
Har du brug for mere viden omkring loadtider eller hvad du på din side kan forbedre, så skal du være velkommen til at kontakte mig på nick snabel a niebling punktum dk.
maj 18, 2011 @ 22:21:08
Hej Nick,
Tak for dit grunde input — det er jo et helt blog-indlæg i sig selv
Jeg er faktisk selv begyndt at benytte sprites (samle grafikken i én fil) på det sidste, og det har skam også givet en del.
Jeg har også tænkt på mulighed ved at benytte subdomæner til f.eks. statiske filer, men er gået mere i retning af at benytte en reelt fil-caching server.
Jeg har, kort, læst om “cookieless domain”, men har aldrig helt fundet ud af hvad det skulle være godt for, eller hvordan det sættes op. Er det noget du kender til, og i hvilke tilfælde bør man tage det i brug?