时下grunt非常的火啊,用着虽然很爽,但是它的配置确实很烦。如果之前没有用过,想要一下子熟练驾驭它,有一定的学习成本,而且还要装node这个大家伙,项目之初我们选择了compiler.jar这个轻量的工具进行打包。我一直在寻思着,如何编写一键打包工具。之前呢是手工的拼接好有的js文件,做成符合compiler.jar打包文件所要求的批处理文件,然后运行这个批处理,生成我们需要的js和css文件。随着js文件数量的增长,纯手工拼接这些文件的地址就变得非常考验人的耐心了,而且还容易漏掉或重复某些文件,于是“一键打包工具”的编写就变得刻不容缓了。下面是一个真实的index.html文件的一部分:
doctype html>html>head> meta charset=utf-8> meta http-equiv=x-ua-compatible content=ie=edge,chrome=1> meta name=viewport content=target-densitydpi=device-dpi, initial-scale=1, user-scalable=0, maximum-scale=1> script src=lib/data/database.js name=nobuild>script> script src=lib/loadmode.js>script> script src=lib/core/jquery.js>script> script src=lib/core/underscore.js>script> script src=lib/animate/svgicons/snap.min.js>script> script src=lib/animate/pixi.js>script> script src=lib/core/xut.js>script> script src=lib/core/ismobile.js>script> script src=lib/core/aaronrequire.js>script> script src=lib/core/nexttick.js>script> script src=lib/config.js>script> script src=lib/core/lang/object.js>script> script src=lib/core/lang/function.js>script> script src=lib/core/lang/array.js>script> script src=lib/core/video.js>script> script src=lib/core/event/asevented.js>script> script src=lib/core/message/pms.js>script> script src=lib/plugin/cordova.js>script> script src=lib/plugin/readassetsfileplugin.js>script> script src=lib/plugin/initdatabase.js>script> script src=lib/plugin/web.js>script> script src=lib/plugin/video.js>script> script src=lib/plugin/openappplugin.js>script> script src=lib/plugin/tabletplugin.js>script> script src=lib/plugin/statusbar.js>script> script src=lib/plugin/iap.js>script> script src=lib/plugin/appstorelink.js>script> script src=lib/plugin/downloadplugin.js>script> script src=lib/plugin/xxtemanager.js>script> script src=lib/plugin/unzipplugin.js>script> script src=lib/plugin/readplugin.js>script> script src=lib/plugin/deleteplugin.js>script> script src=lib/animate/tweenmax.min.js>script> script src=lib/animate/plugins/throwpropsplugin.min.js>script> script src=lib/animate/pptanimation.js>script> script src=lib/animate/canvasanimation.js>script> script src=lib/animate/dragdrop/draggable.min.js>script> script src=lib/animate/dragdrop/dragdrop.js>script> script src=lib/animate/iscroll.js>script> script src=lib/animate/hammer.js>script> script src=lib/animate/svgicons/svgicons-config.js>script> script src=lib/animate/svgicons/svgicons.js>script> script src=lib/animate/spritea.js>script> script src=lib/util/utils.js>script> script src=lib/util/localstorage.js>script> script src=lib/util/scriptload.js>script> script src=lib/util/executesql.js>script> script src=lib/util/promptnotice.js>script> script src=lib/util/edge.js>script> script src=lib/data/store.js>script> script src=lib/data/storemanager.js>script> script src=lib/main.js>script> script src=lib/initialize.js>script> script src=lib/scenario/scenelayout.js>script> script src=lib/scenario/scenefactory.js>script> script src=lib/scenario/scenecontroller.js>script> script src=lib/loadscene.js>script> script src=lib/dispatcher.js>script> script src=lib/toolbar/navbar.js>script> script src=lib/toolbar/stoolbar.js>script> script src=lib/toolbar/ftoolbar.js>script> script src=lib/toolbar/searchbar.js>script> script src=lib/toolbar/bookmark.js>script> script src=lib/threadtask/buffer.js>script> script src=lib/threadtask/taskcontents.js>script> script src=lib/threadtask/taskcomponents.js>script> script src=lib/threadtask/taskbackground.js>script> script src=lib/threadtask/taskcontainer.js>script> script src=lib/pagebase/parser.js>script> script src=lib/pagebase/collection.js>script> script src=lib/pagebase/multievent.js>script> script src=lib/pagebase/pagebase.js>script> script src=lib/pagebase/page.js>script> script src=lib/pagebase/master.js>script> script src=lib/controller/transform/translation.js>script> script src=lib/controller/overrideapi.js>script> script src=lib/controller/abstract.js>script> script src=lib/controller/emitter.js>script> script src=lib/controller/pagemgr.js>script> script src=lib/controller/mastermgr.js>script> script src=lib/controller/compiler.js>script> script src=lib/controller/viewmodel.js>script> script src=lib/controller/switchpage.js>script> script src=lib/controller/eventdrive.js>script> script src=lib/scheduler/assignautorun.js>script> script src=lib/scheduler/assigntrigger.js>script> script src=lib/scheduler/assignsuspend.js>script> script src=lib/scheduler/assignoriginal.js>script> script src=lib/scheduler/assignrecovery.js>script> script src=lib/scheduler/processcontrol.js>script> script src=lib/scheduler/binding.js>script> script src=lib/directives/dir-content.js>script> script src=lib/directives/dir-widget.js>script> script src=lib/directives/dir-media.js>script> script src=lib/directives/dir-action.js>script> script src=lib/directives/dir-shownote.js>script> script src=lib/component/media/audio.js>script> script src=lib/component/media/video.js>script> script src=lib/component/media/audiomanager.js>script> script src=lib/component/media/videomanager.js>script> script src=lib/component/content/confilter.js>script> script src=lib/component/content/conalgorithm.js>script>
后面还有很长,bug,活人不能被尿憋死,办法总比问题多。我是会一点php的,php在处理文件方面是很拿手的,是时候让它发挥点作用了。于是我想到了用php去自动提出index里边的js和css,然后按指定的格式生成批处理文件,在后台用静默方式运行这个批处理,最后把结果返回给显示器。这样我就可以坐享其成了。想想都有点小激动哟,于是简单的写了一个界面.
接下来就是实现功能了,先不着急编写代码,分析下需求:
1. 遍历index.html文件,提取js文件或css文件.
2. 对这文件进行过虑,因为有些是注释掉的,有些是调式用的。
3. 生成对应的批处理文件
4. 执行批处理文件
5. 显示处理结果
即然有两种情况,我就用一个工厂模式来适配,方便以后扩展其它类型,目光要放长远一点。即然工厂都有了,那索性再来一个接口,约定都必需要实现“接收请求”和“输出结果”这两个接口。再想想处理js和css都可能会有相同的功能,让它们继承一个父类可以使代码复用,于是继承也先用上。目前的设计应当可以满足我的要求了,于是开始编写php代码.
phpheader(content-type: text/html; charset=utf-8);/** * 根据index.html文件中引用的js,生成compressjs.bat * @author frog * @date 2014-11-17 */interface icompress { /** * 处理用户请求 * @return [type] [description] */ public function request(); /** * 处理输出结果 * @return [type] [description] */ public function render();}class basecompress { public $content; public $outpath; public $isauto; public function __construct($isauto=false){ $outpath = '_file'; if(!is_dir($outpath)){ mkdir($outpath); } $this->outpath = $outpath; $this->isauto = $isauto; } /** * 运行批处理 * @return [type] [description] */ public function runbat($name){ }}/** * 压缩javascript文件 * 合并javascript文件 */class compressjs extends basecompress implements icompress { /** * 处理用户请求 * @return [type] [description] */ public function request(){ } /** * 处理输出结果 * @return [type] [description] */ public function render(){}}/** * 压缩样式文件 */class compresscss extends basecompress implements icompress { public function request(){ } /** * 处理输出结果 * @return [type] [description] */ public function render(){} }/** * 工厂类 */class factory { public static function create($type,$isauto){ $ob = null; switch ($type) { case 'js': $ob = new compressjs($isauto); break; case 'css': $ob = new compresscss($isauto); break; default: # code... break; } return $ob; }}
然后是调用处理:
//处理ajax请求if(isset($_post['submit'])){ //是否自动执行批处理 $isauto = $_post['zip'] === 'true' ? true : false; //处理类型 $type = $_post['type']; $c = factory::create($type,$isauto);
//接口方法 $c->request(); $c->render();}else{ echo '请使用静态页访问本程序:点此进入';}
大致的骨架就出来了。具体的填码过程就比较简单了。稍微有点难度的就是执行批处理这个一方法.
是网上提供的方法,以后可能用的上,这里特意贴一下:
public function runbat($name){ if(!file_exists($name) || !$this->isauto){ return; } //转入后台处理 @exec(pclose(popen(start /b . escapeshellcmd($name), r))); }
在前面的index.html中,有一个name=nobuild这个是我人为添加的,这是因为我要过滤这种标识的js文件,这样以后要过滤别的文件,也只要添加这个标识就可以了,不用改php代码。由于是内部使用,没有做表单项来指定工程的路径,默认就是index.html所处的上级目录即为工程目录。这样设计简化了操作,提高了效率。
关于遍历特定的文件,我推荐glob函数,很简洁的方案:
$files = glob($path.'/*.css',glob_nosort);
下面是工程目录结构图:
再来一张运行效果图:
最后是处理结果图:
终于不用写grunt的配置和安装node这个家伙了,再也不担心更新的时候,从svn上拉下来一堆node的东西,是时候和它们说再见了:
好像忘了展示前端代码了:
/** * 选项卡类 * @param {string} id 选项卡的id */function tabs(id){ var node = document.queryselector('#'+id); var selected = node.queryselector('.selected'); this.selected = selected; this.node = node; this.bindevent();}/** * 切换选项卡 * @param {object} event 事件 * @return {[type]} [description] */tabs.prototype.change = function(event){ var element = event.target; if(element.tagname.tolowercase()=='li'){ if(element.classname=='selected'){ return; } }else{ while(element != this.node){ element = element.parentnode; if(element.tagname.tolowercase()=='li'){ break; } } if(element == this.node) return; } this.selected.removeattribute('class'); element.classname = 'selected'; this.selected = element; this.content();}tabs.prototype.content = function(){ var form = document.form1; switch(this.gettabtype()){ case 'js': form.style.display = 'block'; form.children[0].innerhtml = '自动压缩js'; break; case 'css': form.style.display = 'block'; form.children[0].innerhtml = '自动压缩css'; break; default: }}
会前端和后端,就是这么任性。轻轻一点,告别烦恼!造自己的工具,让别人去苦逼吧,so easy!
以上就介绍了自己动手,丰衣足食.,包括了方面的内容,希望对php教程有兴趣的朋友有所帮助。