An Opening Word
In
How to Compress Perl/CGI-Scripts... and
How to Compress PHP and Other Text-Based Files..., I write about achieving better standards according to Yahoo’s
Best Practices for Speeding up Websites guide.
If your server supports PHP5, now there is an incredibly easy way to minify both JavaScript and CSS files on the fly, PLUS a way to combine a number of different files into a single HTTP request.
(See Step 4 of my blog entry on compressing PHP scripts to convert your site to PHP5, particularly if you are using a 1&1 shared hosting package.)
Thanks to
Ryan Grove and
Steve Clay,
Minify! is now here
(download link). As the source page on GoogleCode suggests, it
combines, minifies, and caches JavaScript and CSS files on demand to speed up page loads.Setup and Basic Use
Just download the zip file and drop the
min folder in your root directory.
Then, to include single resources on your page, just set them up like the following with
?f= (
f short for "file"), followed by the URL of the resource:
// css
<link rel="stylesheet" href="/min/?f=/path_to_file/file.css" type="text/css" />
// js
<script type="text/javascript" src="/min/?f=/path_to_file/file.js"></script>
You can also use URL-rewriting if your host supports it (see
Note below):
// js -- notice the "?" before the "f" has been dropped
<script type="text/javascript" src="/min/f=/path_to_file/file.js"></script>
Minify comes with its own URL-builder for easily creating and checking links which you can access at
http://name_of_your_site_here.com/min/index.php once you have it installed on your server.
The builder interface itself will teach you how to serve groups of files as a single, minified resource by adding a few lines to
/min/groupsConfig.php, but we'll go ahead and look at it here anyway:
// In /min/groupsConfig.php, I set up the unique identifier "js"
// to specify a group of 5 hypothetical JS files
return array(
'js' => array(
'//js/file1.js',
'//js/file2.js',
'//js/file3.js',
'//js/file4.js',
'//js/file5.js'
)
);
You can then include this group of files in your HTML tag by specifying
g (for "group"), followed by your unique
js identifier.
<script type="text/javascript" src="/min/g=js"></script>
Or you can take full advantage of comma-delimited arrays and set up as many sets of files paired with unique identifiers as you want (of course including any CSS files using the
link tag, as shown in the first example on this page):
// "js" and "css" file groups set in /min/groupsConfig.php
return array(
'js' => array(
'//js/file1.js',
'//js/file2.js',
'//js/file3.js',
'//js/file4.js',
'//js/file5.js'
),
'css' => array(
'//css/file1.css',
'//css/file2.css',
'//css/file2.css'
)
);
Setting a Long Cache Life for Your Pages
Minify's default cache life is 30 minutes for CSS and JS files. This works well for development servers, but for production servers with stable code, a longer cache time is recommended. Your can easily implement a year-long cache life in the HTML simply by appending a number (yes, any number) as a query string variable.
// css
<link rel="stylesheet" href="/min/g=css&1" type="text/css" />
// js
<script type="text/javascript" src="/min/g=js&1"></script>
However, you
must update this number if you make changes to these files and it is important that users have the latest versions. For this reason, I recommend starting off with the number 1 and incrementing it as your changes dictate, though as long as the numbers are always different, it makes no difference how you do it.
Since this approach requires manual editing, this may not be optimal for you. For the full spectrum of caching possibilities, see the developer doc
HttpCaching; for advanced options of specifying a different cache system (as well as other advanced uses) see the
CookBook doc.
For more general use ideas, including how to specify a
b for "base directory" when a group of single files all share the same root directory path, see the developer README file beginning with the heading "
Minifying a Single File"; for advanced usage beyond the scope of the examples here, see the developer comments at
CustomSource.
Note: If you want to use rewritten urls and you are using a Linux shared hosting package with
1&1 (and maybe even if you're not), you will probably need to make a small adjustment to the included
.htaccess file in the
min directory. The line in the native code you're after reads as follows:
RewriteRule ^([a-z]=.*) index.php?$1 [L,NE]
but you will probably need to change it:
RewriteRule ([a-z]=.*) /min/index.php?$1 [L,NE]
Also to point out the obvious, make sure if you put the
min directory a level deeper (see below), you specify the sub-directory: for example, /
myscripts/min/index.php.
Note on Use Inside A Sub-Directory
By default, Minify is intended to have the
min directory parked at the root level. It works just fine a directory level deeper, however, though this sometimes causes problems with the URL-building interface. The developer docs recommend a solution that uses PHP; see
AlternateFileLayouts.
If you prefer to hatch a solution to the builder interface in JavaScript, you'll need to modify the code slightly. Use your IDE or text editor to open the
_index.js file found in the
builder directory.
The first block of code currently reads as follows; our interest here all deal with
_minRoot:
var MUB = {
_uid : 0
,_minRoot : '/min/?'
,checkRewrite : function () {
var testUri = location.pathname.replace(/\/[^\/]*$/, '/rewriteTest.js').substr(1);
function fail() {
$('#minRewriteFailed')[0].className = 'topNote';
};
$.ajax({
url : '../f=' + testUri + '&' + (new Date()).getTime()
,success : function (data) {
if (data === '1') {
MUB._minRoot = '/min/';
$('span.minRoot').html('/min/');
} else
fail();
}
,error : fail
});
}
Replace this with the following code, which is not particularly pretty, but is "smart" and will read the location of the directory when the script is called, no matter how many levels deep. The three changes are marked below by the comment
// here.
var MUB = {
_uid : 0
,_minRoot : location.pathname.replace('/builder/', '') + '?' // here
,checkRewrite : function () {
var testUri = location.pathname.replace(/\/[^\/]*$/, '/rewriteTest.js').substr(1);
function fail() {
$('#minRewriteFailed')[0].className = 'topNote';
};
$.ajax({
url : '../f=' + testUri + '&' + (new Date()).getTime()
,success : function (data) {
if (data === '1') {
MUB._minRoot = MUB._minRoot.replace('?', ''); // here
$('span.minRoot').html(MUB._minRoot); // here
} else
fail();
}
,error : fail
});
}