matthiasmullie / minify

CSS & JavaScript minifier, in PHP. Removes whitespace, strips comments, combines files (incl. @import statements and small assets in CSS files), and optimizes/shortens a few common programming patterns.
https://matthiasmullie.github.io/minify/
MIT License
1.97k stars 310 forks source link

Javascript compression rate #21

Closed jslegers closed 9 years ago

jslegers commented 10 years ago

I'm glad to see a Belgian developer release his own pure PHP minification solution, but it can't compete yet with the compression rate of YUI compressor.

To test your solution, I took my code from https://github.com/jslegers/4inarow/blob/master/code.js and copy-pasted it into http://www.minifier.org/.

Before compression, the code is 3285 bytes. After compression, the code is recuded to 1908 bytes. When I compare the result with the result I get from http://refresh-sf.com/yui/, the code is reduced to 1233 bytes.

I would consider using your solution if the compression rate would be close enough to the compression rate of YUI compressor. It would also be nice to see the compression rate somewhere on the online interface and have a few configuration options, as it's done on http://refresh-sf.com/yui/ (see also https://github.com/matthiasmullie/minify/issues/18).

To compare results, here's the output I got from my test :

Minifier

(function(doc){var start=function(){finished=false;changePlayer()},newGame=function(message){if(confirm(message)){start();forAllCells(emptyField)}},element=function(id){return doc.getElementById(id)},value=function(el){return element(el).innerHTML},cell=function(i,j){return element("c-"+i+"-"+j)},forAllCells=function(action){for(var t=1;t<7;t++){for(var counter2=1;counter2<8;counter2++){action(t,counter2)}}},sameColor=function(i,j){return testClass(i,j,players[current])},changePlayer=function(){element("c").innerHTML=players[current=(current+1)%2]},horizontalWon=function(i,j){for(var min=j-1;min>0;min--)if(!sameColor(i,min))break;for(var max=j+1;max<8;max++)if(!sameColor(i,max))break;return max-min>4},verticalWon=function(i,j){for(var max=i+1;max<7;max++)if(!sameColor(max,j))break;return max-i>3},diagonalLtrWon=function(i,j){for(var min=i-1,t=j-1;min>0;min--,t--)if(t<1||!sameColor(min,t))break;for(var max=i+1,t=j+1;max<7;max++,t++)if(t>7||!sameColor(max,t))break;return max-min>4},diagonalRtlWon=function(i,j){for(var min=i-1,t=j+1;min>0;min--,t++)if(t>7||!sameColor(min,t))break;for(var max=i+1,t=j-1;max<7;max++,t--)if(t<1||!sameColor(max,t))break;return max-min>4},colorField=function(i,j,color){cell(i,j).className=color},emptyField=function(i,j){colorField(i,j,'')},testClass=function(i,j,value){return cell(i,j).className==value},addCellBehavior=function(i,j){cell(i,j).onclick=function(j){return function(){if(!finished){for(var t=6;t>0;t--){if(testClass(t,j,'')){colorField(t,j,players[current]);if(horizontalWon(t,j)||verticalWon(t,j)||diagonalLtrWon(t,j)||diagonalRtlWon(t,j)){finished=true;newGame(wonMessage.replace("%s",players[current]))}else{changePlayer()}
break}}}}}(j)},players=[value("a"),value("b")],current=0,newGameMessage=value("n"),wonMessage=value("w"),finished;start();forAllCells(addCellBehavior);element("r").onclick=function(){newGame(newGameMessage)}})(document)

YUI Compressor

(function(t){var f=function(){i=false;g()},j=function(w){if(confirm(w)){f();l(r)}},d=function(w){return t.getElementById(w)},o=function(w){return d(w).innerHTML},b=function(x,w){return d("c-"+x+"-"+w)},l=function(y){for(var x=1;x<7;x++){for(var w=1;w<8;w++){y(x,w)}}},k=function(x,w){return h(x,w,e[n])},g=function(){d("c").innerHTML=e[n=(n+1)%2]},c=function(z,x){for(var y=x-1;y>0;y--){if(!k(z,y)){break}}for(var w=x+1;w<8;w++){if(!k(z,w)){break}}return w-y>4},u=function(y,x){for(var w=y+1;w<7;w++){if(!k(w,x)){break}}return w-y>3},s=function(A,x){for(var z=A-1,y=x-1;z>0;z--,y--){if(y<1||!k(z,y)){break}}for(var w=A+1,y=x+1;w<7;w++,y++){if(y>7||!k(w,y)){break}}return w-z>4},p=function(A,x){for(var z=A-1,y=x+1;z>0;z--,y++){if(y>7||!k(z,y)){break}}for(var w=A+1,y=x-1;w<7;w++,y--){if(y<1||!k(w,y)){break}}return w-z>4},v=function(y,x,w){b(y,x).className=w},r=function(x,w){v(x,w,"")},h=function(x,w,y){return b(x,w).className==y},q=function(x,w){b(x,w).onclick=function(y){return function(){if(!i){for(var z=6;z>0;z--){if(h(z,y,"")){v(z,y,e[n]);if(c(z,y)||u(z,y)||s(z,y)||p(z,y)){i=true;j(a.replace("%s",e[n]))}else{g()}break}}}}}(w)},e=[o("a"),o("b")],n=0,m=o("n"),a=o("w"),i;f();l(q);d("r").onclick=function(){j(m)}})(document);
matthiasmullie commented 10 years ago

