Packing Your Javascript w/o Sacrificing Performance using PHP, Caching and Apache
// June 24th, 2010 // Programming, Web Development // David Stinemetze
When coding, I’m not a fan of repetition. I don’t like doing things over and over again. I feel I should also mention that I only like doing things one time. One of the things I find to be a nuisance is having to repack my Javascript code every time I make a simple change to the original source.
Selecting an Encoder
I came across Nicolas Martin’s PHP port of Dean Edward’s Javascript Packer a year or so ago. It seemed to encode rather efficiently for what I needed it for and will be the packer I use in this example. However, should you choose to user an alternate packer or even an obfuscator, it should be easy enough to make the necessary changes.
Let’s pretend our original, unpacked source file is called “func.js” and is located in the “/scripts/” directory. In the same directory, upload the “class.JavaScriptPacker.php” file and create a file called “func.php” with the following contents:
-
<?php
-
// specify our source file
-
$src_file = "func.js";
-
-
require("class.JavaScriptPacker.php");
-
-
// make sure our src file exists
-
-
// fetch contents of source file
-
-
// pack code
-
$myPacker = new JavaScriptPacker($generatedoutput, 62, true, false);
-
$packed = $myPacker->pack();
-
-
// send Javascript headers and file contents
-
?>
In theory at this point you could get away with referencing this PHP file as your Javascript file:
-
<script type="text/javascript" src="scripts/func.php"></script>
Performance Draining
With how it stands now, this script would run every time a user hits a page. If it’s called on every page of a website, this can easily become tens or even hundreds of unnecessary packing operations per user. On a site serving more than 3 users per day, this can cause massive performance problems.
To correct this, we can implement caching. “func.js” is our original source file. So let’s create a new, empty file, called “func.js.cache”. Make sure the webserver has write permissions for the file (i.e. chmod 0666). Now we modify “func.php” to incorporate caching:
-
<?php
-
// specify our source file
-
$src_file = "func.js";
-
// specify our cache file
-
$cache_file = "func.js.cache";
-
-
// make sure our src file exists
-
-
// variable to determine if we will be using a cached file or not
-
$use_cache = false;
-
// Compare file time stamps. If the cache file is newer than the src file, then we use the cache file.
-
}
-
-
// send Javascript headers
-
-
if ($use_cache) {
-
// output the contents of the cache file
-
echo $contents;
-
} else {
-
require(‘class.JavaScriptPacker.php’);
-
-
// fetch contents of source file
-
-
// pack code
-
$myPacker = new JavaScriptPacker($generatedoutput, 62, true, false);
-
$packed = $myPacker->pack();
-
-
// send file contents
-
-
// write to file
-
}
-
?>
At this point, if you execute “func.php” you get an empty script. This is because your timestamp on your source file is older than the timestamp on your cache file. Either re-upload your source file, or run “touch” command on it to update the timestamp. Now execute “func.php” and you should see your packed script. View the contents of your “func.js.cache” file and it should match what you see in your browser.
Protecting Original Code
If you are using an obfuscator instead of or in addition to a packer, someone could always navigate to /scripts/func.js and find the original source code. You could move the source file to some other directory outside of your public_html directory, or you could use Apache Rewrites. In the /scripts/ directory, create an .htaccess file with the following contents:
-
Options +FollowSymLinks
-
RewriteEngine on
-
RewriteBase /scripts/
-
RewriteRule ^func.js$ func.php
Assuming your web server is configured to permit .htaccess files and rewrites, this will force anybody trying to access /scripts/func.js to actually display the contents of /scripts/func.php. This can help protect your original source code. This also works if you are just very particular about your Javascript files being referred to as “.js” files and not “.php” files like I am.
So now you can change your HTML code to:
-
<script type="text/javascript" src="scripts/func.js"></script>
So now whenever I update my “scripts/func.js” file, it feels natural because I see my HTML including “scripts/func.js” as well.
Multiple Files
With a little work, it would be easy enough to have this script process multiple Javascript files. For starters, let’s change our .htaccess to this:
-
Options +FollowSymLinks
-
RewriteEngine on
-
RewriteBase /scripts/
-
RewriteRule ^(.*)\.js$ func.php?src=$1
This tells apache to look for “any_javascript_file.js” and rewrite to “func.php?src=any_javascript_file”.
We now need to alter our “func.php”, but must make sure to be careful not to give hackers read access to our other files on our site. To play it safe, I will assume the only value characters in the filename that preceeds “.js” are alphanumeric characters, hyphens and dashes.
-
<?php
-
// strip out any pesky characters that may cause us security problems
-
$src_file = $src.".js";
-
$cache_file = $src.".js.cache";
-
-
// make sure our src file exists
-
-
// variable to determine if we will be using a cached file or not
-
$use_cache = false;
-
// Compare file time stamps. If the cache file is newer than the src file, then we use the cache file.
-
}
-
-
// send Javascript headers
-
-
if ($use_cache) {
-
// output the contents of the cache file
-
echo $contents;
-
} else {
-
require(‘class.JavaScriptPacker.php’);
-
-
// fetch contents of source file
-
-
// pack code
-
$myPacker = new JavaScriptPacker($generatedoutput, 62, true, false);
-
$packed = $myPacker->pack();
-
-
// send file contents
-
-
// write to file
-
}
-
?>
This now determines our source and cache files based on the passed parameter “src”. Notice that if a user specifies a file that does not exist with a “.js” extension, it will give them a nice little “Can’t find source file” message. If you wanted to, you could always have it produce a 404 “File Not Found” error as well.
One final thing you need to address is your cache file permissions. In this generic case, it may be easier to just allow apache to have write permission for your whole directory. However, if you have security issues with this, just create the empty cache files for each .js file like you did for func.js above. Make sure you set them to have write permission (0666) and then re-upload your original source files to update your timestamp.
What do you think?
Any tips on how I can further optimize this code? Did I make any tragic mistakes? Think I’m an idiot? I’d love to hear your comments.
/* Facebook */


