Home > General, PHP > jsmin as a PHP extension – JavaScript Minify the Fast Way

jsmin as a PHP extension – JavaScript Minify the Fast Way

June 11th, 2009

Yahoo’s performance docs and Google’s page speed best practices recommend that both external and inline javascript code is minified. Two popular tools for minifying JavaScript are JSMIN and YUI Compressor.

I needed to have an efficient solution that can minify javascript on the fly. Unfortunately these tools do not work because a process would need to be forked every time minification needed to be performed. In PHP, one possible solution is to use jsmin-php, but again this is a very slow option. jsmin-php is written in PHP code and parsing a JavaScript file in PHP is relatively slow.

So I decided to develop a php extension based on jsmin.c developed by Douglas Crockford. It creates a native PHP function included as a PHP extension (written in C as opposed to PHP). The speed and efficiency improvement over jsmin-php is over 25x!

Try it out!

Get it here

Install instructions (make sure you have development tools installed as well as PHP and its development components):
tar zxf php-jsmin-1.0.tgz
cd php-jsmin-1.0
phpize
sh ./configure
make
make install
(optional) in php.ini add the following line: extensions=jsmin.so

Sample code:

if (!extension_loaded('jsmin')) {
        dl('jsmin.so');
}
header('Content-Type: text/javascript');
echo jsmin(file_get_contents('my.js'));

I hope you find it useful.

