Compressing JavaScript in PHP (no comments or whitespace)

Note: if you’re a web developer you might be interested in registering to become a ProgClub member. ProgClub is a free international club for computer programmers and we run some mailing lists you might like to hang out on to chat about software development, life, etc.

Given that I’ve been working on compressing CSS and compressing HTML in PHP, it’s only natural that I’m interested in JavaScript compression too. I haven’t done much research on the topic — I’m sure there are better tools out there than the one I’ve cobbled together — but for the sake of it here’s my first take on JavaScript compression in PHP:

function slib_compress_script( $buffer ) {

  // JavaScript compressor by John Elliot <jj5@jj5.net>

  $replace = array(
    '#\'([^\n\']*?)/\*([^\n\']*)\'#' => "'\1/'+\'\'+'*\2'", // remove comments from ' strings
    '#\"([^\n\"]*?)/\*([^\n\"]*)\"#' => '"\1/"+\'\'+"*\2"', // remove comments from " strings
    '#/\*.*?\*/#s'            => "",      // strip C style comments
    '#[\r\n]+#'               => "\n",    // remove blank lines and \r's
    '#\n([ \t]*//.*?\n)*#s'   => "\n",    // strip line comments (whole line only)
    '#([^\\])//([^\'"\n]*)\n#s' => "\\1\n",
                                          // strip line comments
                                          // (that aren't possibly in strings or regex's)
    '#\n\s+#'                 => "\n",    // strip excess whitespace
    '#\s+\n#'                 => "\n",    // strip excess whitespace
    '#(//[^\n]*\n)#s'         => "\\1\n", // extra line feed after any comments left
                                          // (important given later replacements)
    '#/([\'"])\+\'\'\+([\'"])\*#' => "/*" // restore comments in strings
  );

  $search = array_keys( $replace );
  $script = preg_replace( $search, $replace, $buffer );

  $replace = array(
    "&&\n" => "&&",
    "||\n" => "||",
    "(\n"  => "(",
    ")\n"  => ")",
    "[\n"  => "[",
    "]\n"  => "]",
    "+\n"  => "+",
    ",\n"  => ",",
    "?\n"  => "?",
    ":\n"  => ":",
    ";\n"  => ";",
    "{\n"  => "{",
//  "}\n"  => "}", (because I forget to put semicolons after function assignments)
    "\n]"  => "]",
    "\n)"  => ")",
    "\n}"  => "}",
    "\n\n" => "\n"
  );

  $search = array_keys( $replace );
  $script = str_replace( $search, $replace, $script );

  return trim( $script );

}

It’s funny, but jQuery actually choked on my original function because it contains a few strings like “*/*”. To fix the problem I had to patch jQuery with “*/”+”*”, but then I decided to handle that case in my code. Of course jQuery comes pre-minified by tools much more sophisticated than mine. My tool compresses the 230 KB jQuery file to 150 KB, whereas the tool jQuery uses compresses the file to 90 KB. So I think I have my work cut out for me! It was a fun hack though.

