Home > Javascript AJAX CSS > Javascript Compressor Archive

Javascript Compressor Archive

Javascript Compressor (Modified 1 Oct. 2008)

Javascript Compressor がほぼ完成しました。正規表現のエラーチェックと括弧の数を数えてエラーがある場合に表示されます。Compression Ratio も表示させるようにしました。

以前の記事を改良しました。

正規表現部分の[ ] 内の"/" とスペースがあった場合に圧縮時に(スペースがある場合のみ)スペースが消てしまうので今回は、ループさせてRegExp をecmascript 評価 (eval)してチェックするようにしました。
例: exp=/[ / ]/;
通常は、exp=/[ \/ ]/; と書くのですが、実際に正規表現の [ ] 内に"/" があってもjavascript ではエラーになりません。普通に書くと、/ ==> \/, space ==> \s となるのですが、文字コードなどが絡んでどうしても特殊な書き方が必要な例もあるかもしれないのでそれに対応しました。Javascript のコードはとても柔軟性が高いのでまだ100%とは言えないかもしれませんが、一般的なJavascriptのコードではエラーはないと思います。

また今回、Javascript Code Prettifier もセレクトメニューに追加しました。

こちらの記事に詳細があります。使い方はただ貼り付けるだけなので簡単です。(js ファイルなどのセットアップせずに何ヶ所でも貼り付けられます。)

見た目は下にあるJavascript compressor のソースコードのようになります。

Google Gadget の貼り付けコードです。ブログやウェブページに貼り付けられます。

Source code of modified Javascript Compressor function.

Modified on 1 Oct. 2008

