Webbtillgångar - Tips för bättre organisation och prestanda

Kom ihåg när vi var tvungna att spendera mycket tid på att optimera projektets tillgångar (bilder, CSS, etc ...)? Tja idag har användarna en mycket snabbare internetuppkoppling och det verkar som om vi har råd att använda större bilder eller större flashfiler med mycket video och bilder inuti. Men med utvecklingen av mobilutveckling återkommer vi igen i samma situation. Det är oerhört viktigt att skapa väl optimerade webbplatser, så att vi har snabbare applikationer, som hämtar mindre innehåll och svarar omedelbart.


Bilder

Servera rätt storlek

Ofta använder vi samma bilder för olika delar av våra webbplatser. Till exempel, i en webbutik, har alla produkter en översiktsbild. Låt oss säga att vi har tre sidor där vi måste visa bilderna - en sida för att lista produkterna, en annan sida för produktens detaljer och en tredje sida som bara visar bilden i sin ursprungliga storlek.

Så vi behöver tre olika bildstorlekar och om vi använder samma fil för alla tre olika ställen, kommer webbläsaren ladda ner fullstorleksbilden även för listningssidan, där vi faktiskt bara behöver en 200x200 bild. Om den ursprungliga filen är cirka 1 MB och vi har tio produkter per sida, så skulle användaren ladda ner 10 MB. Det är inte en mycket bra idé. Om du kan, försök generera olika bilder för de olika delarna av din webbplats, så sparar du många KB-filer för dina användare. Det är en bra idé att tänka på den aktuella skärmupplösningen. Om någon till exempel öppnar din webbplats på sin iPhone, behöver du inte tjäna den gigantiska header-bilden, som du brukar använda. Genom att använda CSS-mediafrågor kan du skicka en bild med en mindre storlek:

@media bara skärm och (min enhet bredd: 320px) och (max enhet bredd: 480px) .header background-image: url (... /images/background_400x200.jpg); 

Kompression

Att skicka en bild med bara rätt mått är inte alltid tillräckligt. Vissa filformat kan komprimeras mycket utan att förlora sin kvalitet. Det finns många program som kan hjälpa dig. Till exempel, Photoshop ger en fin funktion som heter Spara för webb och enheter:


Det finns många alternativ i den här dialogrutan, men en av de viktigaste är Kvalitet. Om du ställer in det på ungefär 80% kan du minska filstorleken avsevärt.

Självklart kan du använda kod för att komprimera filerna, men jag föredrar personligen Photoshop och jag använder det när det är möjligt. Här är ett enkelt exempel skrivet i PHP:

funktion compressImage ($ source, $ destination, $ quality) $ info = getimagesize ($ source); switch ($ info ['mime']) fall "image / jpeg": $ image = imagecreatefromjpeg ($ source); imagejpeg ($ image, $ destination, $ quality); ha sönder; fall "image / gif": $ image = imagecreatefromgif ($ source); imagegif ($ bild, $ destination, $ kvalitet); ha sönder; fall "image / png": $ image = imagecreatefrompng ($ source); imagepng ($ image, $ destination, $ quality); ha sönder;  compressImage ('source.png', 'destination.png', 85);

sprites

En av de saker du kan göra för att öka prestanda för din ansökan är att minska antalet förfrågningar till servern. Så innebär varje ny bild en ny förfrågan. Det är en bra idé att kombinera dina bilder till en. Den resulterande bilden heter a sprite och med att ändra bakgrund-positionen CSS-stil kan du bara visa den del av bilden du behöver. Twitter Bootstrap använder till exempel sprites för sina interna ikoner:


Därefter kan du i CSS göra något så här för att visa vilken del av sprite du vill ha:

.icon-edit background-image: url ("... /img/glyphicons-halfl-white.png"); Bakgrundsposition: -96px -72px; 

caching

Webbläsarens cachemekanism är din vän. Ja, ibland under utveckling kan det leda till några mycket rolig situationer, men det hjälper verkligen att förbättra webbplatsens prestanda. Varje webbläsare cachar innehåll som bilder, JavaScript eller CSS. Det finns flera sätt att styra cachen och jag föreslår att du kolla in den här stora artikeln för en detaljerad granskning. I allmänhet kan du styra processen genom att ställa in rubriker, som så:

$ expire = 60 * 60 * 24 * 1; // sekunder, minuter, timmar, dagar header ("Cache-Control: maxage =". $ expire); header ("Expires:" .gmdate ('D, d MYH: I: s ', tid () + $ utgår).' GMT '); rubrik ('Senast ändrad:' .gmdate ('D, d M Y H: i: s'). 'GMT');

förhämtning

HTML5 går framåt varje dag. Det finns en trevlig funktion som heter förhämtning vilket berättar för webbläsaren att du behöver lite resurs inom den närmaste framtiden och det bör laddas ned nu, i förväg. Till exempel:

Data URI-schema / inline-bilder

För några år sedan var jag tvungen att utveckla en enkel webbsida, som var bara en HTML-fil. Självklart var det flera bilder, som jag var tvungen att inkludera. Data URI-system hjälpte mig att lösa problemet. Tanken är att konvertera dina bilder till en base64 kodad sträng och placera den i src attribut av img märka. Till exempel:

röd prick

Genom att använda detta tillvägagångssätt är din bild faktiskt i HTML och du sparar en HTTP-begäran. Självklart, om du har en stor bild kommer strängen att vara riktigt lång. Här är ett enkelt PHP-skript som konverterar bilder till base64-strängar:

$ picture = fread ($ fp, file size ($ file)); fclose ($ fp); // base64 kodar binär data, bryt den sedan // i bitar enligt RFC 2045 semantik $ base64 = base64_encode ($ bild); $ tag = ''; $ css = 'url (data: image / jpg; base64,' .str_replace ("\ n", "", $ base64). '); ';

Du kan finna det här användbart i vissa fall, men kom ihåg att det inte fungerar bra i IE.


CSS

Jag tycker om att skriva CSS är som att skriva kod. Du måste fortfarande organisera dina stilar, för att definiera olika block och förhållandet mellan dem. Det är därför jag tycker att CSS-hanteringen är väldigt viktig. Varje del av ansökan ska ha sina egna stilar och de ska vara snygga separerade. Att hålla allt i olika filer ger en bra organisation, men också med sina egna problem.

Vi vet alla att användningen av @importera uttalande är inte en mycket bra idé. Det beror på att alla nya @importera innebär en ny begäran till servern. Och om du till exempel har 20 olika .css filer betyder det att webbläsaren kommer att göra 20 förfrågningar. Och webbläsaren gör inte / visar sidan innan du laddar ned alla stilar. Om några av dina .css filer saknas eller är mycket stora, får du en stor fördröjning innan du ser något på skärmen.

Använd CSS Preprocessors

CSS preprocessorer löser alla problem ovan. Du delar fortfarande dina stilar i olika filer, men i slutet sammanställer förprocessorn allt till en enda .css fil. De erbjuder faktiskt ett gäng coola funktioner som variabler, kapslade block, mixins och arv. Koden ser fortfarande ut som CSS, men den är välformaterad / strukturerad. Det finns få populära förprocessorer som är värda att kontrollera - Sass, LESS, och Stylus. Här är ett enkelt exempel skrivet i MINDER:

.position (@top: 0, @left: 0) position: absolute; topp: @top; vänster: @left; text-align: left; typsnittstorlek: 24px;  .header .position (20px, 30px); .tips .position (10px, -20px);  .logo .position (10px, 20px); 

kommer att producera

.header position: absolute; topp: 20px; vänster: 30px; text-align: left; typsnittstorlek: 24px;  .header.tips position: absolute; topp: 10px; vänster: -20px; text-align: left; typsnittstorlek: 24px;  .header .logo position: absolute; topp: 10px; vänster: 20px; text-align: left; typsnittstorlek: 24px; 

Eller, till exempel om du har styling för en knapp och vill producera precis samma knapp men med en annan färg för texten, kan du göra det här:

.knapp border: solid 1px # 000; vaddering: 10px; bakgrund: # 9f0; färg: # 0029FF;  .aktiv knapp . knapp (); färg: #FFF; 