I like the suggestion to add the compression rate on minifier.org - I'll definitely look into doing that soon.

As for the comparison with YUI: I won't argue, YUI is hands down better at compressing JS (as evidenced by your example)

There's still plenty that could be done to further reduce JS size, with the most to be gained from changing variable & function names to shorter alternatives. That's quite a massive undertaking, though, and will be expensive to process. Some day... :)

matthiasmullie commented 10 years ago

Update: added the minify gains to minifier.org.

jslegers commented 10 years ago

@matthiasmullie :

An alternative to emulating the behavior of composer in PHP would be to use YUI Composer as a dependency for projects where that's possible and use the pure PHP version as a fallback. That way, you have best of both worlds.

For an example of a PHP project that uses YUI Compressor as a depencency, go to https://github.com/mrclay/minify.

javiereguiluz commented 10 years ago

@jslegers in my opinion your proposal is a good idea but it seems out of reach for this project.

What I mean is that if you want maximum compression, you should take the hassle of installing all the frontend tools such as YUI. But if you don't mind sacrificing some bytes in order to get rid of all the non-PHP tools, this project is perfect for you.

AdamWill commented 9 years ago

no criticism intended, but just thought folks might be interested - I was doing some quick minifier benchmarking on ownCloud's javascript today, and threw this one into the comparison. it comes out about dead last, I'm afraid. it just barely beats out the version of jsmin.php from mrclay/minify, and jshrink, on size (by 4k with a total size of ~2.4MB), but loses to jsminplus.php from mrclay and JSqueeze on size. On speed it's the slowest minifier tested, taking 19.35 seconds to process the test files; the next slowest was jsminplus at 15.37 secs, the fastest was JSqueeze at 6.83 secs.

matthiasmullie commented 9 years ago

@AdamWill Thanks for the note. Any chance you could share your test suite so I can profile what particular functions are slowest?

AdamWill commented 9 years ago

@matthiasmullie it's really nothing special, I don't think I'd dignify it with the title 'test suite' :) here it is . To get the source files I just ran for i infind -name *.js | grep -v l10n; do cp $i /somedir; done in the ownCloud git master tree and ran the script from /somedir. You have to feed it all the minifiers. It's really a hack job :) see https://www.happyassassin.net/2014/12/29/adventures-in-php-web-asset-minimization/

matthiasmullie commented 9 years ago

@AdamWill I just pushed some changes (https://github.com/matthiasmullie/minify/commit/bbdc79ef655c1ee6be5540ff80436a0a16b9fc77) that should drastically improve minification speed. Brought my sample suite down from ~16s to ~5s

AdamWill commented 9 years ago

yeah, that sure speeds it up, nice job:

MM minifiy (JS) time: 5.8328921794891

size looks 4K different, might just be FS stuff though.

matthiasmullie commented 9 years ago

What exactly do you mean by "FS stuff"?

In theory, there should be no file size differences compared to before. I couldn't find any differences in my test files, and all test cases still work too. Which leads me to believe (and hope) that that "FS stuff" is the reason for the size differences :D

AdamWill commented 9 years ago

it was a big ol' handwave ;) I'm just using du -c | grep -i total to get the file sizes. I know there's various kinds of weirdness that can affect the utilization of filesystem space by files that are ostensibly the same size, and I'm just not going to go digging through the du man page at this time of night, and my original purpose was just to get a rough comparison - so I'm inclined not to sweat 4KB. If you'd like to make sure the change hasn't caused any regressions, of course, I can try and do a more precise comparison...tomorrow. definitely tomorrow. :P

matthiasmullie commented 9 years ago

Sure! I'm fairly confident no regressions were caused, and the tests didn't pick up any. If you're still motivated enough do to a comparison, feel free (not at all urgent!), it'll be good to have some confirmation. However, I notice you've had plenty of struggles with minifiers lately, I won't hold it against you if you don't want to spend any more time on it :D

matthiasmullie commented 9 years ago

I'll close this one.

The speed improvement seems to work (tests revealed no regressions & nothing related has been reported since.

We also discussed compression rate. I agree that it can be improved (and probably will be as time progresses). This ticket is quite vague (no concrete actionable) and not a real "issue", though - so I'll close it!