1    /****************************************************************
2     2008 (C)samurai-logic.com
3    
4     Javascript Compressor
5    
6     Last Modified 1 Oct. 2008
7    ****************************************************************/
8    function $compress(str){
9    
10   var Size=str.length;
11   
12   //if(/\n/g.test(str)) return("no end of line"); 
13   
14   str=str.replace(/\t+/g," ");
15   
16   Reg=/([^\d\w]\n[^\d\w]|[^\d\w]\s[^\d\w]|[\d\w]\s[^\d\w\$\_\#]|[^\d\w]\s[\d\w])/;
17   
18   //Exp=/[^\\]\/[^\/]*([\s\,\;]*)((\,\s*(\"|\')|(\w+)\s*\(\s*\/*)[\s\S]+|\/\/[\s\S]+|\/\*[\s\S]+|\s{2,}[\s\S]+|\s*)\n*/; 
19   //Exp=/[^\\]\/([^\/])?(\s)*(([\,\s]*(\"|\')|(\w+)\s*\(\s*\/*)[\s\S]+|\/\/[\s\S]+|\/\*[\s\S]+|\s{2,}[\s\S]+|\s*)\n*/; 
20   
21   //Basic Exp 
22   Exp=/[^\\]\/([^\/])/;
23   
24   chr=/(\(|\=|\[|\:|\||\&|\!|\,)/; // new reg 
25   
26   //d_q=/([^\\]\"[^\"]*[^\:]|[^\"]\"[\s]*[\:\,\}\]\)\;\.])/; 
27   //s_q=/([^\\]\'[^\']*[^\:]|[^\']\'[\s]*[\:\,\}\]\)\;\.])/; 
28   //d_q=/([^\\]\"|[^\"]\")/; 
29   //s_q=/([^\\]\'|[^\']\')/; 
30   
31   //modified 1 Oct. 2008  don't need to replace \\\" and \\\'... 
32   d_q=/[^\\]\"/; //replace(/\\\\|\\\"/g,"xx") temp before search(d_q) 
33   s_q=/[^\\]\'/; //replace(/\\\\|\\\'/g,"xx") temp before search(s_q) 
34   
35   bracket=new Array();
36   
37   bracket[0]=0; bracket[1]=0; bracket[2]=0; bracket[3]="";
38   
39   var CODE  = "";  
40   var cmt   = false;
41   var arg   = -1;
42   var pos = end = 0;
43   var last=" ";
44   var temp="";
45   var LEN=str.length;
46   var retrn = false; // for regexp "return /pat/.test()" 
47   
48       while (pos >= 0){
49       var key_q = str.charAt(pos);
50       var key_c = str.substr(pos,2);
51       var key_r = last + key_c;
52   
53       if((pos>6)&&(str.substr(pos-6,6)=="return")&&(/^[\s\n]*\/[^\/\*]/.test(str.substring(pos,LEN))))retrn=true;
54   
55       if (key_q=="'")          { arg = 0; pos++; }     //find pos of keyword ' 
56       elseif (key_q=='"')  { arg = 1; pos++; }     //find pos of keyword " 
57       elseif ((key_q=='/') && (key_c!="//") && (key_c!="/*") && ((chr.test(last) || (retrn))))
58                     { arg = 4; pos++;  }     //find pos of keyword / 
59       elseif (key_c=="//") { arg = 2; pos+=2; }    //find pos of keyword // 
60       elseif (key_c=="/*") { arg = 3; pos+=2; }    //find pos of keyword /* 
61       else              { arg =-1; pos++; }
62   
63       if (arg>=0){    //if keyword is found 
64   
65          if      (arg==0) { temp=(str.substring(pos-1, LEN).replace(/\\\\|\\\"/g,"xx")); end = temp.search(s_q)+pos; temp=null;}
66          elseif (arg==1) { temp=(str.substring(pos-1, LEN).replace(/\\\\|\\\'/g,"xx")); end = temp.search(d_q)+pos; temp=null;}
67   
68          elseif (arg==4) { var eol  = str.indexOf("\n", pos);    // find end of line 
69                     if(eol==-1){return(CODE+"\nerror : no end of line");}
70                     var temp = next = (str.substring(pos-1,eol+2).replace(/\\\\/g,"xx"));    // end+2 ==> \n 
71                     end = 0;    var t_l=temp.length-2; retrn=false; 
72   
73                   while(end<t_l-1){ //(str.substring(pos-1,end+1))==> /pat/ 
74               
75                      var isReg=true;
76   
77                      next=(temp.substring(end,t_l+1)); // store temp to next 
78   
79                        end=parseInt(end+next.search(Exp)+2); //alert("next="+next); //find next key / 
80   
81                      try{ eval(temp.substring(0,end));}catch(e){isReg=false; var err=(e);}
82   
83                      if(isReg) break;
84                   }
85   
86                   end=parseInt(end+pos-2); temp=null; next=null;
87   
88                     if(!(isReg)){bracket[3]+=err+" : "+(str.substring(pos-1,end+1))+" pos ="+pos;}
89                    }
90       
91          elseif (arg==2) { end = str.indexOf("\n", pos);   pos--; cmt = true; }
92   
93          else    /*arg==3*/  { end = str.indexOf("*/", pos); pos--; end++; //pos-- because 2 char "/*" 
94                          if (end == 0) cmt = false; //if not found(avoid error) 
95                          else         cmt = true; }
96   
97          if (end <= 0) end=str.length-1; end++;
98   
99          if (cmt==false) CODE += str.substring(pos-1,end);//alert(str.substring(pos-1,end+1)); 
100  
101         pos=end; //if(arg==4) pos++; // end=pos at "/" so add 1 
102  
103         cmt=false;  //at last, end up with pos=0  
104  
105      }else{ // else keyword is not found 
106  
107        if((last==";") && (key_q=="}")){ key_q="/**/"; bracket[1]--;} //replace(/\;\}/g,"}"); 
108  
109         if (!(Reg.test(key_r))) { CODE += key_q; last=key_q;}
110  
111         switch(key_q){
112          case"(" : bracket[0]++; break;
113          case")" : bracket[0]--; break;
114          case"{" : bracket[1]++; break;
115          case"}" : bracket[1]--; break;
116          case"[" : bracket[2]++; break;
117          case"]" : bracket[2]--; 
118         }
119          if(pos>=str.length) pos=-1;
120      } 
121     }
122    str=null;
123  
124    CODE=CODE.replace(/^\s+/,"").replace(/[\s\n]*$/,"").replace(/\;\/\*\*\//g,"}");
125  
126    var j=CODE.length;
127    var el=$id("ratio");//el.style.backgroundColor="#000"; 
128    el.innerHTML="Compression Ratio:"+j+"/"+Size+"="+eval(j/Size).toFixed(5);
129  
130    var hr ="\n/*------------------------------------\n";
131    var hr2="\n------------------------------------*/\n";
132  
133    if (eval(bracket[0]+bracket[1]+bracket[2])!=0) 
134      CODE+=hr+"Check pair of brackets. \n () :"+bracket[0]+"; {} :"+bracket[1]+"; [] : "+bracket[2]+hr2;
135    if (bracket[3]!="")
136      CODE+=hr+"Check Syntax of RegExp. \n"+(bracket[3]).replace(/xx/g,"\\\\")+hr2;
137  
138    return(CODE);
139  }
140  

Modified on 29 Sep. 2008

1    /****************************************************************
2     2008 (C)samurai-logic.com
3    
4    
5     Javascript Compressor
6    
7     Last Modified 29 Sep. 2008
8    ****************************************************************/
9    function $compress(str){
10   
11   var Size=str.length;
12   
13   //if(/\n/g.test(str)) return("no end of line"); 
14   
15   str=str.replace(/\t+/g," ");
16   
17   Reg=/([^\d\w]\n[^\d\w]|[^\d\w]\s[^\d\w]|[\d\w]\s[^\d\w\$\_\#]|[^\d\w]\s[\d\w])/;
18   
19   //Exp=/[^\\]\/[^\/]*([\s\,\;]*)((\,\s*(\"|\')|(\w+)\s*\(\s*\/*)[\s\S]+|\/\/[\s\S]+|\/\*[\s\S]+|\s{2,}[\s\S]+|\s*)\n*/; 
20   //Exp=/[^\\]\/([^\/])?(\s)*(([\,\s]*(\"|\')|(\w+)\s*\(\s*\/*)[\s\S]+|\/\/[\s\S]+|\/\*[\s\S]+|\s{2,}[\s\S]+|\s*)\n*/; 
21   
22   //Basic Exp 
23   Exp=/[^\\]\/([^\/])/;
24   
25   chr=/(\(|\=|\[|\:|\||\&|\!|\,)/; // new reg 
26   
27   //these RegExp don't need to replace(/\\\\/g,"xx")...but just in case. 
28   d_q=/([^\\]\"[^\"]*[^\:]|[^\"]\"[\s]*[\:\,\}\]\)\;\.])/;
29   s_q=/([^\\]\'[^\']*[^\:]|[^\']\'[\s]*[\:\,\}\]\)\;\.])/;
30   
31   // Basic RegExp 
32   //d_q=/([^\\]\"|[^\"]\")/; 
33   //s_q=/([^\\]\'|[^\']\')/; 
34   
35   bracket=new Array();
36   
37   bracket[0]=0; bracket[1]=0; bracket[2]=0; bracket[3]="";
38   
39   var CODE  = "";        //new string for compressed code 
40   var cmt   = false;    //cmt=true, char is comment.< -- > cmt=false, char is code. 
41   var arg   = -1;        //arg decide the keyword to find 
42   var pos = end = 0;    //pos = postion of open keyword, end = postion of close keyword 
43   var last=" ";        //last is last char which store to CODE 
44   var temp="";        //temp is to find another keyword 
45   var LEN=str.length;
46   var retrn = false;    // for regexp "return /pat/.test()" 
47   
48      /*-----------------------------------------------
49    While loop begin. check each char in string
50    ------------------------------------------------*/
51       while (pos >= 0){
52       var key_q = str.charAt(pos);    //keyword quot 
53       var key_c = str.substr(pos,2);    //keyword comment 
54       var key_r = last + key_c;    //keyword to test key_q is necessary 
55   
56       if((pos>6)&&(str.substr(pos-6,6)=="return")&&(/^[\s\n]*\/[^\/\*]/.test(str.substring(pos,LEN))))retrn=true;
57   
58       if (key_q=="'")          { arg = 0; pos++; }     //find pos of keyword ' 
59       elseif (key_q=='"')  { arg = 1; pos++; }     //find pos of keyword " 
60       elseif ((key_q=='/') && (key_c!="//") && (key_c!="/*") && ((chr.test(last) || (retrn))))
61                     { arg = 4; pos++;  }     //find pos of keyword / 
62       elseif (key_c=="//") { arg = 2; pos+=2; }    //find pos of keyword // 
63       elseif (key_c=="/*") { arg = 3; pos+=2; }    //find pos of keyword /* 
64       else              { arg =-1; pos++; }
65   
66       if (arg>=0){    //if keyword is found 
67   
68          if      (arg==0) { temp=(str.substring(pos-1, LEN)); end = temp.search(s_q)+pos; temp=null;}
69          elseif (arg==1) { temp=(str.substring(pos-1, LEN)); end = temp.search(d_q)+pos; temp=null;}
70   
71          elseif (arg==4) { var eol  = str.indexOf("\n", pos);    // find end of line 
72                     if(eol==-1){return(CODE+"\nerror : no end of line");}
73                     var temp = next = (str.substring(pos-1,eol+2).replace(/\\\\/g,"xx"));    // end+2 ==> \n 
74                     end = 0;    var t_l=temp.length-2; retrn=false; 
75   
76           /*---------------------------------------------------------------
77    loop to find next keyword "/" and evaluate Regular Expression
78    and if RegExp is NG, store error message to var err.
79    ----------------------------------------------------------------*/
80   
81                   while(end<t_l-1){
82               
83                      var isReg=true;
84   
85                      next=(temp.substring(end,t_l+1));      // store temp to next 
86   
87                        end=parseInt(end+next.search(Exp)+2);  //alert("next="+next); //find next key / 
88   
89                      try{ eval(temp.substring(0,end));}       //evaluate RegExp 
90                       catch(e){isReg=false; var err=(e);}// store error msg to err 
91   
92                      if(isReg) break;//if RegExp is OK, then break 
93                   }
94   
95                   end=parseInt(end+pos-2); temp=null; next=null; //add pos to end, and release memory 
96   
97                     if(!(isReg)){bracket[3]+=err+" : "+(str.substring(pos-1,end+1))+" pos ="+pos;}
98                    }
99       
100         elseif (arg==2) { end = str.indexOf("\n", pos);   pos--; cmt = true; }
101  
102         else    /*arg==3*/  { end = str.indexOf("*/", pos); pos--; end++; //pos-- because 2 char "/*" 
103                         if (end == 0) cmt = false; //if not found(avoid error) 
104                         else         cmt = true; }
105  
106         if (end <= 0) end=str.length-1; end++;
107  
108         if (cmt==false) CODE += str.substring(pos-1,end);//alert(str.substring(pos-1,end+1)); 
109  
110         pos=end; //if(arg==4) pos++; // end=pos at "/" so add 1 
111  
112         cmt=false;  //at last, end up with pos=0  
113  
114      }else{ // else keyword is not found 
115  
116        if((last==";") && (key_q=="}")){ key_q="/**/"; bracket[1]--;} //replace(/\;\}/g,"}"); 
117  
118         if (!(Reg.test(key_r))) { CODE += key_q; last=key_q;}
119  
120         switch(key_q){
121          case"(" : bracket[0]++; break;//in case ( is found then count one 
122          case")" : bracket[0]--; break;
123          case"{" : bracket[1]++; break;
124          case"}" : bracket[1]--; break;
125          case"[" : bracket[2]++; break;
126          case"]" : bracket[2]--; 
127         }
128          if(pos>=str.length) pos=-1;
129      } 
130     } //while loop 
131    str=null;
132  
133    CODE=CODE.replace(/^\s+/,"").replace(/[\s\n]*$/,"").replace(/\;\/\*\*\//g,"}");
134  
135    var j=CODE.length;
136    var el=$id("ratio");//el.style.backgroundColor="#000"; 
137    el.innerHTML="Compression Ratio:"+j+"/"+Size+"="+eval(j/Size).toFixed(5);
138  
139    var hr ="\n/*------------------------------------\n";
140    var hr2="\n------------------------------------*/\n";
141  
142    if (eval(bracket[0]+bracket[1]+bracket[2])!=0) 
143      CODE+=hr+"Check pair of brackets. \n () :"+bracket[0]+"; {} :"+bracket[1]+"; [] : "+bracket[2]+hr2;
144    if (bracket[3]!="")
145      CODE+=hr+"Check Syntax of RegExp. \n"+(bracket[3]).replace(/xx/g,"\\\\")+hr2;
146  
147    return(CODE);
148  }
149  

JS Compressor で excanvas.js を圧縮してみる

Google が配布している excanvas.js をJS Compressor 圧縮してみました。圧縮しても動かなかったので、JScript コンパイラーでコードをチェックしてみると、684行目の終わりに、";" が不足してました。

684行目の } の後に 区切りの ; が足りないために圧縮してもエラーになります。付け加えれば大丈夫です。

682. contextPrototype.fill = function() {
683. this.stroke(true);
684. }
685.
686. contextPrototype.closePath = function() {
686. this.currentPath_.push({type: "close"});
687. };

このエラーは、圧縮したJavascriptファイルをJS RegExp (ここで紹介しているガジェット)でチェックすることが出来ます。JS RegExpの正規表現を /(\})[\w]+/g と書いて、マッチ(.match(RegExp)) で実行します。マッチした中に、}word などの } の次に変数が入っているパターンがあればエラーの可能性があります。

excanvas.js のコードです。サイズが大きいので別ファイルにしてます。785行あります。   excanvas.js

CSSもこのガジェットで圧縮出来ますが、IE用のコメントフィルター

width:267px !important; width /**/:266px; の /**/ の部分が削除されてしまいます。

変数の圧縮は、難しい問題じゃないので後々追加する予定です。

13 Sep. 2008 :アルゴリズムの原本に継ぎ足した部分にバグがありました。全体を組み立て直して改めてアップロードします。

14 Sep. 2008 : 修正してアップロードしました。更新が反映されれば使えます。

テストした Javascript ファイルYUI menu.js(217KB=>73KB)
YUI animation.js(48KB->14KB)
YUI container_core.js(137KB->44KB)
圧縮ファイルを使ったページ

Javascript Compressor (Google Gadget)

改良版のJavascript Compressor のソースコードです。 http://www.samurai-logic.com/mt/2008/09/javascript-compressor-modified.html

ガジェットの貼り付けコード

IE でガジェットが表示されないバグがありましたのでcontent type を html→url にしました。
javascript compressorのソースコードは記事の最後に紹介しています。
使い方:
上に、data1, data2, data3, output の4つタブがあります。data1からdata3のテキストエリアにJavaScriptのソースコードをコピー&ペーストします。

(1) Strip Tag はHTMLのタグを削除します。

(2) Escape HTMLは> < & " ' を&gt; &lt; & &quot; &#039;に変換します。

(3) Unescape HTMLは&gt; &lt; & &quot; &#039; を > < & " ' に変換します。

(4) Strip Commentsはスクリプトのコメントを削除します。コメントとソースコードが重なっていないかなどのチェックに使えます。

(5) Compress Javascriptはスクリプトを圧縮します。

実行ボタン(Execute)を押せば、結果がoutput タブのテキストエリアに表示されます。

圧縮するコードのサイズが大きければ、Google Chrome または Safari を使ってください。
テストした Javascript ファイルYUI menu.js(217KB=>73KB)
YUI animation.js(48KB->14KB)
YUI container_core.js(137KB->44KB)
圧縮ファイルを使ったページ

Javascript Compressor 使用上の注意:
コードの行終わりには必ず「;」が書かれていることを確認してください。

例:
function code(){
  var count = 0
  var temp = 10
  return count+temp
}

上のコードの終わりに count=0; と";"がありませんが圧縮前は正常に動きます。
しかし圧縮後は

function code(){var count=0 var temp=10 return count+temp}

となりエラーになります。


このプログラムはJavascript でdata タブのテキストエリアに貼り付けられたスクリプトを圧縮するので、Javascript の処理速度が生命線になります。ある程度大きなコードの圧縮もガジェットレベルで簡単に出来るようになるようなものを想定してます。コードも効率的でスピードを最も重視して書いています。

Pentium 3GHz (CPU)以上で、メモリに余裕があれば、かなり大きなサイズのJavascript ファイルもGoogle Chromeの高速Javascript engine 搭載のブラウザで実行すれば1秒程で圧縮されます(個人所有のPC1台でしか使ってませんので、誤差があるかと思います)。 Javascriptの処理速度の遅いブラウザでの大きなサイズのファイル圧縮は時間がかかります。

Continue reading

Index of all entries

Home > Javascript AJAX CSS > Javascript Compressor Archive

Return to page top