I’ve talked about how you can speed up your web site by serving less files, now its time to get our hands dirty and see how we can easily combine several files into one.
This will prove to be a very simple but handy addition to your toolkit.
As we are working with several paths for the same file (the physical path and its URL) we need to know the root physical path and URL of your web site, (there is an easy and automatic way to do this) that will be the most tricky situation you will find.
Combining JS files into one is fairly easy, just join then !
Combining several CSS files can be tricky as you might have relative paths in them, so we will replace them with full paths.
Be aware that if you use css to preload images this might break it because the image path will change from img/image.jpg to something like http://www.site.com/path/to/imagef-folder/image.jpg.
Also, the cached file will be served as plain text, with no MIME information so you have to specify an .css extension or your browser wont parse it as being CSS, this could easily be done automatically, but this is just a simple proof of concept.
The code is easy to follow and documented so i will just post typical usage examples but if have any questions about the code just leave a comment
Usage Example 1 : Javascript
$c = new fcDiet('path/to/cache/folder'); $c->webServerPath = 'http://mysite.com/'; $c->physicalPath = '/var/www/html/mysite/' ; $c->addFile('file1.js'); $c->addFile('file2.js'); $c->addFile('file3.js'); $c->addFile('file4.js'); echo '<script type="text/javascript" src="'.$c->get() .'"></script>'; |
Usage Example 2 : CSS
$c = new fcDiet('path/to/cache/folder'); $c->webServerPath = 'http://mysite.com/'; $c->physicalPath = '/var/www/html/mysite/' ; $c->replacePaths = true; $c->appendExtension('css'); $c->addFile('file1.css'); $c->addFile('file2.css'); $c->addFile('file3.css'); $c->addFile('file4.css'); echo '<link rel="stylesheet" type="text/css" href="'. $c->get().'" />'; |
The Code
/** * fcDiet * * A simple class to help you join your css and js files into one * * @author Nuno Costa - sven@francodacosta.com * @license GPL */ class fcDiet { public $physicalPath = ''; public $webServerPath = ''; public $replacePaths = false; private $cacheFolder = ''; private $files = null; private $chacheFileName = ''; private $extension = ''; private function createCacheFileName(){ $this->cacheFileName = $this->webServerPath . '/' . $this->cacheFolder. '/' . md5(implode('',$this->files)); if($this->extension != '') $this->cacheFileName .= '.' . $this->extension ; } private function replacePaths($buffer, $path){ $pattern = '/(url\s*)(\(\s*[\"|\']*)([:\/\w\s\d\.]*)([\"|\']*\s*\))/i'; $replace='url(' . str_replace($this->physicalPath, $this->webServerPath, $path) . '$3)'; $ret = preg_replace($pattern, $replace, $buffer); return $ret; } private function cacheHit($file){ return file_exists($file); } function __construct($cacheFolder = ''){ $this->cacheFolder = $cacheFolder ; $this->files = array(); } /** * Adds files to be joined */ function addFile($path){ $this->files[] = $path ; } /** * appends an extension to the cache file * no dot needed just use css instead of .css */ function appendExtension($extension){ $this->extension = $extension; } /** * returns the URL to the cache file * if the cache file does not exits it will be created */ function get(){ $this->createCacheFileName(); $cacheFile = str_replace($this->webServerPath,$this->physicalPath,$this->cacheFileName ); if(! $this->cacheHit($cacheFile)) { $buffer = ''; foreach($this->files as $f){ $tmp = file_get_contents($f) . "\n"; if($this->replacePaths){ //replace url tags with full url $buffer .= $this->replacePaths($tmp, dirname($f).'/'); }else{ $buffer.=$tmp; } } $fh = fopen($cacheFile, 'w'); fputs($fh, $buffer); fclose($fh); } return $this->cacheFileName; } } |

Hi,
This is a good idea but is not very efficient because the browser is loading several files at once and if you give him two big files it may take more time to load them. Of course it is good to combine css and js if they are many but they should be combined in more than 2 files (4 or 6)
@Pavlov
I don’t really agree with with you
Serving 4 files instead of one is a performance problem, you will be serving the same amount of data but with the overhead of making 4 network connections.
The time it takes to setup a network connection and wait for the first byte to arrive is a considerable slice of the total download time
There is no silver bullet when talking about performance. we need to test and see what works best for our specific case, but as a rule of thumb the less files the better
Yes, I agree with you – it depends on the size of the files – if they are smaller 2 files will be fine but if they are bigger (jquery, jquery ui, kendo ui, datatables or combination of them) it is best to be separated in more files.
Unfortunately there is no silver bullet as you sad and every site should be tested and the best solution implemented
@Pavlov
The size of the files is only relevant if you setup more than one host for your files.
Most browsers restrict the number of simultaneous connections to the same host, so having multiple files to download can be an huge problem (js + css + images all on the same host can lead to an increased waiting time)
Concurrency seems to be the key when talking about performance.
I usually organize my files in the following way:
* libraries and code used on all/most pages in one file
* page specific code on a separate file
I found this setup to work nicely for me.
Don’t forget about browser caching, if it is cached it won’t be downloaded again.
This setup will make sure that the response time is quick, as the global files are only downloaded one time
Another option is to lazy load the javascript files, but in most cases the advantage wont be that great when compared to the extra work you need to have