随手做的一个用PHP压缩javascript,css的小脚本

young40博客原文:http://www.cnblogs.com/young40/archive/2012/03/22/2411239.html

 


同一个网页上需要打开的http连接数, 对网站的速度和服务器的压力有着较大的影响, 所以我们需要采用多种方法来在保证功能的前提下来尽量减少http的连接. 比如可以将几个小的js文件, css文件合并成一个文件,然后再对其进行压缩处理, 在减少http连接的同时, 还能减少数据的传输量

SAE不支持磁盘写入, 如果您要使用这个小脚本的话, 需要在本地运行, 将压缩过的代码通过svn上传.
以后我会不断改进, 最终会支持直接线上输出压缩过的js文件的.

实际上, 我准备在本地调试模式的情况下, 每次(或者一定几率)打开网站页面的时候都生成一次. 本地调试调用原始文件编译查错, 线上应用则调用压缩过的js/css

这次随手做的, 时间仓促, 未加详细测试. 压缩合并css完全未实现/测试.
虽然我很希望大家多多使用这个脚本,但是还是要提醒大家使用的话需要多多测试.
另外, 也希望大家多找找bug, 多提意见.

效果如何呢?
除了我写的几个用于测试的脚本之外, 主要思采用了jquery的未压缩版本测试.
例如jquery-1.7.1.js 248,235 bytes (250 KB on disk)
我这边压缩过之后,158,214 bytes (160 KB on disk) 直接压缩掉近100K
当然,jquery官方的压缩版本是93,868 bytes (94 KB on disk). 由此可见, 这个程序还有很大提升的余地.
或许你会疑惑了, 为什么我这边压缩出的版本足足比官方版本大了接近70K? 这是因为jquery官方的压缩不仅仅去掉了注释, 而且还采用了混淆.
比如
function test(number_one, number_two){return number_one+number_two;}会被混淆成
function test(a, b){return a+b;}
可以看到混淆过后的函数仅仅只有原始函数的一半的长度.
当然这是一个很容易读懂的例子, 如果是一个巨大的函数或者类的话,被混淆过之后还极难理解的,以后会考虑做混淆的功能.

我本意是想使用正则来分析js文件, 可惜正则功力不够.
比如我无法用正则区分下面这个, 抛砖引玉, 希望大家讨论下.

/**
我是多行注释
*
*/

var str = '/** 我不是注释,我是字符串 **/';




所以我用了比较笨的方法来实现, 采用语法分析token的方式,没有正则那么优雅啊
直接贴出使用方法和分析的操作代码.

调用方法.

$mc = new MinCode();

$mc->turnCleanEntersOff() //
->turnCleanSpaceOff()
->addFile($base.'/js/ajaxupload.js')
->addFile($base.'js/jquery-1.7.1.js')
->addFile($base.'/js/u.js')
->addFile($base.'js/u2.js')
->addFile($base.'js/u3.js')
->save($base.'./js/j.min.js');




核心分析代码:


$content = file_get_contents($file);

$token_one = false; //遇到了 单引号
$token_two = false; //遇到了 双引号
$token_pattern = false; //遇到了 正则
$token_comment_quick = false; //遇到了 //这种注释
$token_comment_big = false; //遇到了 /** */这种注释

$rs = '';
$normal = true;
$skip = false;
$skipped = " ";

$length = strlen($content);

for($i=0; $i<$length; $i++)
{
$skip = false;

$c = $content[$i];
$p = isset($content[$i-1]) ? $content[$i-1] : false;
$n = isset($content[$i+1]) ? $content[$i+1] : false;

if($normal || $token_pattern)
{
if($normal && $c=='/' && $n!==false && $n!='/' && $n!='*')//第一次遇到了一个/ 并且不是// 和 /*
{
$token_pattern = true;
$normal = false;
}
elseif ($token_pattern && $c=='/' && $p!==false && $p!="\\")//第二次遇到了/ 并且不是被转义的/即不是\/
{
$token_pattern = false;
$normal = true;
}
elseif ($token_pattern && in_array($c, array("\r", "\n", "\n\r") ) )//这一行结束了,但没有遇到正则结束的/, 按道理来讲应该是javascript代码出了问题
{
$token_pattern = false;
$normal = true;
}
}

if($normal || $token_one)
{
if($normal && $c == "'")//字符串开始
{
$token_one = true;
$normal = false;
}
elseif($token_one && $c == "'")//字符串结束
{
$token_one = false;
$normal = true;
}
}

if($normal || $token_two)
{
if($normal && $c == '"')//字符串开始
{
$token_two = true;
$normal = false;
}
elseif($token_two && $c == '"')//字符串结束
{
$token_two = false;
$normal = true;
}
}

if($normal || $token_comment_big)
{
if($normal && $c == '/' && $n!==false && $n=='*')//遇到了/*
{
$token_comment_big = true;
$normal = false;
}
if($token_comment_big && $c == '/' && $p!==false && $p=='*')//遇到了*/
{
$token_comment_big = false;
$normal = true;
$skip = true;
}
}

if($normal || $token_comment_quick)
{
if($normal && $c == '/' && $n!==false && $n=='/')//遇到了//注释
{
$token_comment_quick = true;
$normal = false;
}
if($token_comment_quick && in_array($c, array("\r", "\n", "\n\r") ) )//遇到了回车, 单行注释结束
{
$token_comment_quick = false;
$normal = true;
}
}

if($normal || $token_pattern || $token_one || $token_two)
{
if(!$skip)
{
$rs .= $c;

if(in_array($c, array("\r", "\n", "\n\r")) &&
!in_array($skipped[strlen($skipped) - 1], array("\r", "\n", "\n\r")))
{
$skipped .= $c;
}
}
else
{
$skipped .= $c;
}
}
else
{
$skipped .= $c;
}
}

if($this->_cleanEnters)
{
//会破坏字符串中的 各种 下述字符, 下个版本准备修复
$rs = str_replace(array("\r", "\n\r", "\n", "\t"), '', $rs);
}

if($this->_cleanSpace)
{
//会破坏字符串中的多个连续空格, 下个版本准备修复
for($i=0; $i<10000; $i++)
{
if(!strstr($rs, ' '))
{
break;
}

$rs = str_replace(' ', ' ', $rs);
}
}

return $rs;


几天不写博客, 发现不会插入附件了

如果要下载附件,请移步http://cloudbbs.org/forum.php?mod=viewthread&tid=684 2楼

posted on 2012-03-22 10:53  young40  阅读(616)  评论(0编辑  收藏  举报

导航