I’m currently working on an in-house management system here at Tyrrell Systems, and employ a lot (seriously, a lot) of javascript for everything from ajax loading of information to various layout tweaks and so on.
When I inherited the project (a good 2 years ago now) the previous coders had made use of various scripts they’d found on the web, as well as a lot of hand crafted stuff. I started swapping things over to the rather spiffy Jquery library and added a load more functionality.
However, the system has inevitably started to slow down over the last year or so, loading in all those javascript libraries has taken its toll on page load times. As well as the javascript overhead there’s also around 30 different css files to load in (I like to keep things well segregated!). This leads to the following problem:
As you can see, it was taking nearly 30 seconds just to load in the css & javascript for a typical page.
So, I started looking for a solution. Now, the general (and rather obvious) approach to this is to ‘munge’ all your css (or javascript) files into one big file, run that through some kind of optimiser and then serve the resulting file instead. This reduces page requests & bandwidth used in one go. This is a good example of this general approach. Unfortunately, 90% of these scripts rely on using mod_rewrite to redirect calls to css / js files through a PHP script. My site runs on IIS, so they’re no good for me. To cut a long story short, I decided to write a class that would:
- Allow me to merge multiple css / js files into 1.
- optionally optimise that file before serving it.
- Cache the output so I only have to do this process when I actually change any of the css / javascript.
This is what I came up with. It makes use of jsmin-php for javascript minification, and css-tidy for well, css-tidying so you’ll need to have those if you want to use optimisation. Or you can optionally turn it off. To use the class:
First initialise it:
$main-css = new cacher("main.css","css");
The first parameter is a filename (can be anything you like) and the second is the type (must be css or js).
Next we add our files:
$main-css->add_file("path/to/my/file.css");
or we can add every css/js file in a folder like so:
$main-css->add_folder("path/to/my/folder/");
then when we’ve added everything, we output the files:
$main-css->output();
The output file will be cached (in /theme/cache by default) until you delete the cached copy from that folder. So if you change any of the files included using this class, remember to delete your cached file!
and that’s it.
Just to complete the before / after theme here’s what this did to my loading times:
Here’s the code (as usual, it’s free to use but please give some credit if you do).
nb: the variable $cfg used here is a global class used in the project this came from. Basically, $cfg->root needs to point at the webroot for your project.
<?php class cacher{ function __construct($filename,$type) $this->type = $type; $this->filename = $cfg->root."\theme\cache\".$filename; $this->url = "/theme/cache/$filename"; $this->optimise = $optimise; if (file_exists($this->filename)) { $this->output(); $this->cached = true; } else { $this->cached = false; $this->fh = fopen($this->filename,"a") or die("unable to open file $this->filename"); } } function add_folder($newfolder){ global $cfg; if ($this->cached == true){ return; } else { $dh = opendir($cfg->root.$newfolder); while (false !== ($file = readdir($dh))){ $ext = substr($file,strrpos($file,'.')+1); if ($this->type == $ext){ fwrite($this->fh,file_get_contents($cfg->root.$newfolder."\".$file)); fwrite($this->fh,"n"); } } closedir($dh); } } function add_file($newfile){ if ($this->cached == true){ return; } else { fwrite($this->fh,file_get_contents($newfile)); fwrite($this->fh,"n"); } } function output(){ if ($this->cached == true){ return; } else { if ($this->type == "css"){ fclose($this->fh); if ($this->optimise == true){ require("lib/csstidy/class.csstidy.php"); $css_out = new csstidy(); $css_out->parse(file_get_contents($this->filename)); $this->fh = fopen($this->filename,"w"); fwrite($this->fh,$css_out->print->plain()); fclose($this->fh); } echo ""; } elseif ($this->type == "js") { fclose($this->fh); if ($this->optimise == true){ require("lib/jsmin/jsmin.php"); $js_out = JSMin::minify(file_get_contents($this->filename)); $this->fh = fopen($this->filename,"w"); fwrite($this->fh,$js_out); fclose($this->fh); } echo ""; } } } } ?>
Hi,
Is it possible that a part of the code is missing? I think the start is missing there
Hi Samuel, it was indeed! I’ve amended the code sample, cheers for pointing that out 🙂