1
0
mirror of https://github.com/mrclay/minify.git synced 2025-08-07 14:46:29 +02:00

Closure Compiler API minifier and unit test

JSMin preserves "/*!"
This commit is contained in:
Steve Clay
2010-08-02 00:30:24 +00:00
parent 5d9d81f875
commit c698941cc4
7 changed files with 175 additions and 3 deletions

View File

@@ -1,6 +1,7 @@
Minify Release History
Version 2.1.4
* Option to minify JS with Closure Compiler API w/ JSMin failover
* Cookie/bookmarklet-based debug mode. No HTML editing!
* Allows 1 file to be missing w/o complete failure
* Combine multiple groups and files in single URI

View File

@@ -102,6 +102,18 @@ $min_serveOptions['bubbleCssImports'] = false;
$min_serveOptions['maxAge'] = 1800;
/**
* To use Google's Closure Compiler API (falling back to JSMin on failure),
* uncomment the following lines:
*/
/*function closureCompiler($js) {
require_once 'Minify/JS/ClosureCompiler.php';
return Minify_JS_ClosureCompiler::minify($js);
}
$min_serveOptions['minifiers']['application/x-javascript'] = 'closureCompiler';
//*/
/**
* If you'd like to restrict the "f" option to files within/below
* particular directories below DOCUMENT_ROOT, set this here.

View File

@@ -308,7 +308,7 @@ class JSMin {
$this->get();
// if comment preserved by YUI Compressor
if (0 === strpos($comment, '!')) {
return "\n/*" . substr($comment, 1) . "*/\n";
return "\n/*!" . substr($comment, 1) . "*/\n";
}
// if IE conditional comment
if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {

View File

@@ -0,0 +1,109 @@
<?php
/**
* Class Minify_JS_ClosureCompiler
* @package Minify
*/
/**
* Minify Javascript using Google's Closure Compiler API
*
* @link http://code.google.com/closure/compiler/
* @package Minify
* @author Stephen Clay <steve@mrclay.org>
*/
class Minify_JS_ClosureCompiler {
const URL = 'http://closure-compiler.appspot.com/compile';
/**
* Minify Javascript code via HTTP request to the Closure Compiler API
*
* @param string $js input code
* @param array $options unused at this point
* @return string
*/
public static function minify($js, array $options = array())
{
$obj = new self($options);
return $obj->min($js);
}
/**
*
* @param array $options
*
* fallbackFunc : default array($this, 'fallback');
*/
public function __construct(array $options = array())
{
$this->_fallbackFunc = isset($options['fallbackMinifier'])
? $options['fallbackMinifier']
: array($this, '_fallback');
}
public function min($js)
{
$content = $this->_getPostContent($js);
$bytes = (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2))
? mb_strlen($content, '8bit')
: strlen($content);
if ($bytes > 200000) {
throw new Minify_JS_ClosureCompiler_Exception(
'POST content larger than 200000 bytes'
);
}
$response = $this->_getResponse($content);
if (preg_match('/^Error\(\d\d?\):/', $response)) {
if (is_callable($this->_fallbackFunc)) {
$response = "/* Received errors from Closure Compiler API:\n$response"
. "\n(Using fallback minifier)\n*/\n";
$response .= call_user_func($this->_fallbackFunc, $js);
} else {
throw new Minify_JS_ClosureCompiler_Exception($response);
}
}
if ($response === '') {
$errors = $this->_getResponse($this->_getPostContent($js, true));
throw new Minify_JS_ClosureCompiler_Exception($errors);
}
return $response;
}
protected $_fallbackFunc = null;
protected function _getResponse($content)
{
$contents = file_get_contents(self::URL, false, stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $content,
'max_redirects' => 0,
'timeout' => 15,
)
)));
if (false === $contents) {
throw new Minify_JS_ClosureCompiler_Exception(
"No HTTP response from server"
);
}
return trim($contents);
}
protected function _getPostContent($js, $returnErrors = false)
{
return http_build_query(array(
'js_code' => $js,
'output_info' => ($returnErrors ? 'errors' : 'compiled_code'),
'output_format' => 'text',
'compilation_level' => 'SIMPLE_OPTIMIZATIONS'
));
}
protected function _fallback($js)
{
require_once 'JSMin.php';
return JSMin::minify($js);
}
}
class Minify_JS_ClosureCompiler_Exception extends Exception {}

View File

@@ -1,10 +1,10 @@
/* is.js
/*! is.js
(c) 2001 Douglas Crockford
2001 June 3
*/
var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'}
/**
/*!*
* preserve this comment, too
*/
is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;}

View File

@@ -0,0 +1,49 @@
<?php
require_once '_inc.php';
require_once 'Minify/JS/ClosureCompiler.php';
function test_Minify_JS_ClosureCompiler()
{
global $thisDir;
$src = "
(function (window, undefined){
function addOne(input) {
return 1 + input;
}
window.addOne = addOne;
window.undefined = undefined;
})(window);
";
$minExpected = "(function(a,b){a.addOne=function(c){return 1+c};a.undefined=b})(window);";
$minOutput = Minify_JS_ClosureCompiler::minify($src);
if (false !== strpos($minOutput, 'Error(22): Too many compiles')) {
echo "!NOTE: Too many recent calls to Closure Compiler API to test.\n";
return;
}
$passed = assertTrue($minExpected == $minOutput, 'Minify_JS_ClosureCompiler : Overall');
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
echo "\n---Output: " .countBytes($minOutput). " bytes\n\n{$minOutput}\n\n";
echo "---Expected: " .countBytes($minExpected). " bytes\n\n{$minExpected}\n\n";
echo "---Source: " .countBytes($src). " bytes\n\n{$src}\n\n\n";
}
$src = "function blah({ return 'blah';} ";
$exc = null;
try {
$minOutput = Minify_JS_ClosureCompiler::minify($src);
} catch (Exception $e) {
$exc = $e;
}
$passed = assertTrue(
$exc instanceof Minify_JS_ClosureCompiler_Exception
, 'Minify_JS_ClosureCompiler : Throws Minify_JS_ClosureCompiler_Exception');
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
echo "\n---Message: " . var_export($exc->getMessage(), 1) . "\n\n\n";
}
}
test_Minify_JS_ClosureCompiler();

View File

@@ -9,6 +9,7 @@ require 'test_Minify_Cache_Memcache.php';
require 'test_Minify_Cache_ZendPlatform.php';
require 'test_Minify_CSS.php';
require 'test_Minify_CSS_UriRewriter.php';
require 'test_Minify_JS_ClosureCompiler.php';
require 'test_Minify_CommentPreserver.php';
require 'test_Minify_HTML.php';
require 'test_Minify_ImportProcessor.php';