作为开发,不止是前端,优化永远是绕不开的,我们的目标是让产品更快。优化的对象不仅仅是指产品本身,还有我们日常的开发过程。从加入团队到现在,大约一半的时间都花在了优化上。这期间遇到了很多问题。回过头来看,优化并没有那么简单,也是一件很微不足道的事情。要打造一个无痛开发流程和持续优化产品相对容易,真的不容易。没有灵丹妙药,任何项目都需要花费大量时间和精力。但任何值得改进的改进,都让我们觉得辛苦没有白费。有时我只想偷懒,摆脱无聊的重复。我刚进来的时候,加上我的团队,一共有3个全职前端开发人员。项目比较简单。前人在模块化方面做得很好,但是感觉做的还不够彻底。后来项目逐渐庞大,再加上重构同学的加入,当时人数达到了13人。这个过程中遇到了很多问题。前端框架进化了三次,都是因为一些棘手的问题,不得不做出调整。没有绝对的好与坏,只有适合与不适合。11.0时代前期,模块化已经做得很好了,至少不用花很多时间去重构代码。模块划分如下图,逻辑层级比较清晰。前端模块化所依赖的主流库是国内的seajs和国外的requirejs,这里就不说了。Seajs作为模块管理器,zepto作为基础库文件,lib主要包括项目中使用的主流第三方库文件。我们知道,模块化带来的最大弊端是HTTP请求量的增加,所以上线时必须合并文件。下图的打包模块是一个大的文件集合,打包了很多JS模块。除了上图中的基础库文件和业务模块层,大部分文件上线时都打包在package.js中。大多数页面的JS请求是这样的:细心的同学可能会注意到两个问题:文件大小和加载时间。刚才的截图是在PC端截的,手机端和不同网络环境下的表现会更差。现在我们来看一下目录的问题:目录看起来是标准的,但实际上它是公共和业务的混合体。大部分文件合并为一个文件,合并策略不合理。第二点带来的第三个问题是,发布上线的时候,只要涉及包文件两个人发布,就不可避免的会发生冲突。发布时需要下载最后一个文件,与合并后的新文件进行对比,避免发送错误。注意第四点是人为的。不小心发错了,或者覆盖了别人刚刚发布的文件,这种事情发生了不下10次。测试机只有一台,测试环境频繁覆盖是家常便饭。版本控制问题,不是用SVN作为版本,而是在机器上预发布代码,管理混乱。不敢想象如果一个10+人的团队在这种模式下一起开发会是什么样子。22.0时代第一个版本带来的问题,真是让人痛心。每次开发一个版本都是一件痛苦的事情,尤其是在测试和发布的过程中。所以开始慢慢工作。随着业务的扩大,人员的增多,就诞生了下面的图。优化措施:调整模块,使共享模块更加通用,业务模块跟随业务本身。更改模块合并策略。既然大了,我就把它分成小的,一定程度上缓解了冲突。替换原来的同步文件工具,包括测试环境和官方环境,接入ARS,测试发布过程顺畅很多。ARS具有冲突检测功能,告别手动比较和合并,覆盖不再容易发生。公共JS文件缓存在localstorage,模拟manifest,有版本号控制。使用SVN作为面板控制工具,不再比对外网代码。一些统计localstoragelocalcachelocalstoragecachehitratefirstscreentimewindow.onloadtime一切看起来都很好,但是好景不长,因为新的问题又来了。在将package.js文件拆分成多个文件之前,实际请求是合并请求,包括JS文件和CSS文件。combo文件其实存在延迟问题,在发布的时间节点出现不同步的问题,直接导致页面挂掉。除了combo文件,由于浏览器缓存的问题,每次更新版本都要手动添加时间戳,避免缓存导致的错误。也是很痛苦的一点。随着业务的增长,APP中访问的页面越来越多。触屏页面不再是重点,如何更好的利用APP加速页面才是重点。很多人想到了手Q的离线包,但是听说在实践中不是很方便,所以我们采用了客户端缓存hash文件的策略,告别了304。于是自动化又来了。雪碧图像基本上是手动的;代码混淆不压缩;CSS合并文件需要写地址,类似如下:http://at.qq.com/min/f=cssv4/common/reset.css,cssv4/common/base.css,cssv4/module/btns.css,cssv4/module/tab.css,cssv4/module/app-list.css,cssv4/module/talk-bar.css,cssv4/module/popup.css,cssv4/page/game-detail.css,cssv4/page/talk.css,cssv4/module/comments-bar.css33.0era为了解决以上问题,还需要进一步优化流程。简单点就是提高自动化程度。3.1探索期前期也有一些关于方案选择的讨论,没空从底层写起。之前折腾过Grunt之后,发现并没有那么好用。后来发现百度的前端解决方案FIS可以满足我们的需求。生成以hash值(后缀)命名的文件,改代码,生成新文件,并自动更新HTML中的引用(核心诉求),如下图:Mergesprite图片压缩混淆文件合并(包括JS文件和CSS文件)能做到这几点就基本可以满足我们的需求了。前期一切都是未知数,不太明白会遇到什么大问题。乍一看,它看起来非常好用。如果是简单的页面,会很简单。简单的几行配置就可以搞定,但是目前FIS的配置文件已经有200+行了。有些特性很难满足,需要二次开发。入门容易,深入难。必须阅读源码才能修改源码和编写插件。这大概就是使用FIS的经验吧。前期想的是如何依靠工具把开发-测试-预发布-发布这个流程顺畅的跑起来。总体思路如下:注意:调试和发布代码与源代码分开。本地调试代理如fiddler,或者在线开发Machinedeploy是构建工具同步文件保证源代码最新版本的功能,通过ARS发布代码。工程的进展并不像想象的那么顺利。实践中遇到了一些问题,只能硬着头皮咬牙解决。3.2苦难时期的矛盾矛盾一直存在,只是到了2.0时代就没有那么明显了。原因是测试环境的JS已经合并过一次了。时间问题由于一开始文件比较少,所以构建速度基本没问题。后来,业务越来越多,涉及的开发也越来越多。文件数量增加到4000+,构建时间一步步增加。开发调试耗时3987ms,发布构建时进行md5计算和文件压缩耗时181745ms!真受不了。在ARS过程中用过ARS的同学一定明白,这个过程还是挺痛苦的。完成提交到SVN、点击同步等一系列操作比较繁琐。buildcommand命令比较长,参数多,输出文件比较难记。发布起来很麻烦。每修改一个字母,发布时就会生成一个新的文件。发布的时候真的是在文件堆里找!!这一系列的问题像一座山一样倒下,群里的开发同学再也无法愉快的开发了。3.3深度优化减少冲突的进一步解决方案是对模块进行细分。测试环境不合并文件,所以冲突的概率几乎很小,因为公用库经过2.0的调整已经基本稳定。缩短时间建设时间这么长,这样开发是行不通的。花了一些时间研究了FIS的源码,发现FIS监听的是整个工程文件,每次构建都需要扫描所有文件,所以随着文件数量的增加,时间必然会增加。然后进行深度改造,变得不那么像FIS。一次次优化,改变构建策略。依赖构建:当一个文件依赖于另一个文件时,将构建另一个文件。如果a.html依赖b.js,构建时只产生这两个文件,其他文件不构建,文件数量减少,时间大大缩短。开发构建(单位毫秒)发布构建(单位毫秒)构建命令优化输入命令比较麻烦,直接使用GUI界面,点击按钮即可。在此感谢@koppthe@kolawang短时间内用node编写的GUI。输出文件更多地依赖构建后,只输出相关文件,输出文件将大大减少,发布难度将大大降低。ARS进程修复bug时,不需要ARS同步,直接将监控文件的变化同步到测试环境。仅需8ms!!!.如果开启同步按钮,修改后的文件会立即上传到测试环境,不会有相互覆盖的问题。群里每个人负责不同的模块,公共模块基本稳定,很难出现这样的问题。在实践中,这样的事情很少发生。相反,我的朋友们觉得他们松了一口气。比起繁琐的查找和传输文件的过程,轻松多了。发布优化构建工具会生成一个文件列表,点击打开文件夹,找到对应的文件;列表对应SVN路径,账单直接粘贴到ARS即可计费。sprite图片优化发布后,会将所有引用的CSS文件合并为一个,然后将引用的图标合并为一张sprite图片,有点粗鲁。因为将公共CSS文件的图片单独合并成Sprite图片比较合理,公共图片的变化频率也不会那么高。开发一个插件,CSS合并前精灵一次,合并后精灵一次。统计和优化无法统计用户网络类型(大致)未知。理论上wifi还是占多数。从其他四种类型来看,wifi占据绝大多数,2g用户很少。在PCVSMobile的JS下载和执行效率上,移动端明显低于PC端。JS优化前,app内部的JS文件都是通过seajs下载的。后来才知道为什么不直接写
