Web Assets - Tips voor een betere organisatie en prestaties

Weet je nog dat we veel tijd hadden moeten besteden aan het optimaliseren van de activa van ons project (afbeeldingen, CSS, enz.)? Tegenwoordig hebben gebruikers een veel snellere internetverbinding en het lijkt erop dat we het ons kunnen veroorloven om grotere afbeeldingen of grotere flash-bestanden te gebruiken met veel video en afbeeldingen erin. Met de opkomst van mobiele ontwikkeling zijn we echter weer terug in dezelfde situatie. Het is uiterst belangrijk om goed geoptimaliseerde sites te maken, zodat we snellere applicaties hebben, die minder inhoud downloaden en onmiddellijk reageren.


Afbeeldingen

Serveer de juiste maat

Vaak gebruiken we dezelfde afbeeldingen voor verschillende delen van onze websites. In een online winkel hebben alle producten bijvoorbeeld een overzichtsfoto. Laten we zeggen dat we drie pagina's hebben waarop we die afbeeldingen moeten weergeven - één pagina voor het weergeven van de producten, een andere pagina voor de productdetails en een derde pagina die alleen de foto in de oorspronkelijke grootte laat zien.

We hebben dus drie verschillende beeldformaten nodig en als we hetzelfde bestand voor alle drie de verschillende plaatsen gebruiken, downloadt de browser de afbeelding op volledig formaat, zelfs voor de lijstpagina, waar we eigenlijk alleen een foto van 200x200 nodig hebben. Als het oorspronkelijke bestand ongeveer 1 MB is en we tien producten per pagina hebben, downloadt de gebruiker 10 MB. Dat is geen goed idee. Probeer als u kunt verschillende afbeeldingen voor de verschillende delen van uw site te genereren, dit bespaart veel KB's voor uw gebruikers. Het is een goed idee om rekening te houden met de huidige schermresolutie. Als iemand bijvoorbeeld uw site op zijn iPhone opent, hoeft de gigantische headerafbeelding die u normaal gebruikt niet te worden weergegeven. Door CSS-mediaquery's te gebruiken, kunt u een afbeelding met een kleiner formaat verzenden:

@media only-scherm en (min-device-width: 320px) and (max-device-width: 480px) .header background-image: url (... /images/background_400x200.jpg); 

samendrukking

Het verzenden van een afbeelding met alleen de juiste afmetingen is niet altijd voldoende. Sommige bestandsindelingen kunnen veel worden gecomprimeerd zonder hun kwaliteit te verliezen. Er zijn veel programma's die u kunnen helpen. Photoshop biedt bijvoorbeeld een leuke functie genaamd Opslaan voor web en apparaten:


Er zijn veel opties in dit dialoogvenster, maar een van de belangrijkste is Kwaliteit. Als u de instelling op 80% instelt, kan dit de bestandsgrootte aanzienlijk verminderen.

Natuurlijk kunt u code gebruiken om de bestanden te comprimeren, maar ik geef persoonlijk de voorkeur aan Photoshop en ik gebruik het waar mogelijk. Hier is een eenvoudig voorbeeld geschreven in PHP:

functie compressImage ($ source, $ destination, $ quality) $ info = getimagesize ($ source); switch ($ info ['mime']) case "image / jpeg": $ image = imagecreatefromjpeg ($ source); imagejpeg ($ afbeelding, $ bestemming, $ kwaliteit); breken; case "image / gif": $ image = imagecreatefromgif ($ source); imagegif ($ afbeelding, $ bestemming, $ kwaliteit); breken; case "image / png": $ image = imagecreatefrompng ($ source); imagepng ($ afbeelding, $ bestemming, $ kwaliteit); breken;  compressImage ('source.png', 'destination.png', 85);

Sprites

Een van de dingen die u kunt doen om de prestaties van uw toepassing te verbeteren, is het aantal verzoeken naar de server te verminderen. Elke nieuwe afbeelding betekent dus een nieuwe aanvraag. Het is een goed idee om uw afbeeldingen in één te combineren. De resulterende afbeelding wordt a genoemd sprite en met het veranderen van de background-position CSS-stijl, kunt u alleen het gedeelte van de afbeelding weergeven dat u nodig hebt. Twitter Bootstrap gebruikt bijvoorbeeld sprites voor zijn interne iconen:


In de CSS kun je zoiets doen, om te laten zien welk deel van de sprite je wilt:

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

caching