Effektiv CSS

Normalt tänker de flesta utvecklare inte på effektiv CSS. Effektiviteten hos CSS återspeglar sidans rendering och om dina stilar är ineffektiva kommer din ansökan att göras långsamt av webbläsare. Ett intressant faktum är att webbläsare analyserar CSS-selektorerna från höger till vänster. Vilket innebär att följande kod:

kropp ul li a färg: # F000; text-dekoration: ingen; 

... är inte effektivt alls. Det beror på att motorn kommer att få alla taggar och kommer att behöva utvärdera var och en av moderelementen för att slutligen samla den nödvändiga stilen. Du bör också veta att i effektivitetssyfte är selektorerna sorterade i följande ordning: ID, klass, tag och universal. Det betyder att ett element med en id set kommer att bli gjorda snabbare än ett element med bara en taggväljare. Det är naturligtvis ingen mening att lägga till ids på alla element i DOM-trädet, men du bör definitivt kolla din kod och förbättra den där det är möjligt. Om du till exempel har något liknande här:

ul #navigation li background: # ff0232; 

Du borde ta bort ul del, för att du bara har en #navigering element på sidan. Eller i följande väljare:

body .content p font-size: 20px; 

Det är uppenbart att .innehåll elementet är ett barn av kropp märka. Alla element är faktiskt barn av detta element.

Här är två användbara länkar om det här ämnet: developers.google.com och css-tricks.com

Filstorlek

Som vi nämnde ovan är det bra att ha så liten kod som möjligt, eftersom webbläsaren inte gör sidan innan du laddar ner CSS. Här är några tips för att minska filstorleken.

Kombinera liknande stilar:

.rubrik font-size: 24px;  .content font-size: 24px; 

... omvandlas till:

.header, .content font-size: 24px; 

Använd shorthands. Istället för:

.rubrik bakgrundsfärg: # 999999; bakgrundsbild: url (... /images/header.jpg); Bakgrundsställning: Överst till höger; 

Skriv det på det här sättet:

.rubrik bakgrund: # 999 url (... /images/header.jpg) till höger; 

Minifiera din CSS-kod. Du kan göra detta genom att använda ett verktyg som i allmänhet tar bort alla mellanslag och nya rader. Till exempel CSSOptimiser eller Minifycss. Det är vanligt att använda sådana instrument på serverns sida, dvs något som skrivs på baksidans språk. Normalt minskar dessa komponenter din kod och tjänar den till användaren.

Sätt dina CSS-filer i Märka

Det är bra att inkludera din .css filer i huvud taggen, så kommer webbläsaren att ladda ner den först.


JavaScript

Minska antalet HTTP-förfrågningar

Samma som med din CSS - det är bra att minska antalet begäranden som ska skickas till servern. I de flesta fall upphör inte laddningen av JavaScript-filerna att återge sidan, men det kommer att göra vissa delar av sidan icke-funktionell.

Minifiera din kod

Det finns en massa bibliotek som gör JavaScript-minifiering. Det är något som kommer att minska filens storlek, men tänk på att i en utvecklingsmiljö är det bra att hålla koden ren. De flesta av dessa verktyg ändrar namnet på dina variabler och omvandlar allt till en ensträngsträng, vilket gör debuggingprocessen nästan omöjlig.

CommonJS, AMD, RequireJS - Ge det ett försök

JavaScript har inte en mekanism för hantering av moduler. Så, alla dessa saker är uppfunna för att lösa detta problem. De tillhandahåller ett API som du kan använda för att definiera och använda moduler. Till exempel, här är ett exempel taget från http://requirejs.org/:

   Mitt provprojekt     

Mitt provprojekt

Insidan av main.js, du kan använda fordra() att ladda alla andra skript du behöver:

