谈前端代码的精简、混淆、压缩和编译
前⼏天突然想写⼀个css的js压缩⼯具,于是这两天研究了⼀下⼏个js、css的压缩⼯具并且理清楚了⼀些概念和原理,下⾯总结⼀下。
⼏个基本概念
在⽹站部署前,我们往往要对前端的代码进⾏发布,我这⾥说的“发布”,指的就是精简、混淆、压缩、编译或者还有其他的操作,有些操作很相似,但每个操作的都有其中的意义。
精简(minify)
对前端代码精简的⽬的很明显,就是减少代码体积,减⼩⽹络传输时间,提⾼页⾯响应。
⽽具体到如何精简,其实也很简单,下⾯是其中的⼀些办法:
1.删除代码注释
2.删除⽆意义或者多余的空⽩(如空格,制表符,回车,换⾏)
3.删除可以省略的符号(如css最后⼀条规则后⾯的分号,js块内最后的⼀条语句的分号)
4.缩短语句(如果css的简写,html中disabled='disabled' 改成disabled , js中缩短局部变量)
对于精简这个功能,⼤部分⼯具都基本实现了上⾯的⽅法,包括有yuicompresser,closure complie,jsmin,packer.
混淆(obfuscation)
混淆这个功能主要针对Javascript代码,它的⽬的是减低代码的可读性,防⽌被追踪出程序逻辑。
事实上,对代码精简,压缩,编码都有混淆的效果。
⾸先,上⾯提到精简的办法中,删除注释,删除缩进(空格,制表符,换⾏),缩短局部变量都可以有效减低程序可读性。除了删除缩进可以⽤过js格式化/美化⼯具还原,其它两个步骤都是不可逆的。
其次,通过编码混淆代码,这篇⽂章⾥⾯介绍了很多⽜X的编码加密⽅法。但是这些⽅法有个明显缺点,增加代码体积,⽽且编码加密都是可逆的。
最后,通过压缩的办法,当然,也是可逆的,下⾯我们详细探讨⼀下。
压缩(compress)
压缩这⼀个说法很常被⽤来概括前⾯这三种操作,其实上,真正实现压缩的我⽬前只看到⼀种⽅案:的base64编码压缩.
这⾥可以先看⼀个简单的例⼦:
压缩前代码:
压缩后代码:
1eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){returnr[e]}];e=function(){return'\\w+'};c=1};while(c--
)if(k[c])place(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);returnp}('1.2("0").3="4 5 6 0";',7,7,'header|document|getElemntById|innerHTML|This|is|the'.split('|'),0,{}))
压缩后的代码很恶⼼,但是认真研究可以发现⾥⾯只有三个东西:压缩后原⽂,字符表,解压器。
packer的base64编码的压缩率很⾼,精简后代码依然可以减少50%体积以上,因为带有解压器,和字符表,上⾯的例⼦没有体现压缩效果,⼀般来说,越长的代码压缩率更⾼。
如果对⾥⾯构造有兴趣的可以直接研究packer的源代码,算法都是⽤js写的,另外,还可以看看这篇⽂章.
很多地⽅都把packer这个功能称为混淆,当然,这的确有混淆的效果,上⾯也提到。但是,从算法上看,packer base64 encode是⼀个字典压缩算法,故这⾥归类为压缩。
另外,需要提醒的是,虽然压缩有混淆效果,但是过程依然可逆,⽽且解压器和字符表明摆在那⾥,只要把eval四个字母改成alert就可以看到压缩前的代码。
因为⽤了邪恶的eval,packer后的代码性能会减低...很多,另外,解压的过程也会消耗⼀点时间。
特别要注意的是,如果服务器有gzip功能,就不必也不应⽤packer base64 encode来压缩。因为packer base64 encode压缩加gzip压缩后的体积⽐源代码只⽤gzip压缩还要⼤。
原因也可想⽽知,我们⽤js进⾏了⼀次低效压缩,gzip压缩的空间就⼤⼤减低了。
编译(compile)
说到编译,不得不先提到,它和其他⼯具不同的是,除了精简功能,它还可以对Javascript代码进⾏优化。
gcc的⾼级模式会对Javascript进⾏语义分析,然后会进⾏删除⽆⽤代码,删除没有使⽤的变量,优化逻辑关系等⽐较激进的优化。
虽然编译前后都是Javascript代码,但是这个过程已经算得上实际意义上的编译了。
js代码加密软件另外,除了gcc,还要说的是最近很流⾏的⼀些新语⾔:, , ,这⾥先简单扫盲⼀下:
coffeescript是⼀个类ruby的语⾔,书写起来更加简洁和优美,coffeescript可以完全编译成同效的Javascript。
⽽less和sass是在css上进⾏语法扩展,在css上实现了变量,作⽤域,函数之类的功能。
现在,类似这样的语⾔,⼯具,框架越来越多,好像的可以对线性代码编译,不⽤我们写⼀堆回调。⽟伯的seajs可以“预编译”模块,出模块依赖关系来异步load顺序执⾏模块。
github上有⼀份记录了所有的这类东东,有兴趣可以去研究⼀下。
谈到这些,我们仿佛感觉到了前端发展的⼀个趋势,我们原来写的html,css,Javascript已经开始变成了⼀个“中间语⾔”,⽽且越来越多的团队也有了⾃⼰的⼀套前端编译系统更加彰显了这个趋势。
李松峰⽼师博客⾥⾯有两篇⽂章也对这个话题进⾏了讨论:
这是⼀个有趣的话题,上⾯很多内容只能贴个链接了,也许下次应该单独做⼀篇⽂章来慢慢讨论⼀下。
CSSPacker
这是我研究⼏个压缩⼯具后,⾃⼰突发奇想写的⼀个⼩玩具。
简单介绍⼀下,上⾯提过packer,这是⼀个真正意义上⽤Javascript实现的压缩解压⽅案(当然,相对于客户端的⼀些压缩软件还差很远),它本来是⽤来压缩Javascript的,我把它移植⼀下,折腾出这个csspacker⽀持压缩css。
本来有三个功能:精简代码,缩短局部变量,base64编码压缩,下⾯简单介绍⼀下:
1. packer原本精简代码是根据Javascript语法精简的,我把精简代码部分重写了,以适应css语⾔;
2. 缩短局部变量没⽤,直接删掉这个操作;
3. base64编码压缩适⽤于任何⽂本,可以直接保留。但是解压的操作要修改⼀下,原来Javascript直接把解压后的字符串eval⼀下就好
了,css⽐⽐较蛋疼,要新建⼀个style节点,把解压后css⽂本插进去。
另外⼀个⽐较重⼤的问题是,图⽚路径问题。css⽂件上使⽤的相对路径是相对于css的位置的,但是js是相对于页⾯的位置的,所以,如果css含有相对路径,要输⼊css所在⽹络位置,它会⾃动把⾥⾯的相对路径转换为URL。
路径问题让这个packer不那么⽅便了,我还考虑其他⽅案。⽬前的另外⼀个想法是,fork⼀个分⽀,把csspacker功能弄进去。
好吧,有兴趣的欢迎去调戏调戏⼀下。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论