flex-combo
Advanced tools
Comparing version 0.7.9 to 0.8.0
507
api.js
@@ -5,2 +5,3 @@ var urlLib = require("url"); | ||
var mime = require("mime"); | ||
var async = require("async"); | ||
var isUtf8 = require("is-utf8"); | ||
@@ -95,4 +96,7 @@ var iconv = require("iconv-lite"); | ||
/* 以配置文件指定编码输出encoded buffer */ | ||
function convert(buff, _url) { | ||
buff = new Buffer(buff); | ||
function convert(content, _url) { | ||
var buff = content; | ||
if (typeof content != "object" || !Buffer.isBuffer(content)) { | ||
buff = new Buffer(content); | ||
} | ||
@@ -116,18 +120,58 @@ var charset = isUtf8(buff) ? "utf-8" : "gbk"; | ||
/* 缓存文件 */ | ||
function cacheFile(_url, buff) { | ||
var absPath = pathLib.join(this.cacheDir, utilLib.MD5(pathLib.join(this.HOST, _url))); | ||
if (!/[<>\*\?]+/g.test(absPath)) { | ||
fsLib.writeFile(absPath, buff); | ||
} | ||
} | ||
/* 构建Request头 */ | ||
function buildRequestOption(url) { | ||
var protocol = (this.req.protocol || "http") + ':'; | ||
var H = this.req.headers.host.split(':'); | ||
var reqPort = H[1] || (protocol == "https:" ? 443 : 80); | ||
var reqHostName = H[0]; | ||
var reqHostIP; | ||
if (this.param.hostIp) { | ||
reqHostIP = this.param.hostIp; | ||
} | ||
else if (this.param.hosts && this.param.hosts[reqHostName]) { | ||
reqHostIP = this.param.hosts[reqHostName]; | ||
} | ||
else { | ||
reqHostIP = reqHostName; | ||
} | ||
var requestOption = { | ||
protocol: protocol, | ||
host: reqHostIP, | ||
port: reqPort, | ||
path: url, | ||
method: this.req.method || "GET", | ||
headers: {host: reqHostName} | ||
}; | ||
requestOption.headers = utilLib.merge(true, this.param.headers, requestOption.headers); | ||
if (reqHostIP == reqHostName) { | ||
return false; | ||
} | ||
return requestOption; | ||
} | ||
/* LESS动态编译 */ | ||
function lessCompiler(xcssfile) { | ||
var less = require("./engines/less"); | ||
return less.call(this, xcssfile); | ||
function lessCompiler(xcssfile, url, param, cb) { | ||
return require("./engines/less")(xcssfile, url, param, cb); | ||
} | ||
/* SASS动态编译 */ | ||
function sassCompiler(xcssfile) { | ||
var sass = require("./engines/sass"); | ||
return sass.call(this, xcssfile); | ||
function sassCompiler(xcssfile, url, param, cb) { | ||
return require("./engines/sass")(xcssfile, url, param, cb); | ||
} | ||
/* TPL动态编译 */ | ||
function tplCompiler(htmlfile, url) { | ||
var jstpl = require("./engines/jstpl"); | ||
return jstpl.call(this, htmlfile, url); | ||
function jplCompiler(htmlfile, url, param, cb) { | ||
return require("./engines/jpl")(htmlfile, url, param, cb); | ||
} | ||
@@ -139,12 +183,20 @@ | ||
function FlexCombo(param, dir) { | ||
var moduleName = pathLib.basename(__dirname); | ||
this.HOST = null; | ||
this.URL = null; | ||
this.req = null; | ||
this.res = null; | ||
this.cacheDir = null; | ||
this.param = utilLib.clone(require("./lib/param")); | ||
this.result = {}; | ||
var confFile = ''; | ||
if (dir && (/^\//.test(dir) || /^\w{1}:[\\|\/].*$/.test(dir))) { | ||
this.confFile = pathLib.join(dir, "config.json"); | ||
confFile = pathLib.join(dir, "config.json"); | ||
} | ||
else { | ||
this.confFile = pathLib.join(process.cwd(), dir || ('.' + moduleName), moduleName + ".json"); | ||
var moduleName = pathLib.basename(__dirname); | ||
confFile = pathLib.join(process.cwd(), dir || ('.' + moduleName), moduleName + ".json"); | ||
} | ||
var confDir = pathLib.dirname(this.confFile); | ||
var confDir = pathLib.dirname(confFile); | ||
if (!fsLib.existsSync(confDir)) { | ||
@@ -154,14 +206,17 @@ utilLib.mkdirPSync(confDir); | ||
if (fsLib.existsSync(this.confFile)) { | ||
this.param = {}; | ||
if (!fsLib.existsSync(confFile)) { | ||
fsLib.writeFileSync(confFile, JSON.stringify(this.param, null, 2), {encoding: "utf-8"}); | ||
} | ||
else { | ||
this.param = require("./lib/param"); | ||
fsLib.writeFileSync(this.confFile, JSON.stringify(this.param, null, 2), {encoding: "utf-8"}); | ||
var confJSON = {}; | ||
try { | ||
confJSON = JSON.parse(fsLib.readFileSync(confFile)); | ||
} | ||
catch (e) { | ||
Log.error("Params Error!"); | ||
confJSON = {}; | ||
} | ||
this.param = utilLib.merge(true, this.param, confJSON, param||{}); | ||
var conf = JSON.parse(fsLib.readFileSync(this.confFile)); | ||
this.param = utilLib.merge(true, this.param, conf, param || {}); | ||
this.cacheDir = pathLib.join(confDir, "cache"); | ||
this.cacheDir = pathLib.join(confDir, "../.cache"); | ||
if (!fsLib.existsSync(this.cacheDir)) { | ||
@@ -173,5 +228,2 @@ utilLib.mkdirPSync(this.cacheDir); | ||
constructor: FlexCombo, | ||
config: function (param) { | ||
this.param = utilLib.merge(true, this.param, param || {}); | ||
}, | ||
parser: function (_url) { | ||
@@ -205,5 +257,3 @@ var url = urlLib.parse(_url).path.replace(/\\|\/{1,}/g, '/'); | ||
rule: "\\.less\\.css$", | ||
func: function (xcssfile) { | ||
return lessCompiler(xcssfile.replace(/\.css$/, '')); | ||
} | ||
func: lessCompiler | ||
}, | ||
@@ -216,20 +266,15 @@ { | ||
rule: "\\.scss\\.css$", | ||
func: function (xcssfile) { | ||
return sassCompiler(xcssfile.replace(/\.css$/, '')); | ||
} | ||
func: sassCompiler | ||
}, | ||
{ | ||
rule: "\\.jpl$|\\.jpl\\.js$", | ||
func: function (htmlfile, url) { | ||
return tplCompiler(htmlfile, url); | ||
} | ||
rule: "\\.jpl$", | ||
func: jplCompiler | ||
}, | ||
{ | ||
rule: "\\.html\\.js$", | ||
func: function (htmlfile, url) { | ||
var content = tplCompiler(htmlfile, url); | ||
if (content) { | ||
func: function (htmlfile, url, param, cb) { | ||
jplCompiler(htmlfile, url, param, function(e, content) { | ||
fsLib.writeFile(htmlfile, convert.call(this, content)); | ||
} | ||
return content; | ||
cb(e, content); | ||
}); | ||
} | ||
@@ -246,256 +291,180 @@ } | ||
}, | ||
handle: function (req, res, next) { | ||
var HOST = (req.protocol||"http") + "://" + (req.hostname||req.host||req.headers.host); | ||
init: function(req, res) { | ||
this.req = req; | ||
this.res = res; | ||
this.HOST = (req.protocol||"http") + "://" + (req.hostname||req.host||req.headers.host); | ||
// 不用.pathname的原因是由于??combo形式的url,parse方法解析有问题 | ||
var URL = urlLib.parse(req.url).path.replace(/([^\?])\?[^\?].+$/, "$1"); | ||
this.URL = urlLib.parse(req.url).path.replace(/([^\?])\?[^\?].+$/, "$1"); | ||
var suffix = ["\\.phtml$","\\.js$","\\.css$","\\.png$","\\.gif$","\\.jpg$","\\.jpeg$","\\.ico$","\\.swf$","\\.xml$","\\.less$","\\.scss$","\\.svg$","\\.ttf$","\\.eot$","\\.woff$","\\.mp3$"]; | ||
if (this.param.supportedFile) { | ||
suffix = this.param.supportedFile.split('|'); | ||
var suffix = ["\\.jpl$", "\\.phtml$","\\.js$","\\.css$","\\.png$","\\.gif$","\\.jpg$","\\.jpeg$","\\.ico$","\\.swf$","\\.xml$","\\.less$","\\.scss$","\\.svg$","\\.ttf$","\\.eot$","\\.woff$","\\.mp3$"]; | ||
var supportedFile = this.param.supportedFile; | ||
if (supportedFile) { | ||
suffix = supportedFile.split('|'); | ||
} | ||
var engines = this.param.engine || {}; | ||
for (var k in engines) { | ||
suffix.push(k); | ||
if (this.URL.match(new RegExp(k))) { | ||
this.param.urls[pathLib.dirname(this.URL)] = pathLib.dirname(engines[k]); | ||
} | ||
this.addEngine(k, require(pathLib.join(process.cwd(), engines[k]))); | ||
} | ||
if (this.param.filter) { | ||
req.url = helper.filteredUrl(URL, this.param.filter, this.param.debug); | ||
return this.URL.match(new RegExp(suffix.join('|'))) ? true : false; | ||
}, | ||
header: function() { | ||
var U4M = this.URL; | ||
if (U4M.match(/\.less$|\.scss$|\.sass$/)) { | ||
U4M += ".css"; | ||
} | ||
else if (U4M.match(/\.jpl$/)) { | ||
U4M += ".js"; | ||
} | ||
this.res.writeHead(200, { | ||
"Access-Control-Allow-Origin": '*', | ||
"Content-Type": mime.lookup(U4M) + (isBinFile(U4M) ? '' : ";charset=" + this.param.charset), | ||
"X-MiddleWare": "flex-combo" | ||
}); | ||
}, | ||
engineHandler: function(_url, next) { | ||
var absPath = helper.getRealPath(_url, this.param.filter, this.param.urls, this.param.debug); | ||
var engines = this.param.engine; | ||
if (engines) { | ||
for (var k in engines) { | ||
suffix.push(k); | ||
if (URL.match(new RegExp(k))) { | ||
this.param.urls[pathLib.dirname(URL)] = pathLib.dirname(engines[k]); | ||
} | ||
this.addEngine(k, require(pathLib.join(process.cwd(), engines[k]))); | ||
var matchedIndex = -1; | ||
for (var i = this.engines.length - 1, matched = null, matchedNum = -1; i >= 0; i--) { | ||
matched = _url.match(new RegExp(this.engines[i].rule)); | ||
if (matched && matched[0].length > matchedNum && typeof this.engines[i].func == "function") { | ||
matchedNum = matched[0].length; | ||
matchedIndex = i; | ||
} | ||
} | ||
if (URL.match(new RegExp(suffix.join('|')))) { | ||
var U4M = URL; | ||
if (URL.match(/\.less$|\.scss$|\.sass$/)) { | ||
U4M += ".css"; | ||
} | ||
else if (URL.match(/\.jpl$/)) { | ||
U4M += ".js"; | ||
} | ||
res.writeHead(200, { | ||
"Access-Control-Allow-Origin": '*', | ||
"Content-Type": mime.lookup(U4M) + (isBinFile(URL) ? '' : ";charset=" + this.param.charset), | ||
"X-MiddleWare": "flex-combo" | ||
if (!this.result[_url] && matchedIndex >= 0 && this.engines[matchedIndex]) { | ||
var engine = this.engines[matchedIndex]; | ||
var self = this; | ||
engine.func(absPath, _url, this.param, function(e, result, realPath) { | ||
self.result[_url] = convert.call(self, result, _url); | ||
self.param.debug && Log.engine(_url, realPath||absPath); | ||
next(); | ||
}); | ||
} | ||
else { | ||
next(); | ||
} | ||
}, | ||
staticHandler: function(_url, next) { | ||
var absPath = helper.getRealPath(_url, this.param.filter, this.param.urls, false); | ||
/* 获取待处理文件列表 */ | ||
var files = this.parser(URL); | ||
var FLen = files.length; | ||
var Q = new Array(FLen); | ||
Log.request(HOST, files); | ||
if (!this.result[_url] && fsLib.existsSync(absPath)) { | ||
var buff = fsLib.readFileSync(absPath); | ||
/* 响应输出 */ | ||
function sendData(F) { | ||
var flag = true; | ||
for (var i = 0, len = Q.length; i < len; i++) { | ||
flag &= Boolean(Q[i]); | ||
} | ||
if (flag) { | ||
res.end(utilLib.joinBuffer(Q)); | ||
!F && Log.response(HOST+req.url); | ||
} | ||
if (!isBinFile(absPath)) { | ||
buff = convert.call(this, buff, _url); | ||
} | ||
/* 构建HTTP(s)请求头 */ | ||
function buildRequestOption(url) { | ||
var protocol = (req.protocol || "http") + ':'; | ||
this.result[_url] = buff; | ||
this.param.debug && Log.local(_url, absPath); | ||
} | ||
var H = req.headers.host.split(':'); | ||
var reqPort = H[1] || (protocol == "https:" ? 443 : 80); | ||
next(); | ||
}, | ||
cacheHandler: function(_url, next) { | ||
var absPath = pathLib.join(this.cacheDir, utilLib.MD5(pathLib.join(this.HOST, _url))); | ||
var reqHostName = H[0]; | ||
var reqHostIP; | ||
if (this.param.hostIp) { | ||
reqHostIP = this.param.hostIp; | ||
} | ||
else if (this.param.hosts && this.param.hosts[reqHostName]) { | ||
reqHostIP = this.param.hosts[reqHostName]; | ||
} | ||
else { | ||
reqHostIP = reqHostName; | ||
} | ||
if (!this.result[_url] && fsLib.existsSync(absPath)) { | ||
this.result[_url] = fsLib.readFileSync(absPath); | ||
this.param.debug && Log.cache(_url, absPath); | ||
} | ||
var requestOption = { | ||
protocol: protocol, | ||
host: reqHostIP, | ||
port: reqPort, | ||
path: url, | ||
method: req.method || "GET", | ||
headers: {host: reqHostName} | ||
}; | ||
requestOption.headers = utilLib.merge(true, this.param.headers, requestOption.headers); | ||
if (reqHostIP == reqHostName) { | ||
return false; | ||
} | ||
return requestOption; | ||
next(); | ||
}, | ||
fetchHandler: function(_url, next) { | ||
if (!this.result[_url]) { | ||
var self = this; | ||
var requestOption = buildRequestOption.call(this, _url); | ||
if (requestOption) { | ||
ALProtocol[requestOption.protocol] | ||
.request(requestOption, function (nsres) { | ||
var buffer = []; | ||
nsres | ||
.on("error", function () { | ||
self.result[_url] = new Buffer("/* " + _url + " Proxy ERROR! */"); | ||
Log.error(_url); | ||
next(); | ||
}) | ||
.on("data", function (chunk) { | ||
buffer.push(chunk); | ||
}) | ||
.on("end", function () { | ||
var buff = utilLib.joinBuffer(buffer); | ||
cacheFile.call(self, _url, buff); | ||
self.result[_url] = buff; | ||
Log.remote(_url, requestOption); | ||
next(); | ||
}); | ||
}) | ||
.on("error", function () { | ||
self.result[_url] = new Buffer("/* " + _url + " Req ERROR! */"); | ||
Log.error(_url); | ||
next(); | ||
}) | ||
.end(); | ||
} | ||
/* 从本地读取文件(会尝试进行动态编译) */ | ||
function readFromLocal(_url) { | ||
_url = helper.filteredUrl(_url, this.param.filter, this.param.debug); | ||
// urls中key对应的实际目录 | ||
var repPath = ''; | ||
var revPath = _url; | ||
var map = this.param.urls; | ||
var longestMatchNum = 0; | ||
for (k in map) { | ||
if (_url.indexOf(k) == 0 && longestMatchNum < k.length) { | ||
longestMatchNum = k.length; | ||
repPath = map[k]; | ||
revPath = _url.slice(longestMatchNum); | ||
} | ||
} | ||
var absPath = ''; | ||
if (repPath.indexOf('/') == 0 || /^\w{1}:\\.*$/.test(repPath)) { | ||
absPath = pathLib.normalize(pathLib.join(repPath, revPath)); | ||
} | ||
else { | ||
absPath = pathLib.normalize(pathLib.join(process.cwd(), repPath, revPath)); | ||
} | ||
// 尝试使用注册的引擎动态编译 | ||
var matchedIndex = -1; | ||
for (var i = this.engines.length - 1, matched = null, matchedNum = -1; i >= 0; i--) { | ||
matched = _url.match(new RegExp(this.engines[i].rule)); | ||
if (matched && matched[0].length > matchedNum && typeof this.engines[i].func == "function") { | ||
matchedNum = matched[0].length; | ||
matchedIndex = i; | ||
} | ||
} | ||
var buff = null; | ||
if (matchedIndex >= 0 && this.engines[matchedIndex]) { | ||
var engine = this.engines[matchedIndex]; | ||
buff = engine.func.call(this, absPath, _url); | ||
if (buff) { | ||
var suffix = engine.rule.replace(/^\\.|\$/g, '').split("\\."); | ||
this.param.debug && Log.engine(_url, absPath.replace(new RegExp(engine.rule), '.' + (suffix[0] || "unknown"))); | ||
} | ||
else { | ||
this.param.debug && Log.warn(absPath, "Engine Fail! TRY TO FIND Local"); | ||
} | ||
} | ||
// 尝试读取静态文件 | ||
if (!buff) { | ||
if (fsLib.existsSync(absPath)) { | ||
Log.local(_url, absPath); | ||
buff = fsLib.readFileSync(absPath); | ||
} | ||
else { | ||
this.param.debug && Log.warn(absPath, "Not Found! TRY TO FIND Cache"); | ||
} | ||
} | ||
if (buff) { | ||
if (isBinFile(absPath)) { | ||
return (typeof buff == "object" && Buffer.isBuffer(buff)) ? buff : new Buffer(buff); | ||
} | ||
return convert.call(this, buff, _url); | ||
} | ||
return null; | ||
else { | ||
self.result[_url] = new Buffer("/* " + _url + " Loop! */"); | ||
Log.error(_url); | ||
next(); | ||
} | ||
} | ||
else { | ||
next(); | ||
} | ||
}, | ||
handle: function (req, res, next) { | ||
if (this.init(req, res)) { | ||
this.header(); | ||
/* 从缓存读取文件 */ | ||
function readFromCache(_url) { | ||
var absPath = pathLib.join(this.cacheDir, utilLib.MD5(pathLib.join(HOST, _url))); | ||
if (fsLib.existsSync(absPath)) { | ||
var buff = fsLib.readFileSync(absPath); | ||
this.param.debug && Log.cache(_url, absPath); | ||
if (isBinFile(absPath)) { | ||
return buff; | ||
} | ||
return convert.call(this, buff, _url); | ||
} | ||
else { | ||
this.param.debug && Log.warn(absPath, "Not Found! TRY TO FIND Remote"); | ||
} | ||
var files = this.parser(this.URL); | ||
var FLen = files.length; | ||
var self = this; | ||
var Q = []; | ||
return null; | ||
} | ||
Log.request(this.HOST, files); | ||
/* 缓存文件 */ | ||
function cacheFile(_url, buff) { | ||
var absPath = pathLib.join(this.cacheDir, utilLib.MD5(pathLib.join(HOST, _url))); | ||
if (!/[<>\*\?]+/g.test(absPath)) { | ||
fsLib.writeFile(absPath, buff); | ||
} | ||
for (var i = 0; i < FLen; i++) { | ||
Q.push( | ||
(function(i){ | ||
return function(cb) { | ||
self.engineHandler(files[i], cb); | ||
} | ||
})(i), | ||
(function(i){ | ||
return function(cb) { | ||
self.staticHandler(files[i], cb); | ||
} | ||
})(i), | ||
(function(i){ | ||
return function(cb) { | ||
self.cacheHandler(files[i], cb); | ||
} | ||
})(i), | ||
(function(i){ | ||
return function(cb) { | ||
self.fetchHandler(files[i], cb); | ||
} | ||
})(i) | ||
); | ||
} | ||
/* 从线上获取资源 */ | ||
function fetchOnline(file, i) { | ||
var self = this; | ||
var requestOption = buildRequestOption.call(self, file); | ||
if (requestOption) { | ||
ALProtocol[requestOption.protocol] | ||
.request(requestOption, function (nsres) { | ||
var buffer = []; | ||
nsres | ||
.on("error", function () { | ||
Q[i] = convert.call(self, new Buffer("/* " + file + " Proxy ERROR! */")); | ||
Log.error(file); | ||
sendData(); | ||
}) | ||
.on("data", function (chunk) { | ||
buffer.push(chunk); | ||
}) | ||
.on("end", function () { | ||
var content = utilLib.joinBuffer(buffer); | ||
Q[i] = content; | ||
cacheFile.call(self, file, content); | ||
Log.remote(file, requestOption); | ||
sendData(); | ||
}); | ||
}) | ||
.on("error", function () { | ||
Q[i] = convert.call(self, new Buffer("/* " + file + " Req ERROR! */")); | ||
Log.error(file); | ||
sendData(); | ||
}) | ||
.end(); | ||
async.series(Q, function() { | ||
var buff; | ||
for (var i = 0; i < FLen; i++) { | ||
buff = self.result[files[i]]; | ||
res.write(buff ? buff : new Buffer("/* "+files[i]+" Empty!*/")); | ||
} | ||
else { | ||
Q[i] = convert.call(self, new Buffer("/* " + file + " Loop! */")); | ||
Log.error(file); | ||
sendData(); | ||
} | ||
} | ||
Log.response(self.HOST + req.url); | ||
res.end(); | ||
}); | ||
var F = false; | ||
for (var i = 0; i < FLen; i++) { | ||
var file = files[i]; | ||
// 读本地最新文件内容 | ||
var localContent = readFromLocal.call(this, file); | ||
if (localContent) { | ||
Q[i] = localContent; | ||
continue; | ||
} | ||
// 读本地缓存内容 | ||
var cacheContent = readFromCache.call(this, file); | ||
if (cacheContent) { | ||
Q[i] = cacheContent; | ||
continue; | ||
} | ||
F = true; | ||
// 读线上内容并缓存 | ||
fetchOnline.call(this, file, i); | ||
} | ||
sendData(F); | ||
} | ||
@@ -502,0 +471,0 @@ else { |
var helper = require("../lib/util"); | ||
var pathLib = require("path"); | ||
var less = require("less"); | ||
var utilLib = require("mace")(module); | ||
function Loader() { | ||
this.TREE = {}; | ||
this.vars = []; | ||
this.func = []; | ||
} | ||
Loader.prototype = { | ||
constructor: Loader, | ||
check: function (son, parent) { | ||
if (this.TREE[parent] && this.TREE[parent] == -1) { | ||
return true; | ||
module.exports = function (xcssfile, url, param, cb) { | ||
xcssfile = xcssfile.replace(/\.css$/, ''); | ||
var lesstext = helper.getUnicode(xcssfile); | ||
less.render(lesstext, { | ||
paths: [], | ||
compress: false, | ||
filename: xcssfile | ||
}, function(e, result) { | ||
if (!e) { | ||
cb(e, result.css, xcssfile); | ||
} | ||
else if (son == parent) { | ||
return false; | ||
} | ||
else { | ||
return this.check(son, this.TREE[parent]); | ||
console.log(e); | ||
cb(e, lesstext, xcssfile); | ||
} | ||
}, | ||
fetch: function (xcssfile, parent) { | ||
if (parent) { | ||
this.TREE[xcssfile] = parent; | ||
} | ||
else { | ||
this.TREE[xcssfile] = -1; | ||
} | ||
var self = this; | ||
var lesstxt = helper.getUnicode(xcssfile); | ||
lesstxt.replace(/^\s{0,}@(.+)\:|^\s{0,}\.(.+)\s{0,}\(.{0,}\)\s{0,}\{[\s\S]*?\}/g, function ($0, $1, $2) { | ||
if ($1) { | ||
if (self.vars.indexOf($1) == -1) { | ||
self.vars.push($1); | ||
} | ||
else { | ||
utilLib.warn("variable %s is defined!", $1); | ||
} | ||
} | ||
if ($2) { | ||
if (self.func.indexOf($2) == -1) { | ||
self.func.push($2); | ||
} | ||
else { | ||
utilLib.warn("function %s is defined!", $2); | ||
} | ||
} | ||
}); | ||
lesstxt = lesstxt.replace(/@import\s+(["'])(\S+?)\1;?/mg, function (t, f, relpath) { | ||
var filepath = pathLib.join(pathLib.dirname(xcssfile), relpath); | ||
if (!/\.[a-z]{1,}$/i.test(filepath)) { | ||
filepath += ".less"; | ||
} | ||
if (self.check(filepath, xcssfile)) { | ||
return self.fetch(filepath, xcssfile); | ||
} | ||
else { | ||
return "/* Overflow: " + filepath + " */"; | ||
} | ||
}); | ||
return lesstxt; | ||
} | ||
}; | ||
module.exports = function (xcssfile) { | ||
var loader = new Loader(); | ||
var lesstxt = loader.fetch(xcssfile); | ||
if (lesstxt) { | ||
return new (less.Parser)({processImports: false}) | ||
.parse(lesstxt, function (e, tree) { | ||
if (e) { | ||
return "/* [" + xcssfile + "] LESS COMPILE ERROR! */"; | ||
} | ||
return tree.toCSS(); | ||
}) + "\n"; | ||
} | ||
return null; | ||
}); | ||
}; |
@@ -5,6 +5,8 @@ var helper = require("../lib/util"); | ||
var sass = require("node-sass"); | ||
module.exports = function(xcssfile) { | ||
module.exports = function(xcssfile, url, param, cb) { | ||
xcssfile = xcssfile.replace(/\.css$/, ''); | ||
var sasstxt = helper.getUnicode(xcssfile); | ||
var result = null; | ||
if (sasstxt) { | ||
return sass.renderSync({ | ||
result = sass.renderSync({ | ||
data: sasstxt | ||
@@ -14,9 +16,9 @@ }) + "\n"; | ||
return null; | ||
cb(false, result, xcssfile); | ||
}; | ||
} | ||
catch(e) { | ||
module.exports = function(xcssfile) { | ||
return "/* node-sass isn't installed\n *"+xcssfile+" ERROR!\n */"; | ||
module.exports = function(xcssfile, url, param, cb) { | ||
cb(false, "/* node-sass isn't installed\n *"+xcssfile+" ERROR!\n */"); | ||
}; | ||
} |
@@ -22,9 +22,10 @@ /** | ||
http.createServer(function (req, res) { | ||
fcInst = new FlexCombo(); | ||
fcInst.handle(req, res, function () { | ||
res.writeHead(404, {"Content-Type": "text/plain"}); | ||
res.end("Your combo file not found."); | ||
}); | ||
}) | ||
http | ||
.createServer(function (req, res) { | ||
fcInst = new FlexCombo(); | ||
fcInst.handle(req, res, function () { | ||
res.writeHead(404, {"Content-Type": "text/plain"}); | ||
res.end("Your combo file not found."); | ||
}); | ||
}) | ||
.listen(1234); |
@@ -16,7 +16,7 @@ module.exports = { | ||
}, | ||
engine:{}, | ||
engine: {}, | ||
urls: {}, | ||
define: "KISSY.add", | ||
anonymous: false, | ||
debug: true | ||
debug: false | ||
}; |
var fsLib = require("fs"); | ||
var pathLib = require("path"); | ||
var isUtf8 = require("is-utf8"); | ||
@@ -29,2 +30,32 @@ var iconv = require("iconv-lite"); | ||
return _url; | ||
} | ||
/* 获取应用filter规则后的本地地址 */ | ||
exports.getRealPath = function (_url, filter, map, debug) { | ||
_url = exports.filteredUrl(_url, filter, debug); | ||
_url = (_url.match(/^\//) ? '' : '/') + _url; | ||
map = map || {}; | ||
// urls中key对应的实际目录 | ||
var repPath = ''; | ||
var revPath = _url; | ||
var longestMatchNum = 0; | ||
for (var k in map) { | ||
if (_url.indexOf(k) == 0 && longestMatchNum < k.length) { | ||
longestMatchNum = k.length; | ||
repPath = map[k]; | ||
revPath = _url.slice(longestMatchNum); | ||
} | ||
} | ||
var absPath = ''; | ||
if (repPath.indexOf('/') == 0 || /^\w{1}:\\.*$/.test(repPath)) { | ||
absPath = pathLib.normalize(pathLib.join(repPath, revPath)); | ||
} | ||
else { | ||
absPath = pathLib.normalize(pathLib.join(process.cwd(), repPath, revPath)); | ||
} | ||
return absPath; | ||
}; |
{ | ||
"name": "flex-combo", | ||
"version": "0.7.9", | ||
"version": "0.8.0", | ||
"description": "The Flex-combo is combo tool designed for web front-end developer. It support various kinds of combo format by modify configuration(eg. yahoo combo).", | ||
@@ -13,9 +13,10 @@ "main": "index.js", | ||
"dependencies": { | ||
"async": "~0.9.0", | ||
"commander": "~2.5.0", | ||
"iconv-lite": "~0.4.4", | ||
"is-utf8": "~0.2.0", | ||
"juicer": "~0.6.6-stable", | ||
"less": "~2.2.0", | ||
"mace": "~2.0.0", | ||
"mime": "~1.2.11", | ||
"juicer": "~0.6.6-stable", | ||
"less": "~1.7.5" | ||
"mime": "~1.2.11" | ||
}, | ||
@@ -30,6 +31,6 @@ "repository": { | ||
"node", | ||
"taobao" | ||
"alibaba" | ||
], | ||
"author": "wayfind", | ||
"license": "BSD" | ||
} | ||
} |
@@ -102,4 +102,4 @@ # Flex Combo 介绍 | ||
-c, --charset [string] http响应数据的编码方式,默认为utf-8 | ||
-p, --http_port [int] 启动HTTP服务的端口,默认为80 | ||
-P, --https_port [int] 启动HTTPS服务的端口,默认为443 | ||
-p, --http_port [int] 启动HTTP服务的端口,默认为80 | ||
-P, --https_port [int] 启动HTTPS服务的端口,默认为443 | ||
@@ -123,3 +123,3 @@ 在项目目录下执行`flex-combo`而不带任何参数时,将以项目目录为根目录建立Combo服务器。 | ||
"urls": { | ||
"/xxx":"/Users/david/xxxproject" | ||
"/xxx": "/Users/david/xxxproject" | ||
}, | ||
@@ -132,2 +132,5 @@ "headers": {"host":"a.tbcdn.cn"}, | ||
"charset": "utf-8", | ||
"engine": { | ||
"^/mock/.+\\.json$":"mock/index.js" | ||
}, | ||
"filter": { | ||
@@ -138,8 +141,8 @@ "\\?.+": "", | ||
}, | ||
"supportedFile": "\\.js|\\.css|\\.png|\\.gif|\\.jpg|\\.swf|\\.xml|\\.less", | ||
"urlBasedCharset": {}, | ||
"hosts":{ | ||
"hosts": { | ||
"a.tbcdn.cn":"122.225.67.241", | ||
"g.tbcdn.cn":"115.238.23.250" | ||
} | ||
}, | ||
"debug": true | ||
} | ||
@@ -156,4 +159,4 @@ ``` | ||
{ | ||
"/xxx":"/Users/david/xxxproject", | ||
"/yyy":"/Users/david/yyyproject" | ||
"/xxx": "/Users/david/xxxproject", | ||
"/yyy": "/Users/david/yyyproject" | ||
} | ||
@@ -168,4 +171,4 @@ ``` | ||
{ | ||
"/xxx":"/Users/david/xxxproject", | ||
"/xxx/aaa":"/Users/david/yyyproject" | ||
"/xxx": "/Users/david/xxxproject", | ||
"/xxx/aaa": "/Users/david/yyyproject" | ||
} | ||
@@ -187,3 +190,3 @@ ``` | ||
``` | ||
"headers": {"host":"a.tbcdn.cn"}, | ||
"headers": {"host": "a.tbcdn.cn"}, | ||
``` | ||
@@ -195,4 +198,4 @@ | ||
"hosts":{ | ||
"a.tbcdn.cn":"122.225.67.241", | ||
"g.tbcdn.cn":"115.238.23.250" | ||
"a.tbcdn.cn": "122.225.67.241", | ||
"g.tbcdn.cn": "115.238.23.250" | ||
} | ||
@@ -221,2 +224,6 @@ ``` | ||
#### 自定义引擎 | ||
`engine` 支持使用者自行插入处理逻辑(处理权交给使用者编写的js),可应用于截获url进行数据mock或对应某些文件后缀匹配处理逻辑。 | ||
#### 过滤器 | ||
@@ -226,5 +233,5 @@ | ||
#### 支持文件扩展名 | ||
#### 调试模式 | ||
`supportedFile`可以定义支持的文件扩展名列表。 | ||
`debug` 为true时,终端窗口将显示更多信息 | ||
@@ -231,0 +238,0 @@ ## lib开发模式 |
279
41426
8
684
+ Addedasync@~0.9.0
+ Addedajv@6.12.6(transitive)
+ Addedasap@1.0.0(transitive)
+ Addedasn1@0.2.6(transitive)
+ Addedassert-plus@1.0.0(transitive)
+ Addedasynckit@0.4.0(transitive)
+ Addedaws-sign2@0.7.0(transitive)
+ Addedaws4@1.13.2(transitive)
+ Addedbcrypt-pbkdf@1.0.2(transitive)
+ Addedcaseless@0.12.0(transitive)
+ Addedcombined-stream@1.0.8(transitive)
+ Addedcore-util-is@1.0.2(transitive)
+ Addeddashdash@1.14.1(transitive)
+ Addeddelayed-stream@1.0.0(transitive)
+ Addedecc-jsbn@0.1.2(transitive)
+ Addedextend@3.0.2(transitive)
+ Addedextsprintf@1.3.0(transitive)
+ Addedfast-deep-equal@3.1.3(transitive)
+ Addedfast-json-stable-stringify@2.1.0(transitive)
+ Addedforever-agent@0.6.1(transitive)
+ Addedform-data@2.3.3(transitive)
+ Addedgetpass@0.1.7(transitive)
+ Addedhar-schema@2.0.0(transitive)
+ Addedhar-validator@5.1.5(transitive)
+ Addedhttp-signature@1.2.0(transitive)
+ Addedimage-size@0.3.5(transitive)
+ Addedis-typedarray@1.0.0(transitive)
+ Addedisstream@0.1.2(transitive)
+ Addedjsbn@0.1.1(transitive)
+ Addedjson-schema@0.4.0(transitive)
+ Addedjson-schema-traverse@0.4.1(transitive)
+ Addedjsprim@1.4.2(transitive)
+ Addedless@2.2.0(transitive)
+ Addedmime-db@1.52.0(transitive)
+ Addedmime-types@2.1.35(transitive)
+ Addedoauth-sign@0.9.0(transitive)
+ Addedperformance-now@2.1.0(transitive)
+ Addedpromise@6.1.0(transitive)
+ Addedpsl@1.15.0(transitive)
+ Addedpunycode@2.3.1(transitive)
+ Addedqs@6.5.3(transitive)
+ Addedrequest@2.88.2(transitive)
+ Addedsafe-buffer@5.2.1(transitive)
+ Addedsshpk@1.18.0(transitive)
+ Addedtough-cookie@2.5.0(transitive)
+ Addedtunnel-agent@0.6.0(transitive)
+ Addedtweetnacl@0.14.5(transitive)
+ Addeduri-js@4.4.1(transitive)
+ Addeduuid@3.4.0(transitive)
+ Addedverror@1.10.0(transitive)
- Removedasn1@0.1.11(transitive)
- Removedassert-plus@0.1.5(transitive)
- Removedaws-sign2@0.5.0(transitive)
- Removedboom@0.4.2(transitive)
- Removedclean-css@2.2.23(transitive)
- Removedcombined-stream@0.0.7(transitive)
- Removedcommander@2.2.0(transitive)
- Removedcryptiles@0.2.2(transitive)
- Removedctype@0.5.3(transitive)
- Removeddelayed-stream@0.0.5(transitive)
- Removedforever-agent@0.5.2(transitive)
- Removedform-data@0.1.4(transitive)
- Removedhawk@1.1.1(transitive)
- Removedhoek@0.9.1(transitive)
- Removedhttp-signature@0.10.1(transitive)
- Removedless@1.7.5(transitive)
- Removedmime-types@1.0.2(transitive)
- Removednode-uuid@1.4.8(transitive)
- Removedoauth-sign@0.3.0(transitive)
- Removedqs@1.0.2(transitive)
- Removedrequest@2.40.0(transitive)
- Removedsntp@0.2.4(transitive)
- Removedstringstream@0.0.6(transitive)
- Removedtldts@6.1.73(transitive)
- Removedtldts-core@6.1.73(transitive)
- Removedtough-cookie@5.1.0(transitive)
- Removedtunnel-agent@0.4.3(transitive)
Updatedless@~2.2.0