kräva (["hjälpar / util"], funktion (util) // Den här funktionen heter när scripts / hjälper / util.js laddas. // Om använd.js-samtal definierar (), blir den här funktionen inte avbruten tills // utils beroenden har laddats, och utilitetsargumentet håller // modulvärdet för "hjälpar / util".);

Använd namnområden

Om vi ​​pratar om kodorganisation kan vi inte hoppa över delen om namnområden. Nativt finns det ingen sådan funktion i JavaScript, men du kan fortfarande uppnå samma sak med en liten kod. Om du till exempel vill bygga din egen MVC-ram har du förmodligen följande klasser:

var modell = funktion () ...; var view = funktion () ...; var controller = funktion () ...;

Om du lämnar saker som de är i ovanstående kod, blir de offentliga och det finns en större chans att skapa konflikter med andra bibliotek i ditt projekt. Så att gruppera dem i ett oberoende objekt (namespace) gör ramverket skyddad:

var MyAwesomeFramework = modell: funktion () ..., visa: funktion () ..., controller: funktion () ...

Följ designmönster

Det är inte nödvändigt att återuppfinna hjulet. JavasScript blev väldigt populär och det finns många bra metoder där ute. Designmönster är återanvändbara lösningar för vanliga problem i programmeringen. Efter några av dem hjälper du dig att bygga en bra applikation. Men om jag försöker täcka dem alla här, skulle jag behöva skriva en bok, så här är bara några av dem:

Konstruktormönster

Använd det här mönstret för att skapa en förekomst av en viss objekttyp. Här är ett exempel:

var Klass = funktion (param1, param2) this.var1 = param1; this.var2 = param2;  Class.prototype = metod: funktion () alert (this.var1 + "/" + this.var2); ;

Eller så kan du prova det här:

funktionsklass (param1, param2) this.var1 = param1; this.var2 = param2; this.method = function () alert (param1 + "/" + param2); ; ; var instance = ny klass ("värde1", "värde2");

Modulmönster

Modulmönstret ger oss möjligheten att skapa privata och offentliga metoder. Till exempel, i koden nedan, variabeln _index och metoden privateMethod är privata. ökning och getIndex är offentliga.

var-modul = (funktion () var _index = 0; var privatMethod = funktion () return _index * 10; returnera inkrement: funktion () _index + = 1;, getIndex: funktion () return _index; ;) ();

Observer Mönster

Varhelst du ser prenumeration eller försändelse av händelser kommer du troligtvis att se det här mönstret. Det finns observatörer som är intresserade av något som är relaterat till ett visst objekt. När åtgärden inträffar meddelar objektet observatörerna. Exemplet nedan visar hur vi kan lägga till en observatör på användare objekt:

var Users = list: [], lyssnare: , lägg till: funktion (namn) this.list.push (namn: namn); this.dispatch ( "user-added"); , på: funktion (händelsenamn, lyssnare) if (! this.listeners [eventName]) this.listeners [eventName] = []; this.listeners [eventname] .push (lyssnare); , avsändning: funktion (händelsenamn) om (this.listeners [eventName]) for (var i = 0; i 

Funktionskedjemönster

Detta mönster är ett bra sätt att organisera det offentliga gränssnittet för din modul. Det sparar tid och förbättrar läsbarheten:

var User = profil: , namn: funktion (värde) this.profile.name = value; returnera detta; , jobb: funktion (värde) this.profile.job = value; returnera detta; , getProfile: function () returnera this.profile; ; var profil = Användarnamn ("Krasimir Tsonev"). jobb ("webbutvecklare"). getProfile (); console.log (profil);

Jag rekommenderar starkt att du kolla denna bok av Addy Osmani. Det är en av de bästa resurserna som du kan hitta om designmönster i JavaScript.


Tillgångar-Pack

Nu när vi närmar oss slutet av den här artikeln vill jag dela några tankar om CSS och JavaScript-kodhantering på servern. Det är en mycket vanlig teknik för att lägga till sammanslagning, minifiering och sammanställning i programmets logik. Ofta finns det någon form av cachemekanism, men alla saker händer under körtiden. Så du har förmodligen en kodlogik som hanterar begäran om .js eller .css filer och serverar rätt innehåll. Bakom denna process är sammanställningen, minifiering eller vad du än använder för att förpacka dina tillgångar.

I mina senaste projekt använde jag ett verktyg som heter tillgångar-pack. Det är verkligen användbart och jag kommer att förklara i detalj vad exakt det gör, men den mer intressanta delen är hur jag använde den. Detta bibliotek är endast avsett att användas i utvecklingsläge, det är inte något som stannar i din kodbas och det är inte något som du ska installera på din produktionsserver.

Tanken är att endast använda förpackaren när du arbetar på tillgångarna (CSS, JS). Den tittar faktiskt på ändringar i specifika kataloger och sammanställer / förpackar koden i en enda fil. Genom att använda detta tillvägagångssätt behöver du inte tänka på minifiering eller sammanställning. Allt du behöver göra är att skicka den sammanställda statiska filen till användaren. Detta ökar prestandan i din ansökan, eftersom den bara tjänar statiska filer och gör det självklart enklare. Du behöver inte ställa in något på din server eller genomföra onödig logik.

Så här kan du installera och använda tillgångar-pack.

Installation

Det här verktyget är en Nodejs-modul, så du borde ha Node redan installerad. Om du inte gör det, gå till nodejs.org/download och ta tag i paketet för ditt operativsystem. Efter det:

npm installera -g assetspack

Användande

Modulen arbetar med JSON-konfiguration. När den används via kommandoraden bör du placera dina inställningar i en .json fil.

Via kommandoraden

Skapa en assets.json fil och kör följande kommando i samma katalog:

assetspack

Om din konfigurationsfil använder ett annat namn eller finns i en annan katalog, använd:

assetspack --config [sökväg till json fil]

I kod

var AssetsPack = kräver ("assetspack"); var config = [typ: "css", titta på: ["css / src"], output: "test / packed / styles.css", minifiera: true, exclude: ["custom.css"]]; var pack = nytt AssetsPack (config, function () console.log ("AssetsPack ser");); pack.onPack (funktion () console.log ("AssetsPack gjorde jobbet"););

Konfiguration

Konfigurationen ska vara en giltig JSON-fil / -objekt. Det är bara en rad objekt:

[(asset object), (asset object), (asset object), ...]

Asset Object

Den grundläggande strukturen för tillgångsobjektet är som så:

typ: (filtyp / sträng, kan vara css, js eller mindre till exempel), titta på: (katalog eller kataloger för att titta på / sträng eller array av strängar /), pack: (katalog eller kataloger för packning / sträng eller array av strängar /.), utgång: (sökväg till utgångsfil / sträng /), minifiera: / boolean /, utesluta: (rad filnamn)

De packa egendom är inte obligatorisk. Om du saknar det, är dess värde lika med Kolla på. minify som standard är false.

Här är några exempel:

Packning CSS

typ: "css", titta på: ["test / data / css", "test / data / css2"], pack: ["test / data / css", "test / data / css2"], utgång: test / packed / styles.css ", avgränsa: true, exclude: [" header.css "]

Förpackning av JavaScript

typ: "js", titta på: "test / data / js", pack: ["test / data / js"], output: "test / packed / scripts.js", minifiera: true, exclude: .js "]

Förpackning .mindre filer

Förpackningen av .mindre filer är lite annorlunda. De packa egendom är obligatoriskt och det är i grunden din ingångspunkt. Du borde importera alla andra .mindre filer där. De utesluta egendom är inte tillgänglig här.

typ: "mindre", titta på: ["test / data / mindre"], pack: "test / data / mindre / index.less", utgång: "test / packed / styles-less.css" 

Om du hittar några problem, kolla tester / förpackning-less.spec.js av förvaret i GitHub.

Packar andra filformat

tillgångar-pack fungerar med alla filformat. Till exempel kan vi kombinera HTML-mallar i en enda fil genom att göra något så här:

typ: "html", titta på: ["test / data / tpl"], output: "test / packed / template.html", utesluter: ["admin.html"]

Den enda sak som du borde veta här är att det inte finns någon minifiering.


Slutsats

Som främsta webbutvecklare borde vi försöka leverera bästa möjliga prestanda för våra användare. Tipsen ovan är inte tänkt att täcka alla aspekter av tillgångsorganisation och prestanda, men de är de jag har behandlat personligen under mitt dagliga arbete. Vänligen gärna dela några av dina tips nedan, i kommentarerna.