What performance could be expected when used on small websites like my web search, http://soogle.net ?
I’m not sure if this is a serious question, or just a clever attempt at building links back to your site. If it’s the latter, I applaud you for your efforts and will let it stand, seeing as your site doesn’t appear to be malicious. If this was a serious question, I have no idea. I don’t know your platform. I don’t know your setup. I don’t know if you’re working in a cluster or on a single web server. But in theory, using caching, should have a minimal affect on your performance. Instead of it having to do complex conversions, it’s only having to read and output the contents of your javascript cache file. The only performance hit comes from the Apache Rewrites and the PHP that is being executed before your content is displayed. It’s never gonna be quite as fast as reading a javascript file directly, but I think the overhead is probably going to be minimal.
Your article was easy to follow and I found it interesting – thank you!
Have you heard of Minify? It’s a PHP5 script (I believe similar to yours) that minimizes and compresses javascript and css: http://code.google.com/p/minify/
Thanks for the comments. I had used Douglas Crawford’s minify (the project this seems to be based on) before, but didn’t realize it had been ported into this PHP project.
Their code seems to be bulkier and slightly more complicated than mine, but it probably is more powerful. I do like how it compresses CSS in addition to javascript and concatenates everything into a single file for an added performance boost.
I may consider expanding this code to do the same, just to have some comparable piece of code. It should be easy enough to do. If I end up doing it, I’ll post an addendum to this blog post with the new code.
Many thanks for this article. I came accrous searching for some technices building my web widget. Seems pretty usuall, but i can’t find any straightforward tutorial.
The widget should be for everyone free to include and displays content form my page. By now i’m so far, that i will make it in JS (instead of iframe) and i think it’s enough when i cache the results and update this file every 15 minutes or so. So your tutorial came really handy. Also thanks for the extension hint
Do you know another tutorial for building embeddable widgets?
I’m not sure what you mean by a “tutorial for building embeddable widgets”, but essentially what I’ve done in the past for embeddable javascript codes, is store the HTML content in some variable, such as some_html_content and then have the javascript file execute document.write(some_html_content). I dunno if that helps our not.
hey david, thanks for the reply. i will build the widget as described here – http://drnicwilliams.com/2006/11/21/diy-widgets/ so the js and php isn’t a problem. But he didn’t mengioned anything about caching. And as this is my weak point i wanted to ask you, if there is something to bear in mind. I will cache the output of the php file as described in your post, but is there anything important that i’m missing. Eventually i could even cache the php-file (which generates the cache) – client-side caching. or is this a bad idea….