Maven中使用yui和minify压缩css js资源

原文地址 http://www.mark.ah.cn

YUICompressor

minify

closure-compiler介绍

CC 是真正的编译器

Closure Compiler 和 YUI Compressor 并不是同类产品,虽然 CC 和 YC 同样产出压缩后的 JS 文件,但是 YC 只做了词法上的扫描,而 CC 并不只是一个 compressor 那么简单,器如其名,它是一个compiler。

CC 功能概述

在详细讨论 CC 的高级模式前,还是简明介绍一下功能体系。

编译级别

CC 的 compilation_level 包括三个级别:

1.WHITESPACE_ONLY

只删除空白、注释。

2.SIMPLE_OPTIMIZATIONS

在 WHITESPACE_ONLY 基础上将局部变量和参数转成短名称。

3.ADVANCED_OPTIMIZATIONS

更加激进的重命名、移除垃圾代码、内联函数。

可以看到,SIMPLE_OPTIMIZATIONS 级别的 CC,和 YC 无异,没做什么真正的编译工作,所以说,使用了高级模式的 CC 才是四肢健全的 CC 。

约束条件

使用 CC 有一定约束条件,这影响到我们的编码风格:

1.WHITESPACE_ONLY

不认可 JS 1.5 以上版本的语言特性

不保留注释

2.SIMPLE_OPTIMIZATIONS

完全禁用 with 和 eval

字符串中引用的函数名 / 参数名不会改动(CC 不改动所有字符串)

3.ADVANCED_OPTIMIZATIONS 模式下的约束放到下文详述

注解Annotations 也是 CC 的重要组成部分,使用 JSDoc 风格,用以辅助高级模式下的编译,下文详述。

使用 CC 高级模式

在 CC 下,启用高级模式的方法是加入参数 --compilation_level ADVANCED_OPTIMIZATION。

作为一个 compiler,CC 的高级模式下,额外的优化政策是:

1.更激进的重命名,如 obj.property 改为 a.b,将深度过高的命名空间平坦化等;

2.移除垃圾代码,如删除未被调用的方法定义,警告逻辑死角(return 后的语句等);

3.将函数内联,如 a call b, b call c,a(),那么直接执行 c()。

要达到高级模式的预期优化效果,开发者必须对自己做一些约束,因为 js 是弱类型、动态性的。否则js 的这种灵活将使 compiler 无能为力。

总体上,这种约束包括限定某些 js 编码风格,以及使用相应的 JSDoc 注解。

以下详述具体的约束以及代码的检查 / 优化效果:

强类型的模拟

•使用 @private 标注私有域,私有域被外部引用会报错。开发者也可以按照“国际惯例”给私有域加上_ 前缀或后缀,以提醒自己 / 协作者这是一个私有域,@private 注解用来告诉 CC;这样,开发者可以不必使用诸如老道的“模块模式”等技巧来真正地隐藏私有变量,将检查工作丢给CC,让开发尽可能朴实简单。

•类似有 @protect

类系统的模拟

•使用 @extends 标注继承关系,继承体系会被优化。

•使用 @interface 标注接口,接口是类似 function ThisIsAInterface(obj) {}的 函数体为空的构造器定义,编译后将移除其相关代码。同时,标注 @implements 的构造器必须实现implemented 的接口的所有方法(正如其他 OO 语言一样),否则,CC 报错。这同样简化了接口 / 实现的约束,靠 CC 来保证实现关系的可靠性。

条件编译的模拟

•使用 @define 标记状态开关,适用于调试 logger 等 开发 / 发布 状态需要分离的模式。

可以在编译时指定参数来标识 define 参数的状态。这其实就是一个条件编译,真给力……

对象平坦化及属性名缩减

•对象属性会被编译为单变量,比如 foo.bar to foo$bar,这种标记方法看起来很像 java 中被编译出来的内部类~~之后 foo$bar 被进一步缩短。对象之所以能被平坦化是因为在 js 中对象可以看做是一群引用 / 原始数据类型的容器。

