mirror of
https://github.com/mrclay/minify.git
synced 2025-08-08 15:16:56 +02:00
Closure Compiler API minifier and unit test
JSMin preserves "/*!"
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
Minify Release History
|
Minify Release History
|
||||||
|
|
||||||
Version 2.1.4
|
Version 2.1.4
|
||||||
|
* Option to minify JS with Closure Compiler API w/ JSMin failover
|
||||||
* Cookie/bookmarklet-based debug mode. No HTML editing!
|
* Cookie/bookmarklet-based debug mode. No HTML editing!
|
||||||
* Allows 1 file to be missing w/o complete failure
|
* Allows 1 file to be missing w/o complete failure
|
||||||
* Combine multiple groups and files in single URI
|
* Combine multiple groups and files in single URI
|
||||||
|
@@ -102,6 +102,18 @@ $min_serveOptions['bubbleCssImports'] = false;
|
|||||||
$min_serveOptions['maxAge'] = 1800;
|
$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
|
* If you'd like to restrict the "f" option to files within/below
|
||||||
* particular directories below DOCUMENT_ROOT, set this here.
|
* particular directories below DOCUMENT_ROOT, set this here.
|
||||||
|
@@ -308,7 +308,7 @@ class JSMin {
|
|||||||
$this->get();
|
$this->get();
|
||||||
// if comment preserved by YUI Compressor
|
// if comment preserved by YUI Compressor
|
||||||
if (0 === strpos($comment, '!')) {
|
if (0 === strpos($comment, '!')) {
|
||||||
return "\n/*" . substr($comment, 1) . "*/\n";
|
return "\n/*!" . substr($comment, 1) . "*/\n";
|
||||||
}
|
}
|
||||||
// if IE conditional comment
|
// if IE conditional comment
|
||||||
if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
||||||
|
109
min/lib/Minify/JS/ClosureCompiler.php
Normal file
109
min/lib/Minify/JS/ClosureCompiler.php
Normal 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 {}
|
4
min_unit_tests/_test_files/js/before.min.js
vendored
4
min_unit_tests/_test_files/js/before.min.js
vendored
@@ -1,10 +1,10 @@
|
|||||||
/* is.js
|
/*! is.js
|
||||||
|
|
||||||
(c) 2001 Douglas Crockford
|
(c) 2001 Douglas Crockford
|
||||||
2001 June 3
|
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'}
|
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
|
* 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;}
|
is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;}
|
||||||
|
49
min_unit_tests/test_Minify_JS_ClosureCompiler.php
Normal file
49
min_unit_tests/test_Minify_JS_ClosureCompiler.php
Normal 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();
|
@@ -9,6 +9,7 @@ require 'test_Minify_Cache_Memcache.php';
|
|||||||
require 'test_Minify_Cache_ZendPlatform.php';
|
require 'test_Minify_Cache_ZendPlatform.php';
|
||||||
require 'test_Minify_CSS.php';
|
require 'test_Minify_CSS.php';
|
||||||
require 'test_Minify_CSS_UriRewriter.php';
|
require 'test_Minify_CSS_UriRewriter.php';
|
||||||
|
require 'test_Minify_JS_ClosureCompiler.php';
|
||||||
require 'test_Minify_CommentPreserver.php';
|
require 'test_Minify_CommentPreserver.php';
|
||||||
require 'test_Minify_HTML.php';
|
require 'test_Minify_HTML.php';
|
||||||
require 'test_Minify_ImportProcessor.php';
|
require 'test_Minify_ImportProcessor.php';
|
||||||
|
Reference in New Issue
Block a user