Het caching-mechanisme van de browser is je vriend. Ja, soms tijdens de ontwikkeling kan dit tot sommigen leiden grappig situaties, maar het helpt echt om de prestaties van uw site te verbeteren. Elke browser cacheert inhoud zoals afbeeldingen, JavaScript of CSS. Er zijn verschillende manieren om de caching te controleren en ik stel voor dat u dit geweldige artikel leest voor een gedetailleerde beoordeling. Over het algemeen kunt u het proces besturen door headers in te stellen, zoals:

$ expire = 60 * 60 * 24 * 1; // seconds, minutes, hours, days header ('Cache-Control: maxage = ". $ expire); header (" Expires:' .gmdate ('D, d MYH: i: s ', time () + $ expire).' GMT '); header ('Last-Modified:' .gmdate ('D, d M Y H: i: s'). 'GMT');

prefetching

HTML5 gaat elke dag vooruit. Er is een leuke functie genoemd prefetching die de browser vertelt dat u in de nabije toekomst een bron nodig heeft en deze moet nu van tevoren worden gedownload. Bijvoorbeeld:

URI-schema / Inline-afbeeldingen

Een paar jaar geleden moest ik een eenvoudige webpagina ontwikkelen, die eigenlijk maar één HTML-bestand moest zijn. Natuurlijk waren er verschillende afbeeldingen, die ik moest opnemen. Data URI-schema's hebben me geholpen het probleem op te lossen. Het idee is om uw afbeeldingen om te zetten in een base64-gecodeerde reeks en deze in de src attribuut van de img label. Bijvoorbeeld:

rode stip

Door deze benadering te gebruiken, bevindt uw afbeelding zich feitelijk in de HTML en slaat u één HTTP-verzoek op. Natuurlijk, als je een grote afbeelding hebt, zal de reeks erg lang zijn. Hier is een eenvoudig PHP-script dat afbeeldingen converteert naar base64-reeksen:

$ picture = fread ($ fp, bestandsgrootte ($ bestand)); fclose ($ fp); // base64 codeert de binaire gegevens en verdeelt deze // in chunks volgens RFC 2045-semantiek $ base64 = base64_encode ($ afbeelding); $ tag = ''; $ css = 'url (data: image / jpg; base64,'. str_replace ("\ n", "", $ base64). '); ';

Dit kan in sommige gevallen nuttig zijn, maar houd er rekening mee dat het niet zo goed werkt in IE.


CSS

Ik vind het leuk om te denken dat het schrijven van CSS hetzelfde is als het schrijven van code. Je moet je stijlen nog steeds organiseren, om verschillende blokken en de relatie daartussen te definiëren. Dat is waarom ik denk dat CSS-beheer echt belangrijk is. Elk onderdeel van de applicatie zou zijn eigen stijlen moeten hebben en ze zouden mooi gescheiden moeten zijn. Alles in verschillende bestanden houden, biedt een goede organisatie, maar heeft ook zijn eigen problemen.

We weten allemaal dat het gebruik van de @importeren verklaring is geen erg goed idee. Dat komt omdat elke nieuwe @importeren betekent een nieuw verzoek aan de server. En als je bijvoorbeeld 20 verschillende hebt .css bestanden betekent dit dat de browser 20 verzoeken zal doen. En de browser toont / toont de pagina niet voordat alle stijlen zijn gedownload. Als sommige van uw .css bestanden ontbreken of erg groot zijn, u krijgt een grote vertraging voordat u iets op het scherm ziet.

Gebruik CSS Preprocessors

CSS preprocessors lossen alle bovenstaande problemen op. Je verdeelt je stijlen nog steeds in verschillende bestanden, maar aan het einde compileert de preprocessor alles in een enkele .css het dossier. Ze bieden eigenlijk een heleboel coole functies zoals variabelen, geneste blokken, mixins en overerving. De code lijkt nog steeds op CSS, maar hij is goed opgemaakt / gestructureerd. Er zijn weinig populaire preprocessors die de moeite waard zijn om te controleren - Sass, LESS en Stylus. Hier is een eenvoudig voorbeeld geschreven in MINDER:

.positie (@top: 0, @left: 0) positie: absoluut; top: @top; links links; text-align: left; tekengrootte: 24 px;  .header .position (20px, 30px); .tips .position (10px, -20px);  .logo .position (10px, 20px); 

zal produceren

.header positie: absoluut; top: 20px; links: 30px; text-align: left; tekengrootte: 24 px;  .header .tips positie: absoluut; top: 10px; links: -20px; text-align: left; tekengrootte: 24 px;  .header .logo positie: absoluut; top: 10px; links: 20px; text-align: left; tekengrootte: 24 px; 

