Create a gist now

Instantly share code, notes, and snippets.

PHP Function to Minify HTML, CSS and JavaScript
<?php
// Based on <https://github.com/mecha-cms/extend.minify>
define('MINIFY_STRING', '"(?:[^"\\\]|\\\.)*"|\'(?:[^\'\\\]|\\\.)*\'');
define('MINIFY_COMMENT_CSS', '/\*[\s\S]*?\*/');
define('MINIFY_COMMENT_HTML', '<!\-{2}[\s\S]*?\-{2}>');
define('MINIFY_COMMENT_JS', '//[^\n]*');
define('MINIFY_PATTERN_JS', '\b/[^\n]+?/[gimuy]*\b');
define('MINIFY_HTML', '<[!/]?[a-zA-Z\d:.-]+[\s\S]*?>');
define('MINIFY_HTML_ENT', '&(?:[a-zA-Z\d]+|\#\d+|\#x[a-fA-F\d]+);');
define('MINIFY_HTML_KEEP', '<pre(?:\s[^<>]*?)?>[\s\S]*?</pre>|<code(?:\s[^<>]*?)?>[\s\S]*?</code>|<script(?:\s[^<>]*?)?>[\s\S]*?</script>|<style(?:\s[^<>]*?)?>[\s\S]*?</style>|<textarea(?:\s[^<>]*?)?>[\s\S]*?</textarea>');
// get URL
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] === 443 ? 'https' : 'http') . '://';
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : "");
$url = $protocol . $host;
// escape character
define('X', "\x1A");
// normalize line–break(s)
function n($s) {
return str_replace(["\r\n", "\r"], "\n", $s);
}
// trim once
function t($a, $b) {
if ($a && strpos($a, $b) === 0 && substr($a, -strlen($b)) === $b) {
return substr(substr($a, strlen($b)), 0, -strlen($b));
}
return $a;
}
function fn_minify($pattern, $input) {
return preg_split('#(' . implode('|', $pattern) . ')#', $input, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
}
function fn_minify_css($input, $comment = 2, $quote = 2) {
if (!is_string($input) || !$input = n(trim($input))) return $input;
$output = $prev = "";
foreach (fn_minify([MINIFY_COMMENT_CSS, MINIFY_STRING], $input) as $part) {
if (!trim($part)) continue;
if ($comment !== 1 && strpos($part, '/*') === 0 && substr($part, -2) === '*/') {
if (
$comment === 2 && (
// Detect special comment(s) from the third character. It should be a `!` or `*` → `/*! keep */` or `/** keep */`
strpos('*!', $part[2]) !== false ||
// Detect license comment(s) from the content. It should contains character(s) like `@license`
stripos($part, '@licence') !== false || // noun
stripos($part, '@license') !== false || // verb
stripos($part, '@preserve') !== false
)
) {
$output .= $part;
}
continue;
}
if ($part[0] === '"' && substr($part, -1) === '"' || $part[0] === "'" && substr($part, -1) === "'") {
// Remove quote(s) where possible …
$q = $part[0];
if (
$quote !== 1 && (
// <https://www.w3.org/TR/CSS2/syndata.html#uri>
substr($prev, -4) === 'url(' && preg_match('#\burl\($#', $prev) ||
// <https://www.w3.org/TR/CSS2/syndata.html#characters>
substr($prev, -1) === '=' && preg_match('#^' . $q . '[a-zA-Z_][\w-]*?' . $q . '$#', $part)
)
) {
$part = t($part, $q); // trim quote(s)
}
$output .= $part;
} else {
$output .= fn_minify_css_union($part);
}
$prev = $part;
}
return trim($output);
}
function fn_minify_css_union($input) {
if (stripos($input, 'calc(') !== false) {
// Keep important white–space(s) in `calc()`
$input = preg_replace_callback('#\b(calc\()\s*(.*?)\s*\)#i', function($m) {
return $m[1] . preg_replace('#\s+#', X, $m[2]) . ')';
}, $input);
}
$input = preg_replace([
// Fix case for `#foo<space>[bar="baz"]`, `#foo<space>*` and `#foo<space>:first-child` [^1]
'#(?<=[\w])\s+(\*|\[|:[\w-]+)#',
// Fix case for `[bar="baz"]<space>.foo`, `*<space>.foo` and `@media<space>(foo: bar)<space>and<space>(baz: qux)` [^2]
'#(\*|\])\s+(?=[\w\#.])#', '#\b\s+\(#', '#\)\s+\b#',
// Minify HEX color code … [^3]
'#\#([a-f\d])\1([a-f\d])\2([a-f\d])\3\b#i',
// Remove white–space(s) around punctuation(s) [^4]
'#\s*([~!@*\(\)+=\{\}\[\]:;,>\/])\s*#',
// Replace zero unit(s) with `0` [^5]
'#\b(?:0\.)?0([a-z]+\b|%)#i',
// Replace `0.6` with `.6` [^6]
'#\b0+\.(\d+)#',
// Replace `:0 0`, `:0 0 0` and `:0 0 0 0` with `:0` [^7]
'#:(0\s+){0,3}0(?=[!,;\)\}]|$)#',
// Replace `background(?:-position)?:(0|none)` with `background$1:0 0` [^8]
'#\b(background(?:-position)?):(0|none)\b#i',
// Replace `(border(?:-radius)?|outline):none` with `$1:0` [^9]
'#\b(border(?:-radius)?|outline):none\b#i',
// Remove empty selector(s) [^10]
'#(^|[\{\}])(?:[^\{\}]+)\{\}#',
// Remove the last semi–colon and replace multiple semi–colon(s) with a semi–colon [^11]
'#;+([;\}])#',
// Replace multiple white–space(s) with a space [^12]
'#\s+#'
], [
// [^1]
X . '$1',
// [^2]
'$1' . X, X . '(', ')' . X,
// [^3]
'#$1$2$3',
// [^4]
'$1',
// [^5]
'0',
// [^6]
'.$1',
// [^7]
':0',
// [^8]
'$1:0 0',
// [^9]
'$1:0',
// [^10]
'$1',
// [^11]
'$1',
// [^12]
' '
], $input);
return trim(str_replace(X, ' ', $input));
}
function fn_minify_html($input, $comment = 2, $quote = 1) {
if (!is_string($input) || !$input = n(trim($input))) return $input;
$output = $prev = "";
foreach (fn_minify([MINIFY_COMMENT_HTML, MINIFY_HTML_KEEP, MINIFY_HTML, MINIFY_HTML_ENT], $input) as $part) {
if ($part === "\n") continue;
if (!trim($part) && (
$prev[0] === '<' && $prev[1] !== '/' && substr($prev, -2) !== '/>' && !preg_match('#^<i(?:mg|nput)\b#', $prev)
)) continue;
if ($part !== ' ' && !trim($part) || $comment !== 1 && strpos($part, '<!--') === 0) {
// Detect IE conditional comment(s) by its closing tag …
if ($comment === 2 && substr($part, -12) === '<![endif]-->') {
$output .= $part;
}
continue;
}
if ($part[0] === '<' && substr($part, -1) === '>') {
$output .= fn_minify_html_union($part, $quote);
} else if ($part[0] === '&' && substr($part, -1) === ';' && $part !== '&lt;' && $part !== '&gt;' && $part !== '&amp;') {
$output .= html_entity_decode($part); // Evaluate HTML entit(y|ies)
} else {
$output .= preg_replace('#\s+#', ' ', $part);
}
$prev = $part;
}
$output = str_replace(' </', '</', $output);
// Force space with `&#x0020;` and line–break with `&#x000A;`
return str_ireplace(['&#x0020;', '&#x20;', '&#x000A;', '&#xA;'], [' ', ' ', "\n", "\n"], trim($output));
}
function fn_minify_html_union($input, $quote) {
if (
strpos($input, ' ') === false &&
strpos($input, "\n") === false &&
strpos($input, "\t") === false
) return $input;
global $url;
return preg_replace_callback('#<\s*([^\/\s]+)\s*(?:>|(\s[^<>]+?)\s*>)#', function($m) use($quote, $url) {
if (isset($m[2])) {
// Minify inline CSS(s)
if (stripos($m[2], ' style=') !== false) {
$m[2] = preg_replace_callback('#( style=)([\'"]?)(.*?)\2#i', function($m) {
return $m[1] . $m[2] . fn_minify_css($m[3]) . $m[2];
}, $m[2]);
}
// Minify URL(s)
if (strpos($m[2], '://') !== false) {
$m[2] = str_replace([
$url . '/',
$url . '?',
$url . '&',
$url . '#',
$url . '"',
$url . "'"
], [
'/',
'?',
'&',
'#',
'/"',
"/'"
], $m[2]);
}
$a = 'a(sync|uto(focus|play))|c(hecked|ontrols)|d(efer|isabled)|hidden|ismap|loop|multiple|open|re(adonly|quired)|s((cop|elect)ed|pellcheck)';
$a = '<' . $m[1] . preg_replace([
// From `a="a"`, `a='a'`, `a="true"`, `a='true'`, `a=""` and `a=''` to `a` [^1]
'#\s(' . $a . ')(?:=([\'"]?)(?:true|\1)?\2)#i',
// Remove extra white–space(s) between HTML attribute(s) [^2]
'#\s*([^\s=]+?)(=(?:\S+|([\'"]?).*?\3)|$)#',
// From `<img />` to `<img/>` [^3]
'#\s+\/$#'
], [
// [^1]
' $1',
// [^2]
' $1$2',
// [^3]
'/'
], str_replace("\n", ' ', $m[2])) . '>';
return $quote !== 1 ? fn_minify_html_union_attr($a) : $a;
}
return '<' . $m[1] . '>';
}, $input);
}
function fn_minify_html_union_attr($input) {
if (strpos($input, '=') === false) return $input;
return preg_replace_callback('#=(' . MINIFY_STRING . ')#', function($m) {
$q = $m[1][0];
if (strpos($m[1], ' ') === false && preg_match('#^' . $q . '[a-zA-Z_][\w-]*?' . $q . '$#', $m[1])) {
return '=' . t($m[1], $q);
}
return $m[0];
}, $input);
}
function fn_minify_js($input, $comment = 2, $quote = 2) {
if (!is_string($input) || !$input = n(trim($input))) return $input;
$output = $prev = "";
foreach (fn_minify([MINIFY_COMMENT_CSS, MINIFY_STRING, MINIFY_COMMENT_JS, MINIFY_PATTERN_JS], $input) as $part) {
if (!trim($part)) continue;
if ($comment !== 1 && (
substr($part, 0, 2) === '//' || // Remove inline comment(s)
strpos($part, '/*') === 0 && substr($part, -2) === '*/'
)) {
if (
$comment === 2 && (
// Detect special comment(s) from the third character. It should be a `!` or `*` → `/*! keep */` or `/** keep */`
strpos('*!', $part[2]) !== false ||
// Detect license comment(s) from the content. It should contains character(s) like `@license`
stripos($part, '@licence') !== false || // noun
stripos($part, '@license') !== false || // verb
stripos($part, '@preserve') !== false
)
) {
$output .= $part;
}
continue;
}
if ($part[0] === '"' && substr($part, -1) === '"' || $part[0] === "'" && substr($part, -1) === "'") {
// TODO: Remove quote(s) where possible …
$output .= $part;
} else {
$output .= fn_minify_js_union($part);
}
$prev = $part;
}
return $output;
}
function fn_minify_js_union($input) {
return preg_replace([
// Remove white–space(s) around punctuation(s) [^1]
'#\s*([!%&*\(\)\-=+\[\]\{\}|;:,.<>?\/])\s*#',
// Remove the last semi–colon and comma [^2]
'#[;,]([\]\}])#',
// Replace `true` with `!0` and `false` with `!1` [^3]
'#\btrue\b#', '#\bfalse\b#', '#\b(return\s?)\s*\b#',
// Replace `new Array(x)` with `[x]` … [^4]
'#\b(?:new\s+)?Array\((.*?)\)#', '#\b(?:new\s+)?Object\((.*?)\)#'
], [
// [^1]
'$1',
// [^2]
'$1',
// [^3]
'!0', '!1', '$1',
// [^4]
'[$1]', '{$1}'
], $input);
}
/**
* Backward Compatibility
* ----------------------
*/
function minify_css(...$lot) {
return fn_minify_css(...$lot);
}
function minify_html(...$lot) {
return fn_minify_html(...$lot);
}
function minify_js(...$lot) {
return fn_minify_js(...$lot);
}
@david-hc
david-hc commented Jan 3, 2015

Mungkin javascript juga bisa dengan trik yang sama? regex ?

@tovic
Owner
tovic commented Jan 3, 2015 edited

Ini sampel untuk JavaScript → https://rawgit.com/tovic/mini-web-tools/master/converter.css.html

Contoh untuk minifier HTML → http://jsbin.com/soyawixaho/1/edit?js,output

// HTML Minifier
function minify_html(input) {
    return input
    .replace(/<\!--(?!\[if)([\s\S]+?)-->/g, "") // Remove HTML comments except IE comments
    .replace(/>[^\S ]+/g, '>')
    .replace(/[^\S ]+</g, '<')
    .replace(/>\s{2,}</g, '><');
}

// Test
alert(minify_html('<div>      <span><a href="">test</a> <span></span>\t</span>  \t\r\n\n\n\n\t\t       </div>'));
@tovic
Owner
tovic commented Jan 3, 2015

Example Usage

$str = file_get_contents('p­ath/to/style.css');

// echo
echo minify_css($str);

//­ save as `style.min.css`
file_put_contents('path­/to/style.min.css', minify_css($str));
@kudataz
kudataz commented Jan 7, 2015

example usage yg html dengan inline js & css ?

@tovic
Owner
tovic commented Jan 12, 2015

@kudataz

<style>
<?php echo minify_css(file_get_contents('p­ath/to/style.css')); ?>
</style>

<script>
<?php echo minify_js(file_get_contents('p­ath/to/engine.js')); ?>
</script>
@nakome
nakome commented Jul 22, 2015

Nice functions ;)

@mdmunir
mdmunir commented Oct 3, 2015

👍 Keren gan.
syntak angularjs diminify juga atau dipertahankan?

<table>
    <tr ng-repeat="item in items | filter:q">
        <td>{{item.name}}</td>
        <td>{{item.qty * item.price | number}}</td>
    </>
<table>
@tovic
Owner
tovic commented Nov 21, 2015

@mdmunir Harusnya fungsi ini cuma akan menghapus whitespaces di antara > dan < saja, jadi tidak akan terkompres kode Angular–mu.

@tovic
Owner
tovic commented Nov 21, 2015

Example with Output Buffer

<?php

include 'path/to/php-html-css-js-minifier.php';

ob_start('minify_html');

?>

<!-- HTML code goes here ... -->

<?php echo ob_get_clean(); ?>
@moesphemie

This is just awesome mate! Thank

@AndrewBerry
AndrewBerry commented Feb 28, 2016 edited

Just a heads up - your minify_css function invalidates any use of calc() by removing the whitespace around the + and - operators.
See https://developer.mozilla.org/en/docs/Web/CSS/calc

Otherwise, amazing work! Thanks.

@AndrewBerry Fixed now thanks!

@huiralb
huiralb commented Mar 7, 2016

Great !!
thanks gan, ngirit waktu.

ob_start();

// html content
// ......
$content = minify_html( ob_get_clean() );

echo $content;
@abantecart

Great works on this. Can we use this in our open source under (OSL 3.0) ?
Thank you

@tovic
Owner
tovic commented May 15, 2016

The original license is GPL v3 from the Mecha CMS repository.

@NoahjChampion
NoahjChampion commented May 16, 2016 edited

@tovic Do you have a php based HTML formatter? The opposite of the minifier for HTML? Or can I contact you about making one?

@NoahjChampion Simply use the native PHP Tidy extension.

@viktor-zhuromskyy
viktor-zhuromskyy commented May 18, 2016 edited

Nice piece of code!

Could you please integrate automatic parsing of inline JavaScript code as you did with CSS in your main block?

@devdesco-ceo Something like this:

$content = preg_replace_callback('#<script(>|\s[^<>]*?>)([\s\S]*?)<\/script>#', function($m) {
    return '<script' . $m[1] . minify_js($m[2]) . '</script>';
}, $content);
@viktor-zhuromskyy
viktor-zhuromskyy commented May 18, 2016 edited

Would you be so kind adding exception for removing the following comments tags since these are used by Magento2 for XHR requests markup?

Opening tag <!-- ko
Closing tag /ko -->

Example string not to touch:

<!-- ko template: getTemplate() --><!-- /ko -->

@devdesco-ceo The current version allows you to check specific pattern from the chunks:

if(strpos($v, '<!-- ko') === 0 || strpos($v, '<!-- /ko') === 0) {
    $output .= $v;
    continue; // skip!
}
@noasset
noasset commented May 24, 2016 edited

Bagaimana dengan 'newline' yang ada pada tag pre?
apa juga akan ter 'mini'?

@noasset Tidak pak. Sejak versi yang pertama, proses minifikasi hanya terjadi di antara karakter > dan < saja. Versi yang sekarang bahkan memungkinkan untuk tidak menyentuh tag HTML di dalam blok <(code|pre|script|style)>.

@solankin1576

You can replace the code which you don't need with another word like.
html_code=html_code.replace(/script/g, 'test');
here test is a new word for your code

@sammyukavi
sammyukavi commented Jun 9, 2016 edited

Excellent code! However if minify_html() is used with ob_start,, it fails to parse <!DOCTYPE html> if the html page starts with

<!DOCTYPE html>
<!--[if IE 8]> <html lang="en" class="ie8"> <![endif]-->  
<!--[if IE 9]> <html lang="en" class="ie9"> <![endif]-->  
<!--[if !IE]><!--> <html lang="en"> <!--<![endif]-->  
@wannaco
wannaco commented Jun 26, 2016 edited

great, just that css files generated by lesscss usually have duplicate element tags html, body etc and they are simply stripped out.

@tmb-github

The HTML minifier cannot handle embedded UL lists if there is additional text following the end of the embedded list. In the example below, "...and these are important" is ending the enclosing <li> beginning with "Some finer points:". However, the minification routine places "...and these are important" and the tabs that precede it on a new line following a CRLF:

<div>
    <ul>
        <li>AAAAAAAAAAAAAA</li>
<!-- li begins: -->
        <li>Some finer points:
            <ul> 
                <li>BBBBBBBBBBBB</li>
                <li>CCCCCCCCCCCC</li>
                <li>DDDDDDDDDDDD</li>
            </ul>
            ...and these are important.</li>
<!-- li ends -->
        <li>EEEEEEEEEEE</li>
    </ul>
</div>

...like this:

<div><ul><li>AAAAAAAAAAAAAA</li><li>Some finer points:
            <ul><li>BBBBBBBBBBBB</li><li>CCCCCCCCCCCC</li><li>DDDDDDDDDDDD</li></ul>    ...and these are important.</li><li>EEEEEEEEEEE</li></ul></div>
@tmb-github
tmb-github commented Jul 13, 2016 edited

Single quotes and double quotes around HTML attributes should be removed with the following restrictions:

  1. The quoted material MUST exist within a tag <> (e.g., <mytag b="yes"> becomes <mytag b=yes>, but <script>var b="yes"</script> stays intact).

  2. The quoted material may not have a space character nor an equal sign (e.g., <mytag b="no no" c="no=no"> stays intact).

  3. The quoted material may not be in an href or src definition.

  4. It must handle unicode.

  5. Attribute names may include hyphens, dots, and colons, so these must be accounted for.

Here are three test cases:

<img test="xxx" href="http://example.com/images/Vögel.jpg" alt="Vögel" height="100" width="100"> <img test="xxx" src="http://example.com/images/Vögel.jpg" alt="Vögel" height="100" width="100">

<img test-time="xxx" src="http://example.com/images/Vögel.jpg" alt="Vögel" height="100" width="100"> <img test_time="xxx" src="http://example.com/images/Vögel.jpg" alt="Vögel" height="100" width="100">

<img aa-bb="xxx" cc-dd="xxx yyy" src="http://example.com/Vögel.jpg" temp="Bird" alt="The Bird" height="100" width="100">

Adding this as the second item in the regex array seems to do the job:

'#(?:<[a-z][\w:.-]*|(?!^)\G)(?:\s+(?:(?:src|href)=(?:"[^"]*"|\'[^\']*\')|[a-z][\w:.-]*="(?:[^"=]*\s[^"=]*|[^"\s]*=[^"\s]*)"))*\s+(?!(?:src|href)=)[a-z][\w:.-]*=\K(?|"([^\s"=]*)"|\'([^\s\'=]*)\')#ui',

...with this as as the second parameter array element:

'$1'

(This solution was devised by Wiktor Stribiżew on StackOverflow, so thanks go to him.)

@tmb-github This solution should be optional. You can create another wrapper that will run after the default HTML minifier. Not all people like to see mixed HTML attributes with and without quotes like this → <tag foo=bar baz=1 qux="a b c">

function minify_html_smart_quotes($input) {
    $input = preg_split('#(<[^<>]+?>)#', $input, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
    $output = "";
    foreach($input as $v) {
        if($v[0] === '<' && substr($v, -1) === '>') {
            $output .= _do_something_with_tag($v); // remove optional quotes, etc…
        } else {
            $output .= $v;
        }
    }
    return $output;
}

echo minify_html_smart_quotes(minify_html($input));
@tovic
Owner
tovic commented Jul 17, 2016 edited

A Total Overhaul

Now the character type will be clearer so that you can easily check whether it is string, regular expression, comment or html tag. Now I’m using PHP preg_split to generate each parts correctly in an array. This way, you can make custom string manipulation safely by checking the character pattern first, especially at the beginning and end of the characters. Example:

$output = "";
foreach($input as $v) {
    if(trim($v) === "") continue; // white-space(s) or empty string
    if($v[0] === '"' && substr($v, -1) === '"') { … } // string with double quote
    if($v[0] === "'" && substr($v, -1) === "'") { … } // string with single quote
    if($v[0] === '<' && substr($v, -1) === '>') { // should be a HTML tag or HTML comment
        if($v[1] === '!') { … } // maybe a HTML comment, CDATA or DOCTYPE
        if(substr($v, -12) === '<![endif]-->') { … } // maybe an IE conditional comment
    }
    if(strpos($v, '//') === 0) { … } // maybe a JavaScript comment
    if(substr($v, 0, 2) === '/*' && substr($v, -2) === '*/') { … } // maybe a CSS comment
    // Others… (safe to be minified)
}

If you are interested in doing some more robust testing, you can see some examples here, here and here (look at the $test variable).

@tmb-github
tmb-github commented Jul 21, 2016 edited

There’s a problem with the new CSS minifier. When I first ran it on my CSS, my fonts were not correct. This was not the case with the previous version of the CSS minifier. I eventually tracked down the problem: the old minifier was preserving quotes around all of the text in parentheses in the @font-face rule, like this:

@font-face{font-family:Roman;font-weight:400;font-style:normal;src:url('../fonts/Open-Sans-regular.eot');src:url('../fonts/Open-Sans-regular.eot?#iefix') format('embedded-opentype'),
local('Open Sans'),
local('Open-Sans-regular'),
url('../fonts/Open-Sans-regular.woff2') format('woff2'),
url('../fonts/Open-Sans-regular.woff') format('woff'),
url('../fonts/Open-Sans-regular.ttf') format('truetype'),
url('../fonts/Open-Sans-regular.svg#OpenSans') format('svg')}

This worked. The new CSS minifier strips them out except when there is a space character in the string, like this:

@font-face{font-family:Roman;font-weight:400;font-style:normal;src:url(./fonts/Open-Sans-regular.eot);src:url(./fonts/Open-Sans-regular.eot?#iefix) format(embedded-opentype),
local('Open Sans'),
local(Open-Sans-regular),
url(./fonts/Open-Sans-regular.woff2) format(woff2),
url(./fonts/Open-Sans-regular.woff) format(woff),
url(./fonts/Open-Sans-regular.ttf) format(truetype),
url(./fonts/Open-Sans-regular.svg#OpenSans) format(svg)}

This prevents the fonts from being employed; restoring the surrounding quotes corrected the problem. Every string within parentheses in the @font-face should apparently be enclosed within quotes; the MDN spec on @font-face is here:

https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face

Even though it doesn’t specifically address this except in reference to arguments specifically described as strings, it appears to be true for URLs, etc., as well.

@tovic
Owner
tovic commented Jul 22, 2016 edited

@tmb-github Thanks for the input. Changing the (?<!\bcontent\:) part with (?<!\bcontent\:|\bformat\(|\blocal\() should fix the issue.

@tmb-github
tmb-github commented Jul 28, 2016 edited

@tovic Scratch what I posted earlier here, if you saw it...something else is amiss. I'll write back when I figure it out. The urls seem fine without surrounding quotes.

@tmb-github

@tovic: I've found it. The new routine is stripping out quotes around arguments in format():

/* works--this is what the old version of the CSS minifier produced: */
@font-face{font-family:Roman;font-weight:400;font-style:normal;src:url(./fonts/Muli-regular.eot);src:url(./fonts/Muli-regular.eot?#iefix) format('embedded-opentype'),local('Muli'),local('Muli-regular'),url(./fonts/Muli-regular.woff2) format('woff2'),url(./fonts/Muli-regular.woff) format('woff'),url(./fonts/Muli-regular.ttf) format('truetype'),url(./fonts/Muli-regular.svg) format('svg')}
/* fails--this is what the new version of the CSS minifier produces--text in format() is losing its quotes: */
@font-face{font-family:Roman;font-weight:400;font-style:normal;src:url(./fonts/Muli-regular.eot);src:url(./fonts/Muli-regular.eot?#iefix) format(embedded-opentype),local('Muli'),local('Muli-regular'),url(./fonts/Muli-regular.woff2) format(woff2),url(./fonts/Muli-regular.woff) format(woff),url(./fonts/Muli-regular.ttf) format(truetype),url(./fonts/Muli-regular.svg) format(svg)}
@tovic
Owner
tovic commented Jul 28, 2016

Sigh. I think I will just comment-out that parts for now. Other problem may also occurs on the @charset rules.

@mrizwan47

Great snippet. I've been using for a long time. But recently found a problem, when I minify this script it gives error:

Uncaught SyntaxError: Unexpected identifier

I fixed it by commenting line 248 and 258 but those are important replacements for minification 😞

Any help would be appreciated 😄

@mrizwan47
mrizwan47 commented Aug 20, 2016 edited

Hi @tovic, faced another problem in js minification:

Input:

this.isomethign()

this.test()

Output:

this.isomethign()this.test()

which raises error: Unexpected token this.

Expected output:

this.isomethign();this.test()
@tovic
Owner
tovic commented Aug 24, 2016

@mrizwan47 This minifier does not do any code validation. No characters added by these functions to the source input. You should validate your own code.

@bbykwiatu
bbykwiatu commented Sep 14, 2016 edited

something is wrong when css like this

before:
.foo:not(.active) .bar:nth-child(3) {

}

after:
.foo:not(.active).bar:nth-child(3){}

This compiler does not include space between .foo:not(.active) and .bar:nth-child(3)

@tovic
Owner
tovic commented Sep 24, 2016 edited

@bbykwiatu This is weird. Because I don’t trim any white-spaces arround dot characters → https://gist.github.com/tovic/d7b310dea3b33e4732c0/a2aec8653a893c42f4cf22662e775814c2d91f0a#file-php-html-css-js-minifier-php-L147

And the replacement of #\)\s+\b# to )<space placeholder> before it should fix the issue :\

@avsoftenterprise
avsoftenterprise commented Oct 3, 2016 edited

I have an issue with this minifier.
I'm going to improve my SEO. This is the reason why I convert all image src with path in image base64 string.

When I parse my HTML with minifier it crash and the response page is empty.

Do you have any suggestion?

@Fusseldieb
Fusseldieb commented Oct 5, 2016 edited

When comments have any " ' ", it'll break the javascript badly...

Ex: " // That isn't for something " -> This break the js!

Other than that, nice php :)

EDIT:
I fixed it!

Replace:

// Remove inline comment(s) [^1]
            '#\s*\/\/.*$#m',

with:

// Remove inline comment(s) [^1]
            '#((\/\*)[\S\s]*?(\*\/))|((\/\/)[\S\s]*?(?=[\n\r]))#',

Now it will accept even multiline comments.
Big thanks to http://regexr.com/ :p

EDIT2:
But it still doesn't accept code comments.
Like those: // mydiv.classList.add('fadeout');
It'll break.

@tovic
Owner
tovic commented Oct 29, 2016

@Fusseldieb the parser splits your comment code as string and comment like this:

array('// ', 'myDiv.classList.add(', '\'fadeout\'', ');');

Will try to fix this issue next time. Maybe by setting the comment string in a higher priority to be captured than the string string.

@mocanuga
mocanuga commented Nov 10, 2016 edited

I have some issues with the js minifier.

'use strict' becomes 'usestrict'.
if('foo' in bar) becomes if('foo'inbar).
var Gesture becomes varGesture
var rule = typeof selector == 'object' ? selector : this.get(selector) becomes varrule=typeofselector=='object'?selector:this.get(selector)

I suppose there are more but can't detect them as the parser breaks on first issue.

@tovic
Owner
tovic commented Jan 7, 2017 edited

Updated!

Added function arguments:

$output = minify_{$any}($input, $comment = 2, $quote = 2);
  • 0: Remove
  • 1: Keep
  • 2: Remove if/but/when … (example: keep if detected as IE conditional comments, keep if contains @license, etc.)
@MarlonGnauck
MarlonGnauck commented Jan 22, 2017 edited

<span>0</span>
will be "optimized" to
<span></span>

If I use an other number... all is correct
<span>1</span>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment