UNPKG

rrestjs

Version:

HIgh performance node.js ROA & RESTFUL web framework.

197 lines (190 loc) 8.98 kB
/* *autoStatic.js 文件是自动响应静态文件模块 * *主要作用是会根据是否开启parse整合css和js文件做出不同响应 * *如果未开启 parse 功能,则根据get请求路径自动去 staticFolder 响应静态文件 * *如果开启parse功能,并使用parse功能,请求的是js文件,则会利用ugliyf压缩合并以后响应 * *如果开启parse功能,并使用parse功能,请求的是css文件,则会利用less编译,然后压缩合并响应 * *exports 根据情况输出响应函数 */ var AsyncProxy = require('./modules/AsyncProxy'), RestUtils = require('./RestUtils'), fs = require('fs'), path = require('path'), less = require('less'), msg = require('./msg/msg'), outerror = require('./Outerror'), compressCss = require('./modules/compressCss'),//压缩CSS方法 uglifyjs = function(str){//使用uglify-js压缩,生成压缩后的js文件 var jsp = require("uglify-js").parser, pro = require("uglify-js").uglify, orig_code = str, ast = jsp.parse(orig_code); // parse code and get the initial AST ast = pro.ast_mangle(ast); // get a new AST with mangled names ast = pro.ast_squeeze(ast); // get an AST with compression optimizations var final_code = pro.gen_code(ast); // compressed code here return final_code+';'; }, normalize_query = RestUtils.normalize_query, autoStatic = _restConfig.autoStatic, staticFolder = _restConfig.baseDir + _restConfig.staticFolder, staticParse = _restConfig.staticParse, staticParseName = _restConfig.staticParseName, staticParseCacheTime = _restConfig.staticParseCacheTime, staticParseMaxNumber = _restConfig.staticParseMaxNumber, staticParseCacheFolder = _restConfig.baseDir+_restConfig.staticParseCacheFolder, reg = new RegExp("^"+autoStatic+"/"), staticObj = { parseStaticCache:{}, autoStaticFn:function(req, res){ var filepath = staticFolder+'/'+req.path.slice(1).join('/'), //拼装静态文件绝对地址 lessType = staticObj.getLessType(filepath);//根据绝对地址获取后缀名 if(lessType === 'less'){//如果是css文件则去生成less.前缀的css文件名 staticObj.genless(filepath, function(err, csspath){//生成编译后的less的css文件,返回err和csspath两个参数 if(err) return RestUtils.errorRes(res, err.msg, err.scode); res.sendfile(csspath); }); } else res.sendfile(filepath); }, getMimeType:function(path){//根据路径地址获取后缀名 var po = path.lastIndexOf('.')+1; return path.slice(po).toLowerCase(); }, getLessType:function(path){ if(/.less$/.test(path) || /.less.css$/.test(path)) return 'less';//增加.less文件的判断 //预留接口判断其他例如less的样式表 return false; }, genless:function(filepath, cb){//生成编译后的less文件,即是在原来css文件加前缀less. var cb = cb || function(){}, fileary = filepath.split('/'), filedir = fileary.slice(0, fileary.length-1).join('/'); fs.readFile(filepath, {encoding :'utf-8'},function(err, data){//根据请求读取目录 parser = new(less.Parser)({ paths: [filedir] // Specify search paths for @import directives }); if(err) return cb({msg:msg.resmsg.notFound, scode:404});//如果文件不存在,则cb(err) parser.parse(data, function (err, css) {//开始编译less文件 if(err) return cb({msg:msg.resmsg.lessError, scode:500});//如果编译出错,则cb(err) var css = css.toCSS(), po = filepath.lastIndexOf('/')+1, path = filepath.slice(po), lesspath = filepath.replace(path, 'compile.'+path);//根据元有文件路径拼装成带less.为前缀的less css文件 fs.writeFile(lesspath, css, {encoding :'utf-8'}, function(err){//根据 lesspath 生成编译好的css文件 if(err) return cb({msg:msg.resmsg.lessWriteError, scode:500});//如果写入出错 cb(null, lesspath);//执行回调 传参 lesspath }) }); }) }, parse:function(type, filePathArray, md5str, callback){ var as = AsyncProxy(),//实例化异步代理库 AsyncProxy ary = [],//存放异步方法的数组 fileary = [],//存放buffer.toString()的css或js文档 wrong = 0,//错误记录,大于0说明有错误 genlessnum = filePathArray.length, //待生成less的文件数 gencount = 0, //已经生成的less文件数 readfile = function(value, index, type){ var value = value.replace(autoStatic, ''),//静态文件路径去掉前缀 staticPath = staticFolder+value,//文件的绝对路径 recfn = function(rec){ fs.readFile(staticPath, {encoding :'utf-8'}, function(err, data){ if(err) wrong++; else{//坑爹的uglify,末尾不加';'号而且有错还得用户加try,我去提意见 try{ fileary[index] = zipFn(data); } catch(e){ fileary[index] = data; } } rec();//异步库方法,表示此异步正常返回 }); }; if(type === 'less'){ staticObj.genless(staticPath, function(err, lesspath){ if(err) return callback(err.msg); staticPath = lesspath;//如果是css,则将 staticPath 修改为 lesspath if(++gencount >= genlessnum){ //如果所有的css都生成完成 process.nextTick(function(){ as.ap.apply(as, ary); //开始合并css }) } }); } return recfn;//返回 recfn 函数作为异步函数 }, allComplete = function(){//当所有异步的 recfn 都执行完毕后执行 if(wrong>0) return callback(msg.resmsg.parseNotExist);//如果有错误,则部分文件不存在 fs.writeFile(staticParseCacheFolder+'/'+md5str, fileary.join(''), {encoding :'utf-8'}, function(err){ if(err) return callback(msg.resmsg.parseCreateCacheError);//如果生成缓存文件失败 callback(null, staticParseCacheFolder+'/'+md5str);//生成成功,将缓存路径返回给callback as = null;//垃圾回收 }) }; if(type === 'css' || type==='less'){ var zipFn = compressCss;//css 压缩模块 } else if(type === 'js'){ var zipFn = uglifyjs;//js 压缩模块 } else return callback(msg.resmsg.parseTypeError); filePathArray.forEach(function(value, index){//为每一个路径添加fs访问路径 var vtype = staticObj.getMimeType(value); if(!reg.test(value)) return wrong++;//如果访问路径不正确 if(vtype !=='css' && vtype !== 'js' && vtype !== 'less') return wrong++;//如果后面的文件不是css也不是js ary.push(readfile(value, index, vtype)); }); if(wrong>0) return callback(msg.resmsg.parseError); ary.push(allComplete); if(type !== 'less') as.ap.apply(as, ary); return true; }, createCache:function(type, filePathArray, md5str, res){//生成缓存的方法 var callback = function(errmsg, filepath){//生成缓存以后的回调,如果有错误也会执行 if(errmsg) return RestUtils.errorRes(res, errmsg);//如果生成缓存失败,则输出错误 staticObj.parseStaticCache[md5str] = {//如果正常返回,则创建和更新缓存 timestamp:Date.now(), filepath:filepath, } res.sendfile(filepath); }; staticObj.parse(type, filePathArray, md5str, callback);//根据生成缓存文件函数返回的路径输出缓存 }, }; if(!staticParse){//如果没有开启静态文件整合功能则直接自动输出静态文件 module.exports = staticObj.autoStaticFn; } else{//开启静态文件整合压缩 module.exports = function(req, res){ var parsePath = req.getparam[staticParseName]; if(typeof parsePath === 'undefined' || !parsePath) return staticObj.autoStaticFn(req, res); //开启功能但未使用此方法,则直接自动输出,例如请求是图片或者txt var ary = parsePath.split('|'), type = staticObj.getMimeType(ary[0]), md5str = RestUtils.md5(parsePath)+'.'+type,//生成md5字符串 pobj = staticObj.parseStaticCache[md5str]; ary.map(function(v){ return normalize_query(v); }); if(ary.length>staticParseMaxNumber) return RestUtils.errorRes(res, msg.resmsg.parseTooLong);//如果超长,则报错 if(pobj && (Date.now() - staticParseCacheTime < pobj.timestamp)){//如果有缓存,并且缓存未超时,正常输出缓存文件 var p = pobj.filepath; path.exists(p, function(exist){ if(exist) { res.sendfile(p, function(err){ if(err) outerror(msg.parse(msg.errmsg.parseCacheNotFound+p, err)); }); } else staticObj.createCache(type, ary, md5str, res);//如果读取缓存失败,则去生成缓存 }); } else{ staticObj.createCache(type, ary, md5str, res);//去生成缓存 } } }