Of, bijvoorbeeld als u een knop opmaakt en dezelfde knop wilt produceren, maar met een andere kleur voor de tekst, kunt u dit doen:

.knop border: vast 1px # 000; opvulling: 10px; achtergrond: # 9f0; kleur: # 0029FF;  .actieve knop . knop (); kleur: #FFF; 

Efficiënte CSS

Normaal gesproken denken de meeste ontwikkelaars niet aan efficiënte CSS. De efficiëntie van de CSS weerspiegelt de weergave van de pagina en als uw stijlen inefficiënt zijn, wordt uw toepassing langzaam weergegeven door browsers. Een interessant feit is dat browsers de CSS-selectors van rechts naar links parsen. Dat betekent dat de volgende code:

body ul li a color: # F000; tekstdecoratie: geen; 

... is helemaal niet efficiënt. Dat komt omdat de motor alle tags en zal elk ouderelement moeten evalueren om uiteindelijk de gewenste stijl te verzamelen. Je moet ook weten dat de selectors qua efficiëntie een soort van rangorde hebben in de volgende volgorde: ID, klasse, tag en universeel. Dit betekent dat een element met een ID kaart set wordt sneller gerenderd dan een element met alleen een tag selector. Het is natuurlijk niet logisch om id's toe te voegen aan alle elementen in de DOM-structuur, maar je moet zeker je code controleren en deze waar mogelijk verbeteren. Als u bijvoorbeeld zoiets heeft als dit:

ul #navigation li background: # ff0232; 

Je moet de. Verwijderen ul deel, omdat je er maar één hebt #navigatie element op de pagina. Of in de volgende selector:

body .content p font-size: 20px; 

Het is duidelijk dat de .inhoud element is een kind van de lichaam label. Alle elementen zijn eigenlijk kinderen van dit element.

Hier zijn twee handige links over dit onderwerp: developers.google.com en css-tricks.com

Bestandsgrootte

Zoals we hierboven al vermeldden, is het goed om zo weinig mogelijk code te hebben, omdat de browser de pagina niet rendert voordat de CSS is gedownload. Hier zijn enkele tips om de bestandsgrootte te verkleinen.

Combineer vergelijkbare stijlen:

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

... transformeert naar:

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

Gebruik kortere omschrijving. In plaats van:

.header background-colour: # 999999; background-image: url (... /images/header.jpg); achtergrond-positie: rechtsboven; 

Schrijf het op deze manier:

.header background: # 999 url (... /images/header.jpg) rechtsboven; 

Verklein uw CSS-code. U kunt dit doen door een tool te gebruiken die over het algemeen alle spaties en nieuwe lijnen verwijdert. Bijvoorbeeld CSSOptimizer of Minifycss. Het is gebruikelijk om dergelijke instrumenten aan de serverkant van de toepassing te gebruiken, d.w.z. iets geschreven in de taal van de back-end. Normaal gesproken verkleinen deze componenten uw code en dienen deze voor de gebruiker.

Zet uw CSS-bestanden in de Label

Het is een goede gewoonte om uw .css bestanden in de hoofd tag, op die manier zal de browser het eerst downloaden.


JavaScript

Reduceer het aantal HTTP-verzoeken

Hetzelfde als met uw CSS - het is goed om het aantal verzoeken dat naar de server moet worden verzonden te verminderen. In de meeste gevallen zal het laden van de JavaScript-bestanden de weergave van de pagina niet stoppen, maar het zal sommige delen van de pagina niet-functioneel maken.

Verklein uw code

Er zijn een aantal bibliotheken die JavaScript-minificatie uitvoeren. Het is iets dat de grootte van de bestanden zal verminderen, maar houd er rekening mee dat het in een ontwikkelomgeving goed is om je code schoon te houden. De meeste van deze hulpmiddelen veranderen de naam van uw variabelen en zetten alles om in een regel met één regel, waardoor het debugproces bijna onmogelijk wordt.

CommonJS, AMD, RequireJS - Probeer het eens

JavaScript heeft geen mechanisme om modules te beheren. Dus al die dingen zijn verzonnen om dit probleem op te lossen. Ze bieden een API die u kunt gebruiken om modules te definiëren en te gebruiken. Hier is bijvoorbeeld een voorbeeld van http://requirejs.org/:

   Mijn voorbeeldproject     

Mijn voorbeeldproject

Binnenkant van main.js, je kunt gebruiken vereisen() om andere scripts te laden die u nodig hebt:

require (["helper / util"], functie (util) // Deze functie wordt aangeroepen wanneer scripts / helper / util.js wordt geladen. // Als util.js calls define () aanroept, dan wordt deze functie pas geactiveerd // util's dependencies zijn geladen, en het util-argument zal // de module-waarde voor "helper / util" bevatten.);

Gebruik Namespaces

Als we het hebben over de code-indeling, kunnen we het gedeelte over naamruimten niet overslaan. Eigenlijk is er geen dergelijke functie in JavaScript, maar je kunt nog steeds hetzelfde bereiken met een beetje code. Als u bijvoorbeeld uw eigen MVC-raamwerk wilt bouwen, hebt u waarschijnlijk de volgende klassen:

var model = function () ...; var view = function () ...; var controller = function () ...;

Als u de dingen laat zoals ze zijn in de bovenstaande code, worden ze openbaar en is er een grotere kans op conflicten met andere bibliotheken in uw project. Dus, door ze te groeperen in een onafhankelijk object (naamruimte) wordt het framework beschermd:

var MyAwesomeFramework = model: function () ..., weergave: function () ..., controller: function () ...

Volg ontwerppatronen

Het wiel opnieuw uitvinden is niet nodig. JavasScript werd erg populair en er zijn veel goede praktijken die er zijn. Ontwerppatronen zijn herbruikbare oplossingen voor veel voorkomende problemen bij het programmeren. Als je een aantal van hen volgt, kun je een goede applicatie bouwen. Als ik ze hier allemaal probeer te beschrijven, zou ik een boek moeten schrijven, dus hier zijn er slechts een paar:

Constructorpatroon

Gebruik dit patroon om een ​​exemplaar van een specifiek objecttype te maken. Hier is een voorbeeld:

var Class = function (param1, param2) this.var1 = param1; this.var2 = param2;  Class.prototype = methode: function () alert (this.var1 + "/" + this.var2); ;

Of je kunt dit proberen:

functie Klasse (param1, param2) this.var1 = param1; this.var2 = param2; this.method = function () alert (param1 + "/" + param2); ; ; var instance = new Class ("value1", "value2");

Module patroon

Het modulepatroon geeft ons de mogelijkheid om private en publieke methoden te creëren. Bijvoorbeeld, in de onderstaande code, de variabele _inhoudsopgave en de methode privateMethod zijn privé. aanwas en getIndex zijn openbaar.

var Module = (functie () var _index = 0; var privateMethod = function () return _index * 10; return increment: function () _index + = 1;, getIndex: function () return _index; ;) ();

Waarnemingspatroon

Waar je ook het abonnement of de verzending van evenementen ziet, je ziet waarschijnlijk dit patroon. Er zijn waarnemers die geïnteresseerd zijn in iets dat gerelateerd is aan een specifiek object. Zodra de actie plaatsvindt, stelt het object de waarnemers op de hoogte. Het onderstaande voorbeeld laat zien hoe we een waarnemer kunnen toevoegen aan de gebruikers voorwerp:

var Users = list: [], listeners: , voeg toe: function (name) this.list.push (name: name); this.dispatch ( "gebruiker toegevoegde"); , on: function (eventName, listener) if (! this.listeners [eventName]) this.listeners [eventName] = []; this.listeners [eventName] .Schuif (listener); , verzending: function (eventName) if (this.listeners [eventName]) for (var i = 0; i 

Function Chaining Pattern

Dit patroon is een leuke manier om de openbare interface van uw module te organiseren. Het bespaart tijd en verbetert de leesbaarheid:

var Gebruiker = profiel: , naam: functie (waarde) this.profile.name = waarde; geef dit terug; , job: function (value) this.profile.job = value; geef dit terug; , getProfile: function () return this.profile; ; var profile = User.name ("Krasimir Tsonev"). job ("webontwikkelaar"). getProfile (); console.log (profiel);

Ik raad ten zeerste aan dit boek te lezen door Addy Osmani. Het is een van de beste bronnen die je kon vinden over ontwerppatronen in JavaScript.


Activa-Pack

Nu we het einde van dit artikel naderen, wil ik een paar gedachten over CSS en JavaScript-codebeheer op de server delen. Het is een heel gebruikelijke techniek om samenvoeging, minificatie en compilatie toe te voegen aan de logica van de toepassing. Vaak is er een soort caching-mechanisme, maar alle dingen gebeuren tijdens runtime. Dus je hebt waarschijnlijk wat codelogica, die de aanvraag behandelt .js of .css bestanden en dient de juiste inhoud. Achter dit proces bevindt zich de compilatie, minificatie of wat u ook gebruikt om uw bezittingen in te pakken.

In mijn laatste projecten heb ik een tool gebruikt genaamd activa-pack. Het is echt nuttig en ik zal in detail uitleggen wat het precies doet, maar het interessantere deel is hoe ik het gebruikte. Deze bibliotheek is alleen bedoeld voor gebruik in de ontwikkelingsmodus, het is niet iets dat in je codebasis blijft en dat je niet op je productieserver moet implementeren..

Het idee is om de packer alleen te gebruiken terwijl u aan de assets werkt (CSS, JS). Het controleert in feite op veranderingen in specifieke mappen en compileert / verpakt de code in een enkel bestand. Door deze benadering te gebruiken, hoef je niet na te denken over het minificeren of compileren. Het enige dat u hoeft te doen is het gecompileerde statische bestand naar de gebruiker te sturen. Dit verhoogt de prestaties van uw toepassing, omdat deze alleen statische bestanden serveert en natuurlijk de zaken eenvoudiger maakt. U hoeft niets op uw server in te stellen of onnodige logica te implementeren.

Hier is hoe u kunt instellen en gebruiken activa-pack.

Installatie

Deze tool is een Nodejs-module, dus je moet een node al hebben geïnstalleerd. Als u dat niet doet, gaat u gewoon naar nodejs.org/download en pakt u het pakket voor uw besturingssysteem. Daarna:

npm install -g assetspack

Gebruik

De module werkt met JSON-configuratie. Wanneer het via de opdrachtregel wordt gebruikt, moet u uw instellingen in a plaatsen .json het dossier.

Via de commandoregel

Creëer een assets.json bestand en voer de volgende opdracht uit in dezelfde map:

assetspack

Als uw configuratiebestand een andere naam gebruikt of in een andere map staat, gebruik dan:

assetspack --config [pad naar json-bestand]

In code

var AssetsPack = require ("assetspack"); var config = [type: "css", kijken: ["css / src"], output: "tests / packed / styles.css", minify: true, exclude: ["custom.css"]]; var pack = new AssetsPack (config, function () console.log ("AssetsPack is watching");); pack.onPack (function () console.log ("AssetsPack heeft de taak uitgevoerd"););

Configuratie

De configuratie moet een geldig JSON-bestand / -object zijn. Het zijn maar een reeks objecten:

[(activabestand), (activabestand), (activumobject), ...]

Asset Object

De basisstructuur van het asset-object is als volgt:

type: (bestandstype / string, zou bijvoorbeeld css, js of minder kunnen zijn), watch: (directory of mappen voor kijken / string of array van strings /), pack: (directory of mappen voor packing / string of array van strings /.), output: (pad naar uitvoerbestand / string /), minify: / boolean /, exclude: (array van bestandsnamen)

De pak eigendom is niet verplicht. Als je het mist, is de waarde gelijk aan kijk maar. kleineren standaard is false.

Hier zijn een paar voorbeelden:

CSS inpakken

type: "css", kijken: ["tests / data / css", "tests / data / css2"], pack: ["tests / data / css", "tests / data / css2"], output: " tests / packed / styles.css ", minify: true, exclude: [" header.css "]

JavaScript inpakken

type: "js", kijken: "tests / data / js", pack: ["tests / data / js"], output: "tests / packed / scripts.js", verkleinen: waar, exclusief: ["A .js "]

Inpakken .minder bestanden

De verpakking van .minder bestanden is een beetje anders. De pak eigendom is verplicht en het is in feite uw beginpunt. Je zou de andere moeten importeren .minder bestanden daar. De uitsluiten eigendom is hier niet beschikbaar.

type: "less", watch: ["tests / data / less"], pack: "tests / data / less / index.less", output: "tests / packed / styles-less.css", verkleinen: true 

Als u problemen ondervindt, kijk dan op de testen / verpakkingsgroep less.spec.js van de repository in GitHub.

Andere bestandsindelingen inpakken

activa-pack werkt met elk bestandsformaat. We kunnen bijvoorbeeld HTML-sjablonen combineren in één bestand door zoiets als dit te doen:

type: "html", bekijk: ["tests / data / tpl"], output: "tests / packed / template.html", exclusief: ["admin.html"]

Het enige ding dat je hier moet weten, is dat er geen minificatie is.


Conclusie

Als front-end webontwikkelaars moeten we proberen de best mogelijke prestaties voor onze gebruikers te leveren. De bovenstaande tips zijn niet bedoeld om alle aspecten van de organisatie en prestaties van activa te dekken, maar het zijn de tips die ik persoonlijk heb behandeld tijdens mijn dagelijkse werk. Deel gerust enkele van uw tips hieronder in de comments.