2 thoughts on “Compressing JavaScript in PHP (no comments or whitespace)

  1. Here is regex I wrote for myself as a addon for the scriptmerge plugin for JOOMLA so it also works on mootools. And yes its also compression script in PHP to remove comments and withe spaces and without damage to the javascript. Tested it extensively. Yerico put it in there plugin in 2013 to amuse me it still in there as simple script so I think it is working fine So everyone looking for compression script in PHP for Javascript now you can choose out of both scripts on this blog hope it helps someone…
    It solves losts of comment remove problems and it is fast in comparison to PHP solutions.

    [code]
    //START Remove comments.

    $buffer = str_replace(‘/// ‘, ‘///’, $buffer);
    $buffer = str_replace(‘,//’, ‘, //’, $buffer);
    $buffer = str_replace(‘{//’, ‘{ //’, $buffer);
    $buffer = str_replace(‘}//’, ‘} //’, $buffer);
    $buffer = str_replace(‘*//*’, ‘*/ /*’, $buffer);
    $buffer = str_replace(‘/**/’, ‘/* */’, $buffer);
    $buffer = str_replace(‘*///’, ‘*/ //’, $buffer);
    $buffer = preg_replace(“/\/\/.*\n\/\/.*\n/”, “”, $buffer);
    $buffer = preg_replace(“/\s\/\/\”.*/”, “”, $buffer);
    $buffer = preg_replace(“/\/\/\n/”, “\n”, $buffer);
    $buffer = preg_replace(“/\/\/\s.*.\n/”, “\n \n”, $buffer);
    $buffer = preg_replace(‘/\/\/w[^w].*/’, ”, $buffer);
    $buffer = preg_replace(‘/\/\/s[^s].*/’, ”, $buffer);
    $buffer = preg_replace(‘/\/\/\*\*\*.*/’, ”, $buffer);
    $buffer = preg_replace(‘/\/\/\*\s\*\s\*.*/’, ”, $buffer);
    $buffer = preg_replace(‘/[^\*]\/\/[*].*/’, ”, $buffer);
    $buffer = preg_replace(‘/([;])\/\/.*/’, ‘$1’, $buffer);
    $buffer = preg_replace(‘/((\r)|(\n)|(\R)|([^0]1)|([^\”]\s*\-))(\/\/)(.*)/’, ‘$1’, $buffer);
    $buffer = preg_replace(“/([^\*])[\/]+\/\*.*[^a-zA-Z0-9\s\-=+\|!@#$%^&()`~\[\]{};:\’\”,?]/”, “$1”, $buffer);
    $buffer = preg_replace(“/\/\*/”, “\n/*dddpp”, $buffer);
    $buffer = preg_replace(‘/((\{\s*|:\s*)[\”\’]\s*)(([^\{\};\”\’]*)dddpp)/’,’$1$4′, $buffer);
    $buffer = preg_replace(“/\*\//”, “xxxpp*/\n”, $buffer);
    $buffer = preg_replace(‘/((\{\s*|:\s*|\[\s*)[\”\’]\s*)(([^\};\”\’]*)xxxpp)/’,’$1$4′, $buffer);
    $buffer = preg_replace(‘/([\”\’])\s*\/\*/’, ‘$1/*’, $buffer);
    $buffer = preg_replace(‘/(\n)[^\'”]?\/\*dddpp.*?xxxpp\*\//s’, ”, $buffer);
    $buffer = preg_replace(‘/\n\/\*dddpp([^\s]*)/’, ‘$1’, $buffer);
    $buffer = preg_replace(‘/xxxpp\*\/\n([^\s]*)/’, ‘*/$1’, $buffer);
    $buffer = preg_replace(‘/xxxpp\*\/\n([\”])/’, ‘$1’, $buffer);
    $buffer = preg_replace(‘/(\*)\n*\s*(\/\*)\s*/’, ‘$1$2$3’, $buffer);
    $buffer = preg_replace(‘/(\*\/)\s*(\”)/’, ‘$1$2’, $buffer);
    $buffer = preg_replace(‘/\/\*dddpp(\s*)/’, ‘/*’, $buffer);
    $buffer = preg_replace(‘/\n\s*\n/’, “\n”, $buffer);
    $buffer = preg_replace(“/([^\’\”]\s*)(?!()).*/”,”$1″, $buffer);
    $buffer = preg_replace(‘/([^\n\w\-=+\|!@#$%^&*()`~\[\]{};:\'”,\/?\\\\])(\/\/)(.*)/’, ‘$1’, $buffer);

    //END Remove comments.

    //START Remove all whitespaces
    $buffer = preg_replace(‘/\s+/’, ‘ ‘, $buffer);
    $buffer = preg_replace(‘/\s*(?:(?=[=\-\+\|%&\*\)\[\]\{\};:\,\.\\!\@\#\^`~]))/’, ”, $buffer);
    $buffer = preg_replace(‘/(?:(?<=[=\-\+\|%&\*\)\[\]\{\};:\,\.\\?\!\@\#\^`~]))\s*/’, ”, $buffer);
    $buffer = preg_replace(‘/([^a-zA-Z0-9\s\-=+\|!@#$%^&*()`~\[\]{};:\'”,\/?])\s+([^a-zA-Z0-9\s\-=+\|!@#$%^&*()`~\[\]{};:\'”,\/?])/’, ‘$1$2’, $buffer);

    //END Remove all whitespaces
    [/code]

Leave a Reply