tianma-unicorn
Version:
The Pegasus module for Unicorn System.
195 lines (167 loc) • 7.81 kB
JavaScript
var util = require('mini-util'),
Front = require('./front'),
compiler = require('./compiler'),
unique = require('./unique'),
mime = require('mime-types');
var CONFIG = {};
CONFIG.prod = CONFIG.test = {
longExpires: 31536000,
normalExpires: 1800,
shortExpires: 30
};
CONFIG.dev = {
longExpires: 0,
normalExpires: 0,
shortExpires: 0
};
var GLOBAL_FILE = 'js/5v/lib/ae/debug/global-img-server.js',
PATTERN_YUI = /(YAHOO\.register\s*\(\s*['"]event['"][\s\S]*?\))/,
FONT_MIME = [
'application/vnd.ms-fontobject',
'application/x-font-ttf',
'font/opentype',
'application/x-font-woff',
'application/font-woff'
];
var cache = {},
meta = {};
module.exports = function (config) {
config = util.mix({
mode: 'dev'
}, config);
config = util.mix(config, CONFIG[config.mode]);
return function (req, res) {
var url = new Front().parse(req.path, '/');
if (url && (url.type == '.css' || url.type == '.js')) {
var files = [],
mtimes = [],
mtime, stamp,
filtered = [],
base = url.base,
pathnames = url.pathnames,
expires = config.shortExpires;
req.url('/unicorn.json?')(function (err) {
if (err) {
res(err);
} else {
var options = {
alias: {},
modules: []
},
obj, c, data = res.toString();
try {
obj = JSON.parse(data);
} catch (err) {
res(new Error('JSON syntax error in "unicorn.json"'));
return;
}
options.alias = obj.alias;
options.modules = obj.modules;
c = compiler.generate({
alias: options.alias,
modules: options.modules,
cache: cache,
req: req,
res: res,
mode: config.mode
});
c.compile(GLOBAL_FILE, function (file) {
if (file !== null) {
meta[file.pathname] = {
dataHash: file.meta.dataHash.toString(16),
depsHash: file.meta.depsHash.toString(16),
nameHash: file.meta.nameHash.toString(16),
requires: file.meta.requires
};
}
(function nextFile(i) {
if (i < pathnames.length) {
(function nextCandidate(j) {
if (j < base.length) {
c.compile(base[j] + pathnames[i], function (file) {
if (file !== null) {
meta[file.pathname] = {
dataHash: file.meta.dataHash.toString(16),
depsHash: file.meta.depsHash.toString(16),
nameHash: file.meta.nameHash.toString(16),
requires: file.meta.requires
};
filtered.push(file.pathname);
nextFile(i + 1);
} else {
nextCandidate(j + 1);
}
});
} else {
nextFile(i + 1);
}
}(0));
} else {
if (c.errors.length > 0) {
res(new Error(c.errors[0]));
}
var expanded = [],
extname = url.type;
filtered.forEach(function (pathname) {
var data = meta[pathname];
if (data) {
expanded = expanded.concat(data.requires, pathname);
}
});
if (expanded.length > 0 && extname === '.js' && meta[GLOBAL_FILE]) {
expanded.unshift(GLOBAL_FILE);
}
var dataHash = 0,
depsHash = 0,
data = [];
unique(expanded).forEach(function (pathname, index) {
files[index] = {
pathname: pathname,
data: cache[pathname].data
};
mtimes.push(cache[pathname].mtime);
if (meta[pathname]) {
dataHash += parseInt(meta[pathname].dataHash, 16);
depsHash += parseInt(meta[pathname].depsHash, 16);
}
if (config.mode == 'dev'){
data.push(new Buffer('/*** START OF ' + pathname + ' ***/\n'),
cache[pathname].data,
new Buffer('\n/*** END OF ' + pathname + ' ***/\n'));
}else{
data.push(cache[pathname].data);
}
});
mtime = new Date(Math.max.apply(Math, mtimes));
stamp = dataHash.toString(16) + '_' + depsHash.toString(16);
res.head({
'content-type': mime.contentType(url.type),
'expires': new Date(Date.now() + 1000 * expires).toGMTString(),
'cache-control': 'max-age=' + expires,
'last-modified': mtime.toGMTString(),
'etag': stamp,
'vary': 'Accept-Encoding'
});
if(data.length){
res.status(200);
}else{
res.status(404);
}
res.data(data.join(''));
res();
}
}(0));
});
}
});
} else {
req(function(err){
//set font file cross domain
if (FONT_MIME.indexOf(res.head('content-type')) !== -1) {
res.head('access-control-allow-origin','*');
}
res();
});
}
}
};