根据nicEdit 源码组织结构 中所讲的组织方法,和打包注释,其实可以做一个通用的,nicEdit代码风格的模块打包器.
这里用JavaScript实现一个(没有全部完成,有些地方如何做更好,还在考虑中),
对于一个打包器来说,数据的来源我并不考虑,因为这和使用方法有关,你可以从后台程序输出,也可以通过web服务器支持目录列表自动获取,就是因为方法很多,所以这才不是打包器考虑的内容.
/** * nicEdit 风格 模块打包器说明 */ var modulePacker={ /** * 初始化,输入是一个nicEdit 风格的 src 目录结构的对象,最终js文件直接附加原始文件文本 * 例如: { nicCore:{ nicCore.js:'source code', bkLib.js:'source code' }, nicCode:{ nicCode.js:'source code' } } * 生成一个按模块分的依赖关系对象 this.Dep * 生成一个按依赖关系的模块打包次序数组 this.Order */ init:function(src,license){ function find(str){ var s = module.indexOf(str); if (s<0) return false; s=s+str.length; var e = module.indexOf('\n',s); if (e<0) return false; return module.slice(s,e).split(','); } this.Src=src; this.Dep={}; this.Pk={}; this.Remove={}; for (var i in src) { if (typeof src[i]=='string' || typeof src[i][i+'.js']!='string') continue; this.Dep[i]={}; var module = src[i][i+'.js']; var dep=find('@requires:');//分析依赖请求 if (dep) for (var j = 0; j < dep.length; j++) { dep[j]=(dep[j] || "").replace( /^\s+|\s+$/g, "" ); this.Dep[i][dep[j]]=true; } this.Pk[i]={};//[]; dep=find('@order:');//模块文件调入次序 if (dep){ for (var j = 0; j < dep.length; j++) { dep[j]=(dep[j] || "").replace( /^\s+|\s+$/g, "" ); this.Pk[i][dep[j]+'.js']=this.config(src[i][dep[j]+'.js']); } }else{ this.Pk[i][i+'.js']=this.config(module); } } this.sort(); if (license) return this.packer(license); return this; }, /*把 源文件根据配置分段存储与Pk,以便后续处理*/ config:function(module){ function slice(tn,b1,p,max){//把string第2段分成2段 var begin=tn.begin; var end=tn.end; var e1,b2,e2; e1=module.indexOf(begin,b1); if (e1<0 || e1>=max) return false; b2=e1+begin.length; if (b2<0 || b2>=max) return false; e2=module.indexOf(end,b2); if (e2<0 || e2>=max) return false; p[0]=b1;p[1]=e1; p[2]=b2;p[3]=e2; p[4]=e2+end.length; return true; } function toobj(str){ str=str.replace( /^\s+|\s+$/g, "" ); if(str.indexOf(',')==0) str=str.slice(1); return Function('return {'+str+'};')(); } function push(p){ if(0==obj.length){ obj.push(p); return ; } var pos=false; for(var i = 0;i < obj.length; ++i) if (p.begin>obj[i].begin) pos=i+1; if(pos==false) obj=[].concat([p],obj); else obj = obj.slice(0,pos).concat([p],obj.slice(pos)); } var obj=[]; /*config分析*/ var p=[0,0,0,0,0]; if(slice(this.Config.config,0,p,module.length)){ module=module.slice(p[0],p[1])+module.slice(p[2],p[3])+module.slice(p[4]); if(slice(this.Config.remove,0,p,module.length)){ var remove=toobj(module.slice(p[2],p[3])); if (typeof remove=='object') for (var prop in remove){ if (typeof remove[prop] =='object'){ if (this.Remove[prop]==undefined) this.Remove[prop]={}; for(var s in remove[prop]) this.Remove[prop][s]=remove[prop][s]; }else this.Remove[prop]=remove[prop]; } module=module.slice(p[0],p[1])+module.slice(p[4]); } for (var i in this.Config.tag) { if(slice(this.Config.tag[i],0,p,module.length)) push({begin:p[1],end:p[4],name:i}); } } var pk=[]; var pos=0; obj.push({begin:module.length,end:module.length}); for (var i = 0; i < obj.length;i++) { pk.push({src:module.slice(pos,obj[i].begin),name:obj[i].name||''}); pos=obj[i].end; } return pk; }, /** * 根据依赖关系生成 module 打包次序 */ sort:function(){ function find(str){ for (var i=0;i<order.length;i++) { if (order[i]==str) return i; } return null; } var order=this.Order=[]; var pos; for (var i in this.Dep) { pos=find(i); if(pos!=null) { for (var j in this.Dep[i]) { if (typeof this.Dep[i][j] !='boolean') continue; var pos2=find(j); if (pos2<pos) continue; var str=order[pos]; order[pos]=order[pos2]; order[pos2]=str; } continue; } for (var j in this.Dep[i]) { if (typeof this.Dep[i][j] !='boolean') continue; pos=find(j); if(pos!=null) continue; order.push(j); } order.push(i); } return; }, /** * 多粒度获取依赖关系 this.Dep 的信息 * this.Dep 整个依赖关系 * this.Dep[module] 某个 module 的依赖关系 * this.Dep[module][dep] 检查某个 module 是否依赖于 dep */ getdep:function(module,dep){ if(undefined==module && undefined==dep) return this.Dep; if(dep && this.Dep[module]) return this.Dep[module][dep]; return this.Dep[module]; }, /** * 多粒度获取 this.Remove 的信息 */ getremove:function(key){ if (undefined==key) return this.Remove; return this.Remove[key]; }, /** * 生成打包前的数据 * modules:[] */ prePacker:function(modules){ var pack={}; for (var i =0 ;i<modules.length;i++) { pack[modules[i]]=[]; for (var j in this.Dep[modules[i]]) { pack[j]=[]; } } var prepack=this.Data.prePack={}; for (var i = 0; i < this.Order.length; i++) { var m=this.Order[i]; if(pack[m]){ for(var j in this.Pk[m]) pack[m]=pack[m].concat(this.Pk[m][j]); prepack[m]=pack[m]; } } return this; }, /*给不同的需求留下的自定义处理数据处理对象*/ Data:{}, nicEdit:function(pre,iconsPath){ if(!pre) pre=''; if(iconsPath) iconsPath='"'+iconsPath+'"'; else iconsPath='nicEditIconsPath'; var prePack=this.Data.prePack; var pack=[]; if(typeof pre=='string') pack.push(pre); var pos=0; var iconList=[]; /*偷懒的图片全部打包*/ for (var i in this.Remove.iconFiles) iconList.push('"'+i+'":'+(++pos)); iconList = '{'+iconList.join()+'}'; for(var i in prePack) for(var j=0;j<prePack[i].length;j++){ pack.push(prePack[i][j].src); if(''==prePack[i][j].name) continue; switch(prePack[i][j].name){ case 'iconsPath': pack.push(iconsPath); break; case 'iconList': pack.push(iconList); break; } } this.Data.pack=pack.join(''); }, /** * 配置语法 */ Config:{ /*配置文件*/ configfile:'nicConfig.js', /*配置开始和结束*/ config:{ begin:'/* START CONFIG */', end:'/* END CONFIG */'}, /*需要删除的代码*/ remove:{ begin:'/* NICEDIT_REMOVE_START */', end:'/* NICEDIT_REMOVE_END */'}, tag:{/*需要替换的配置*/ /*合并图标文件的URL路径*/ iconsPath:{ begin:'/* NICEDIT_ICONSPATH_START */', end:'/* NICEDIT_ICONSPATH_END */'}, /*图标和标号列表*/ iconList:{ begin:'/* NICEDIT_ICONLIST_START */', end:'/* NICEDIT_ICONLIST_END */'} } } }