Ubrzajte učitavanje stranice – smanjite CSS, JS (minify)

napisao pedja, 23.03.2009, pod Programiranje

Da bi povećali brzinu učitavanja vaše stranice, potrebno je smanjiti količinu podataka i broj fajlova, koji se prenose od servera ka browseru. Za svaki fajl koji dolazi sa servera, browser mora prvo da pošalje zahtev, pa da sačeka da browser taj zahtev obradi, i da pošalje sadržaj browseru. Svaka od ovih operacija traje neki vremenski period, koji dodatno može da se produži jer sve zavisi od količine saobraćaja na internetu i brzine vaše konekcije. Ako se to pomnoži sa brojem CSS i JS fajlova koje učitavate, dolazite do vremena od nekoliko sekundi. To se sve može dosta ubrzati ako sve vaše CSS i JS fajlove spojite u jedan CSS, tj. jedan JS fajl, i još ga kompresujete.

Minify

Problem koji se javlja kod JS i CSS fajlova je da su oni često relativno veliki i da ih ima nekoliko. Prva dobra stvar je da se svi fajlovi iste vrste spojiti u jedan fajl, tako da na kraju posla imamo samo jedan CSS, tj. JS. Druga stvar je da se ti fajlovi mogu umanjiti prostim izbacivanjem svih karaktera koji su nepotrebni, ali vam pomažu prilikom razvoja ovih fajlova, kao što su komentari i nevidljivi karakteri (razmak, tab i oznaka za kraj reda).

Ovaj proces se naziva minify. Tražeći po internetu svojevremeno, naišao sam na nekoliko css/js kompresor, kako se inače nazivaju ovakvi skriptovi, a za svoje aplikacije sam iskoristio JSMin, za kompresiju JavaScript fajlova, dok sam za potrebe kompresije CSS fajlova, kod delimično sam napisao, a deo našao na internetu.

Ovde ću vam  predstaviti PHP skriptu, koja se pokazala dovoljno dobra da obavi posao skraćivanja fajla.

<?php
include (dirname(__FILE__) . '/jsmin-1.1.1.php');

class minify_that
{

  protected function cache_file_name ($list, $prefix, $ext)
  {
    $fileMD5 = '';
    for ($i=0;$i<count($list);$i++)
    {
      if (file_exists($list[$i]))
        $fileMD5 .= $list[$i] . filemtime($list[$i]);
      else
        die('File '. $list[$i] .' does not exists.');
    }

    return $prefix . '-' . md5($fileMD5) . '.' . $ext;
  }

  protected function check_cache ($local_cache_path, $prefix)
  {
    $dir = scandir($local_cache_path);
    $found = false;
    $i = 0;
    while (!$found &&  $i<count($dir))
    {
      $fileName = explode('-', $dir[$i]);
      $found = $fileName[0] == $prefix;
      ++$i;
    }

    if ($found) return $dir[$i-1];

    return false;
  }

  function css($list, $server_path, $prefix='css')
  {
    return self::files('css', $list, $server_path, $prefix);
  }

  function js($list, $server_path, $prefix='js')
  {
    return self::files('js', $list, $server_path, $prefix);
  }