General, PHP ,

  1. July 2nd, 2009 at 09:55 | #1

    Thanks Eric and Igor, you guys are my hero! This is much better than jsmin-php. Your install instructions worked perfectly under Gentoo Linux without any tweaks.

    You have inspired me too create a small PHP script to quickly minify javascript files on the commandline:

    #!/usr/bin/php
    <?php
    /**
     * jsmin for the commandline
     *
     * Feel free to use and distribute as you wish.
     * Don't blame me for any damage this script might produce
     */
    $instructions = "Usage: jsmin SOURCE [TARGET]
    Remove comments and unnecessary whitespace from JavaScript files.
    Example: jsmin test.js test.min.js";
    try {
       if (empty($argv[1])) {
           throw new Exception('Missing SOURCE argument!');
       }
       if (empty($argv[2])) {
           // no TARGET file specified, minify to STDOUT
           fwrite(STDOUT, trim(jsmin(file_get_contents($argv[1]))));
       }
       else if (!file_exists($argv[2])) {
           // TARGET file does not exist, minify to new file
           jsminPutContents();
       }
       else {
           // TARGET file exists, ask to overwrite existing file
           fwrite(STDOUT, "Overwrite '{$argv[2]}'? [Y/N]: ");
           if (strtoupper(trim(fgets(STDIN))) === 'Y') {
               jsminPutContents();
           }
           else {
               exit(fwrite(STDOUT, "user aborted!\n"));
           }
       }
    }
    catch (Exception $e) {
       fwrite(STDOUT, 'ERROR: ' . $e->getMessage() .
          "\n{$instructions}\n");
    }
    function jsminPutContents() {
       global $argv;
       file_put_contents($argv[2],
          trim(jsmin(file_get_contents($argv[1]))));
       fwrite(STDOUT, "done!\n");
    }
    // EOF
    

    This code presumes that you are running PHP5, that PHP-CLI is located at /usr/bin/php, that the above script is named ‘jsmin’ and is executable and resides in your system PATH. The only thing I noticed is that jsmin outputs content with leading newlines, that is why I have wrapped the output with a trim(). Feel free to use this script at your own risk (of overwriting existing files) in any way you wish.

  2. smcnally
    July 16th, 2009 at 14:57 | #2

    thanks for this module, Igor.

    I’m wondering where I need to run make / make install from:

    I’m on Ubuntu 9.04 and have got apache modules here:

    /usr/lib/apache2/modules

    and php modules here:

    /usr/lib/php5/20060613/

  3. July 16th, 2009 at 15:05 | #3

    From the directory that was created when you untared the file. You should be able to issue each one of those commands exactly as shown in that order.

  4. smcnally
    July 16th, 2009 at 16:08 | #4

    thanks – I untarred the file in my home dir.

    should i untar it from elsewhere?

    (i am not seeing jsmin as a module in phpinfo after an apache restart, so I’m presuming untarring / make / make install from my home dir didn’t place the req’d files in the correct place[s])

  5. smcnally
    July 16th, 2009 at 17:33 | #5

    update: i didn’t have php5-cli installed. I installed that, re-ran through Igor’s instructions above and ran a test. It’s working.

    The output from make was less-than clear to me w/r/t where the libs we’re being placed. I had to run make install as su. (apologies if these are Duh!, but …)

    there’s still no sign of jsmin in phpinfo, so I ran a test to confirm i can minify. Confirmed.

    Very much looking forward to using this. Many thanks

  6. July 23rd, 2009 at 18:32 | #6

    I would recommend wrapping this in a function so you can include some caching. This will help you run minify only once an hour, max.

    function minify($file)
    {
    $cache = ‘cache-’.$file;

    if(!file_exists($cache) || filemtime($cache) > 3600)
    {
    $content = jsmin(file_get_contents($file));
    file_put_contents($cache, $content);
    }

    return file_get_contents($cache);
    }

    Usage:

    if (!extension_loaded(‘jsmin’))
    {
    dl(‘jsmin.so’);
    }
    header(‘Content-Type: text/javascript’);

    echo minify(‘my.js’);

  7. July 23rd, 2009 at 18:43 | #7

    @smcnally
    The extension gets installed to wherever your PHP extensions are kept. It varies for every installation. If you want to load jsmin in apache automatically, you need to edit your php.ini file and add the extension line.

  8. September 8th, 2009 at 19:20 | #8

    JSMin by default strips conditional compilation. This can be avoided by a simple patch (but this modification isn’t spreaded through the web). Web Optimizer ( http://code.google.com/p/web-optimizator/ ) has JSMin included (among YUI Compressor and Packer) and can help in automation of minify and merging you client side logic.

  9. thundercat
    May 14th, 2010 at 15:17 | #9

    Hi… I just installed this and it works great… does it work with CSS as well?

  10. Ricardo
    May 17th, 2010 at 20:27 | #10

    Hi there,
    I’m trying to compile it on Win32 but I’m getting a lot of errors.
    Do you or anyone has the DLL to win32?
    Thanks,
    Ricardo

  11. May 17th, 2010 at 20:35 | #11

    @Ricardo
    What’s a “Win32?” These are strange and weird words you’re using.

  12. Ricardo
    May 18th, 2010 at 08:13 | #12

    Eric, I’m tying to build the extension on Windows but it gives a lot of errors. There’s any mean to surpass this? Alternative to this?
    Thanks,
    Ricardo

  13. June 9th, 2010 at 15:30 | #13

    I just realized this extension doesn’t seem to be multibyte safe :( Can anyone else verify this?

  14. June 9th, 2010 at 15:44 | #14

    @1001 Fonts

    That may be the case. The extension is a straight port of jsmin.c with a few thread-safe changes. Do you have an example?

  15. June 10th, 2010 at 04:44 | #15

    Try the folling PHP code. NOTE the code must be UTF8 encoded or at least some other multibyte encoding.

    [code]

    [/code]

    outputs: var utf8Test=’ ‘;
    expected: var utf8Test=’€’;

    @igor

  16. June 10th, 2010 at 04:47 | #16

    @igor
    Try the folling PHP code. NOTE the code must be UTF8 encoded or at least some other multibyte encoding.

    <?php echo (jsmin(“var utf8Test = ‘€’;”)); // EURO SIGN U+20AC, ?>

    outputs: var utf8Test=’ ‘;
    expected: var utf8Test=’€’;

  17. August 12th, 2010 at 06:35 | #17

    Hi.

    It seems that jsmin was made to work with older versions of PHP ( which needed old version of libtool ), because on my current (updated) distribution of Gentoo Linux (kernel 2.6.31, gcc 4.3.4, glibc 2.11.2, libtool 2.2.6b, php 5.2.13), it fails on compiling jsmin, after phpize and configure:

    $ make
    /bin/sh /usr/local/src/php-jsmin-1.0/libtool –mode=compile cc -I. -I/usr/local/src/php-jsmin-1.0 -DPHP_ATOM_INC -I/usr/local/src/php-jsmin-1.0/include -I/usr/local/src/php-jsmin-1.0/main -I/usr/local/src/php-jsmin-1.0 -I/usr/lib64/php5/include/php -I/usr/lib64/php5/include/php/main -I/usr/lib64/php5/include/php/TSRM -I/usr/lib64/php5/include/php/Zend -I/usr/lib64/php5/include/php/ext -I/usr/lib64/php5/include/php/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /usr/local/src/php-jsmin-1.0/jsmin.c -o jsmin.lo
    /usr/local/src/php-jsmin-1.0/libtool: line 467: CDPATH: command not found
    /usr/local/src/php-jsmin-1.0/libtool: line 1152: func_opt_split: command not found
    libtool: Version mismatch error. This is libtool 2.2.6b, but the
    libtool: definition of this LT_INIT comes from an older release.
    libtool: You should recreate aclocal.m4 with macros from libtool 2.2.6b
    libtool: and run autoconf again.
    make: *** [jsmin.lo] Error 63

    Do you have a newer version of jsmin which might work with this libtool 2.2.6b ?

  18. dale
    August 20th, 2010 at 12:02 | #18

    great extension, @igor. as long as the php-cli package is installed, set up is an absolute breeze – took me less than 5 minutes to get everything running!

  19. dale
    August 25th, 2010 at 15:21 | #19

    @igor, my previous comment was about installing this extension on a linux box. however, I’m trying to compile this on my local install of MAMP and it is compiling it as a 64-bit .so file, but my MAMP needs a ppc and/or i386 version in order for the extension to work successfully. any ideas on how to accomplish this?

  20. September 2nd, 2010 at 03:25 | #20

    Hi guys,

    I patched the code for work with utf8:

    —- utf8.patch —————————

    — jsmin-old.c 2009-03-28 04:07:52.000000000 +0100
    +++ jsmin.c 2010-09-01 10:12:34.355394829 +0200
    @@ -101,7 +101,7 @@
    int theB;
    int theLookahead;
    int error;
    - char *data;
    + unsigned char *data;
    smart_str *buf;
    } jsmin_ctx;

    @@ -366,7 +366,7 @@
    Return a string to confirm that the module is compiled in */
    PHP_FUNCTION(jsmin)
    {
    - char *arg = NULL;
    + unsigned char *arg = NULL;
    int arg_len;
    jsmin_ctx *ctx;
    smart_str buf = {0};

    ———- end of file ———————–

    ——– PHP Test —————————-

    ——— end of file ————————

  21. September 2nd, 2010 at 03:29 | #21

    @Diego Campoy

    ——– PHP Test ———————————–
    $utf8 = “résumé”;
    echo ($utf8==jsmin($utf8))?”ok”:”fail”;

    ——– End of file ———————————–

  22. September 11th, 2010 at 21:10 | #22

    @Phil, this is an issue with your php build.

    @dale, I am not sure I follow. There is nothing in the package that forces the 64-bit build.

  23. October 13th, 2010 at 07:25 | #23

    @Igor
    I’m not sure that’s a problem with my php build, because the Gentoo Linux isn’t so new and unstable, and it’s used by a large linux comunity !
    But to show you guys that I found a temporary solution for php-jsmin-1.0, that you can implement later in your configure/Makefile:

    source=`dirname $0`

    cc -I. -I$source -DPHP_ATOM_INC \
    -I$source/include -I$source/main \
    -I$source -I/usr/lib64/php5/include/php \
    -I/usr/lib64/php5/include/php/main -I/usr/lib64/php5/include/php/TSRM \
    -I/usr/lib64/php5/include/php/Zend -I/usr/lib64/php5/include/php/ext \
    -I/usr/lib64/php5/include/php/ext/date/lib -DHAVE_CONFIG_H -g -O2 \
    -c $source/jsmin.c -o jsmin.o -fPIC -DPIC

    cc -shared jsmin.o -Wl,-soname -Wl,jsmin.so -o jsmin.so

    This worked very fine for me, compiled me the jsmin.so with no errors, and now I use it on 4 web servers that are in production !
    Thanks for no help :)

  24. Joseph
    October 21st, 2010 at 16:34 | #24

    I’ve installed jsmin.c and it’s a 1600x speedup (Yes, one six zero zero) over jsmin.php.

    jsmin.php 25 secs to minify
    jsmin.c 0.016 secs to minify

    LIGHTNING, BABY BOY!

  25. February 16th, 2011 at 05:12 | #25

    works great, many many thanks!

  26. Brian
    April 15th, 2011 at 12:38 | #26

    I was excited to try this out. However, after installing it correctly on my Mac and making the necessary change to my php.ini in MAMP, I get the following error:

    PHP Warning: PHP Startup: Unable to load dynamic library ‘/Applications/MAMP/bin/php5.2/lib/php/extensions/no-debug-non-zts-20060613/jsmin.so’ – (null) in Unknown on line 0

    Any idea how to get around this?

  27. April 15th, 2011 at 19:52 | #27

    I don’t know anything about MAMP or Macs… but searching for that error shows that it’s a fairly common error on OSX with PHP. According to one person, it’s possible it didn’t compile properly, but I can’t make any guesses one way or the other. You may want to look for some help with compiling extensions on some Mac forums.

  28. Attila
    July 5th, 2011 at 18:41 | #28

    Thank you for this extension. I am using this for three months now and with pleasure :)

    Diego, thanks for the quick fix, it works for me as well.

  29. Ebrahim Imami
    July 23rd, 2011 at 00:31 | #29

    jsmin extension removes non-english characters that exists inside .js file

    in my case , jsmin removes persian characters !
    What is the reason !?

  30. March 23rd, 2012 at 01:18 | #30

    Hello Igor,

    Could you host the project publicly?

  31. March 23rd, 2012 at 01:48 | #31
  32. June 6th, 2012 at 14:34 | #32

    Where I need to put the folder? I put it in /opt and install, but it doesn’t work…

    Cent OS.

  33. Brett
    August 8th, 2013 at 18:12 | #33

    I get the following warn/error when I build:

    /Users/xxxxxxxxxxxxxxx/Downloads/php-jsmin-1.0/jsmin.c:86:35: warning: ‘/*’ within block comment [-Wcomment]
    NULL, /*PHP_RSHUTDOWN(jsmin), /* Replace with NULL if there’s nothing to do at request end */
    ^
    /Users/xxxxxxxxxxxxxxx/Downloads/php-jsmin-1.0/jsmin.c:211:7: error: non-void function ‘jsmin_next’ should return a
    value [-Wreturn-type]
    return;
    ^

  1. June 23rd, 2009 at 16:21 | #1