•但是,js 对象实际上更复杂,所以被平坦化后会带来一些副作用,比如如果在对象(字面量)中使用 this 指针,则编译后的结果会导致 this 指向错误。所以 Google 建议仅在 constructor 和 prototype methods 中使用 this,这意味着,在所谓类单例(对象字面量)和类的静态方法(绑定到constructor 上的函数)中都避免使用 this 指针。

•在缩减对象属性 / 方法的名称长度时,有另外一个注意点,那就是必须始终使用 dot syntax(.运算符),而不使用 quoted string([] 运算符),除非索引名是一个变量。这是因为 CC 始终不处理字符串中的内容,所以,var o = { longName: 0 }; o["longName"] 会被翻译为var a = { b: 0 }; a["longName"] 导致出错。实在想使用 quoted string,则在定义的时候也要使用 quoted string。

•对于全局变量,如果出现以 window.property 的形式引用的,必须始终定义为 window.porperty 形式:

window.property = 1;var property = 1; // wrong!

否则也会杯具,CC 可不会 window.property 翻译为 window.a。

垃圾代码的移除

•一个函数声明却未被调用时,默认地,声明体将被干掉。

•在这种机制下,如果一个方法是以 for in 的形式调用的,那么原方法也会被干掉,因为这种动态特征使得 CC 无法清楚方法是否确实在 for in 的时候被调用了。

•对于一些 unreachable 的代码,CC 将报警告。

•如果要产出一份被调用的公共接口,例如库,使用称作 export 的方法将函数导出,防止函数定义被

CC 回收。具体的做法是将函数绑定到某个容器,比如:

function displayNoteTitle(note) { alert(note['myTitle']);}// Store the function in a global property referenced by a string:window['displayNoteTitle'] = displayNoteTitle;

对于需要 export 的函数,均使用 quoted string 风格。

背后的思考

根据以上高级模式优化的行为分析可知,CC 附加给开发者的约束主要有:

1.强制以强类型的静态语言风格编写 js,将关注点从运行时的动态技巧转移到组织代码、编写逻辑本身。而可能由弱类型系统和动态特征产生的问题和风险则交给 CC,即通过开发者与 CC 达成一种编码约定而规避掉。

2.严格要求区分面向开发者的代码和面向机器的代码。

虽然不像 C 等语言会编译产生目标代码,但是 CC 在一定程度上也生成了面向机器的 js,包括压缩空白、缩减标识符、条件编译和冗余代码去除。这和第一点其实是一脉相承的,同样要求开发者将关注点转移到开发本身。

3.使用规范化的接口方式。

这不仅包括要求开发者使用恰当的 annotation(extend, interface, …),同时也给整个 OO-JS 打下了一个框架,开发者必须使用同样的模式进行 OO 编码。另外,要求使用 export 技术统一导出公共接口更强化了这一点。总之,这一点进一步限定了开发者的编码风格,但是带来的好处是明显的:可读、可控、一致性。

曾经有读过 Closure Library 源码的同学评论道:

Google 根本不懂怎么写 javascript!代码里面各种冗余,并且充满了 java 的味道!

当时确实也有这种感觉,比如 Google 把 if(foo) 写作 if(foo != undefined) 等等。

Javascript 固然充满了丰富的动态特征,而且很多特性非常优雅,能够让代码简洁精悍,或者构造出一些令人惊叹的技巧,但是也会产生一些副作用:

•首要的问题是可读性,静态的东西容易一目了然,动态的东西需要经过一番运算才能得出结论。比如 js 中的极晚绑定,再比如标识符运行时重写。

•其次的问题是执行性能。一个比较经典的众 js 工程师都在使用的技巧就是“模拟函数重载”——

在函数体内判断 arguments 的特征,从而对应给出不同的逻辑。由于缺乏强类型,js 本身不能具备真正的重载,但是运行时的判断在带来灵活性的同时,必然会多出很多模拟重载的逻辑,降低性能。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,810评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • 像点燃了夜的野火堆, 漆黑的美,明亮的媚… 是劝你早点归家, 你说你不想离去、眼角带着泪; 哭态也绝美。 这褪色的...
    可乐薄荷丶阅读 225评论 0 1
  • 不管我们一生经历了任何复杂不堪的东西,最后,我们都会返璞归真。 “真”的表面有虚假,丑恶。这两...
    烽火煤阅读 108评论 0 1