  function files($ext = 'css', $list, $server_path, $prefix = 'css')
  {
    if ($ext != 'css' && $ext != 'js')
      die("Extension can be only 'css' or 'js'!");

    $server_path = '/'. trim($server_path, '/') . '/';
    $local_cache_path = $_SERVER['DOCUMENT_ROOT'] . $server_path; 

    $file_name = self::cache_file_name($list, $prefix, $ext);
    $destination_path = $local_cache_path . $file_name;
    $old_file_name = self::check_cache ($local_cache_path, $prefix);

    if($old_file_name != $file_name)
    {
      @unlink($local_cache_path . $old_file_name);

      $fp = fopen($destination_path,"w+");
      if ($ext == 'js')
        for($i=0;$i<count($list);$i++)
        {
          $data = file_get_contents($list[$i]);
          $data = JSMin::minify($data);
          $data = str_replace(
            array(";\n", "}\n", ")\n", "\nelse", "else {", "else\n"),
            array(";", "}", ")", " else", "else{", "else "),
            $data
          );
          fwrite($fp, $data);
        }
      else
        for($i=0;$i<count($list);$i++)
        {
          $data = file_get_contents($list[$i]);
          $data = preg_replace("|\/\*[\s\S]*\*\/|iU",'',$data);
          $data = preg_replace("|[\s]+|",' ',$data);
          $data = preg_replace("|[\s]*:[\s]*|",':',$data);
          $data = preg_replace("|[\s]*;[\s]*|",';',$data);
          $data = preg_replace("|[\s]*{[\s]*|",'{',$data);
          $data = preg_replace("|[\s;]*}[\s]*|",'}',$data);
          fwrite($fp, $data);
        }
      fclose($fp);
    }

    return $server_path . $file_name;
  }
}

Da bi koristili ovu klasu potrebno je skinuti JSMin za PHP sa adrese http://code.google.com/p/jsmin-php/ i staviti ga u isti direktorijum gde se nalazi i ova klasa.

Da bi sve ovo radilo, u vašem kodu potrebno je pozvati ovu ovu klasu na mestu gde učitavate vaše  fajlove.

<?php
  $css = minify_that::css(array('resources/reset.css', 'resources/style.css'), '/css');
?>

<link rel="stylesheet" type="text/css" media="screen" href="<?=$css;?>" />

Sa podrazumevanim podešavanjim potrebno je da na početnom direktorijumu vašeg servera imate ‘css’ poddirektorijum, i da mu dodelite prava za pisanje (0777)  i fajl koji će biti napravljen unutra, imaće ‘css’ prefiks.

Drugi deo posla je JS. Podrazumevani parametri za JS fajlove su da se smešta u ‘js’ poddirektorijum i da je prefiks ‘js’. Isto i ovde važi da direktorijum mora da bude sposoban za pisanje.

<?php
  $js = minify_that::js(array('resources/file1.js', 'resources/file2.js'), '/js');
?>

<script type="text/javascript" src="<?=$js;?>"></script>

Ovaj deo priče oko direktorijuma koji imaju pravo pisanja se odnosi na Linux servera, tačnije sam operativni sistem, koji ima mnogo složenija prava pristupa fajlovima i direktorijumima od Windowsa. Znači da se sve ovo ne odnosi na Windows, na kome većina programera kod nas radi. I to je to što se tiče kompresije fajlove, tj. samog smanjivanja fajlova, koje već samo po sebi da ubrza učitavanje strane.

Napomena: učitavanje JS fajlova smestite na dno vašeg koda iznad </body> taga. Ovo je još jedan usputni savet koji će povećati brzinu učitavanja vaše strane. Jer najčešće da bi vaša strana radila nije joj potrebno da se javascript učitava na vrhu u između <head> i </head>. Ukoliko imate takve skriptove oni mogu da se preprave tako da se učitavaju kasnije.

YUI Compressor

Da bi postigli još manje veličine pri optimizovanju, na internetu možete pronaći YUI Compressor. YUI Compresor će vam poboljšati kompresiju vaših JS fajlova za oko dodatnih 20%. Poređenje ću prikazati na fajlu JQuery.js 1.3.2.

  • Original veličina: 120,763 b
  • JSMin: 73,286 bajtova
  • YUI Compressor: 57,254 b

Ovim prikazom, dobitak koji ostvaruje YUI Compressor je očigledan. Problem je što se ovo morate obaviti kod vas na lokalu pa takav kompresovan fajl podići na server. Razlog tome je što je YUI Compressor pisan u Javi.

Napomena: za one koji ne znaju Java nije isto što i JavaScript, i obratite pažnju na to kada govorite i kada postavljate pitanja na forumima. Java je serverski jezik (server side), dok je JavaScript klijentski jezik (client side) i izvršava se u vašem browseru.

Da bi ga koristili potrebno je da ga skinete sa internet lokacije http://www.julienlecomte.net/yuicompressor/, raspakujete arhivu i iz komandne linije da startujete YUI Compressor.

Napomena: komandnu liniju će te pronaći u Start/Programs/Accessories/Command Prompt.

Za rad YUI Compressora potrebna vam je Java, najverovatnije je imate instaliranu, jer je pojedini programi traže za svoj rad. U slučaju da je nemate možete je preuzeti sa adrese http://java.com/en/download/index.jsp.

Za kraj kompresiju vaših fajlova obavljate tako što u komandnoj liniji napišete:

java -jar /neka/putanja/yuicompressor-2.4.2.jar --type js /putanja/nekompresovan.js > kompresovan.js

Ovde su vam četri stvari bitne, prva je da znate gde ste raspakovali arhivu sa YUI Compressora, druga je parametar type koji moze da bude js i css, putanja do fajla koji kompresujemo i na kraju iza znaka > se nalazi fajl u koji ćemo smestiti kompresovan tekst.

JavaScript – packed

Za JS se na internetu može pronaći još i packer na adresi http://dean.edwards.name/packer/, koji ne bih proporučio. Razlog tome je što se dekompresija ovakvih fajlova obavlja na lokalnom računaru. Iz ovog razloga stranica izgleda da se sporo učitava, još jedan problem je što browser u svom kešu čuva ovakve pakovane fajlove i prilikom svakog ponovnog učitavanja stranice, ponovo ih raspakuje, što dovodi do nepotrebnog usporavanja. Bolje je ostaviti fajlove i ne pakovane jer će ih browser mnogo brže obrađuje.

Sva ova priča oko brzine JS je vezana za brzinu izvršavanja JS u aktuelnim verzijama browsera. U najavi su nove verzije browsera (Firefox 3.5, Opera 10, Safari 4, Chrome 1.0) koje već sad, u raznim stadijumima razvoja, imaju vrlo dobre brzine izvršavanja javascripta. Trenutno ni jedan od ovih browsera nije u finalnoj verziji, ali ih možemo očekivati do kraja godine. Jedini browser koji nema nikakve naznake ubrzanja javascripta je Internet Explorer, kojem je aktuelna verzija 7, a u razvoju je verzija 8. Ovo treba uzeti u obzir je IE i dalje browser sa najvećom pokrivenošću tržišta. Iz tog razloga treba izbegavati ovakvo rešenje, jer ćete imati gomilu nezadovoljnih posetilaca.

Inače među početnicima koji su napisali neki JavaScript i misle da je to nešto jako dobro, i često žele da zaštite svoj rad, najčešće koriste ovaj tip kompresije, zato što na prvi pogled kod koji se dobije iz ovakvog kopresora je totalno nečitljiv. Treba biti svestan toga da je JavaScript klijentski jezik koji se izvršava u browseri da je ovakav kod moguće raspakovati i videti šta u njemu piše. Tako da na kraju kad se sve sabere, nema uštede ni na brzini, a nema ni zaštite vašeg koda.

Provera ispravnosti JavaScript fajlova

Pre bilo kakve kompresije potrebno je proveriti ispravnost vaših JS fajlova, jer se može desiti da fajl koji je ispravno radio dok je bio ne kompresovan, kada se kompresuje počne da prijavljuje greške. Pošto je skript kompresovan, vrlo je teško pronaći gde je greška, jer se sve nalazi u jednoj liniji. Rešenje je JSLint, lično sam ga koristio par puta više iz radoznalosti, a ne iz preke potrebe. Možete da naučite par stvari oko lepšeg pisanja JavaScript fajlova.


Ostavi komentar

Posetite naše prijatelje!

Tražite nešto?

Koristite donju formu za pretragu:

Još uvek niste našli šta tražite? Ostavite komentar za tekst ili nas kontaktirajte, pa ćemo probati da sredimo to!