UNPKG

essi

Version:

Enhanced SSI with Juicer & Velocity

272 lines (237 loc) 8.19 kB
var pathLib = require("path"); var fsLib = require("fs"); var urlLib = require("url"); var util = require("util"); var merge = require("merge"); var mkdirp = require("mkdirp"); var J = require("juicer"); //var livereload = require("livereload"); //var ipLib = require("ip"); var Stack = require("plug-trace").stack; var Juicer = require("./lib/juicer"); var VM = require("./lib/vm"); var Remote = require("./lib/remote"); var AssetsTool = require("./lib/assetsTool"); var Helper = require("./lib/helper"); //var genCer = require(pathLib.join(__dirname, "/https/gen-cer.js")); // var liveReloadMap = { // http: null, // https: null // }; // var liveReloadIP = ipLib.address(); // var liveReloadPort = { // http: 3480, // https: 3443 // }; function ESSI(param, confFile) { this.cacheDir = null; this.param = merge(true, require("./lib/param")); param = param || {}; var pkgName = require(__dirname + "/package.json").name; this.trace = new Stack(pkgName); var confJSON = {}; if (confFile) { this.cacheDir = pathLib.join(pathLib.dirname(confFile), "../.cache"); if (!fsLib.existsSync(confFile)) { fsLib.writeFileSync(confFile, JSON.stringify(this.param, null, 2), {encoding: "utf-8"}); fsLib.chmod(confFile, 0777); } try { confJSON = require(confFile); delete require.cache[confFile]; param.hosts = merge.recursive(param.hosts, confJSON.hosts || {}); } catch (e) { this.trace.error("Can't require config file!", "IO"); confJSON = {}; } } this.param = merge.recursive(true, this.param, confJSON, param); // Magic Variable var key; for (var i in this.param) { key = "__" + i + "__"; if (typeof this.param[i] == "string" && !this.param.replaces[key]) { this.param.replaces[key] = this.param[i]; } } var rootdir = this.param.rootdir || "src"; if (rootdir.indexOf('/') == 0 || /^\w{1}:[\\/].*$/.test(rootdir)) { this.param.rootdir = rootdir; } else { this.param.rootdir = pathLib.normalize(pathLib.join(process.cwd(), rootdir)); } if (!this.cacheDir) { this.cacheDir = pathLib.join(this.param.rootdir, "../.cache"); } this.cacheDir = pathLib.join(this.cacheDir, pkgName); if (this.param.cache && !fsLib.existsSync(this.cacheDir)) { mkdirp(this.cacheDir, function (e, dir) { fsLib.chmod(dir, 0777); fsLib.chmod(this.cacheDir, 0777); }.bind(this)); } // if (this.param.livereload) { // if (liveReloadMap.http === null) { // liveReloadMap.http = livereload.createServer({ // port: liveReloadPort.http // }); // liveReloadMap.http.watch(this.param.rootdir); // } // // if (liveReloadMap.https === null) { // genCer(liveReloadIP, function (e, key, cert) { // liveReloadMap.https = livereload.createServer({ // port: liveReloadPort.https, // https: { // key: key, // cert: cert // } // }); // liveReloadMap.https.watch(this.param.rootdir); // }.bind(this)); // } // } }; ESSI.prototype = { constructor: ESSI, compile: function (realpath, content, cb) { var assetsFlag = (content === null ? false : true); // 保证content是String型,非Buffer if (content && Buffer.isBuffer(content)) { content = Helper.decode(content); } var isVM = /\.vm$/.test(realpath); if (isVM) { var vm = new VM(this.param, this.trace); if (!content) { content = Helper.readFileInUTF8(realpath); } cb(null, vm.render(content, realpath)); } else { var dirname = urlLib.resolve( this.param.cdnPath + '/', pathLib.dirname(pathLib.join(this.param.version, realpath.replace(this.param.rootdir, ''))) ); this.param.replaces["__fullPath__"] = dirname; this.trace.info(this.param.replaces, "Magic Variables"); var isJuicer = true; var ignoreJuicer = this.param.ignoreJuicer; if (util.isArray(ignoreJuicer)) { isJuicer = ignoreJuicer.every(function (i) { return !new RegExp(i).test(realpath); }); } else if (typeof ignoreJuicer == "boolean") { isJuicer = !ignoreJuicer; } var local = new Juicer(this.param, this.trace); if (content) { content = content.replace(/\$\{random\(\)\}/g, ''); content = local.parse(content, realpath, isJuicer, true); } else { content = local.fetch(realpath, isJuicer); } content = Helper.customReplace(content, this.param.replaces); var assetsTool = new AssetsTool(realpath, this.param, assetsFlag); content = assetsTool.action(content, true); // 抓取远程页面 var remote = new Remote(content, this.param, this.trace, this.cacheDir); remote.fetch(function (content) { if (!content) { content = Helper.readFileInUTF8(realpath); } content = Helper.customReplace(content, this.param.replaces); if (this.param.native2ascii) { content = Helper.encodeHtml(content); } cb(null, content.replace(/^[\n\r]{1,}|[\n\r]{1,}$/g, '')); }.bind(this)); } }, getRealPath: function (_url) { _url = urlLib.parse(_url).pathname; var _filter = this.param.filter || {}; var jsonstr = JSON.stringify(_filter).replace(/\\{2}/g, '\\'); var filter = []; jsonstr.replace(/[\{\,]"([^"]*?)"/g, function (all, key) { filter.push(key); }); var regx, ori_url; for (var k = 0, len = filter.length; k < len; k++) { regx = new RegExp(filter[k], 'g'); if (regx.test(_url)) { ori_url = _url; _url = _url.replace(regx, _filter[filter[k]]); this.trace.filter(regx, ori_url, _url); } } _url = urlLib.parse(_url).pathname; var realPath = pathLib.join(this.param.rootdir, _url); var vmRealPath = realPath.replace(/_(\w)/g, function (total, word) { return word.toUpperCase(); }); var isExistsVM = fsLib.existsSync(vmRealPath); if (fsLib.existsSync(realPath) || isExistsVM) { return isExistsVM ? vmRealPath : realPath; } else { return null; } }, handle: function (req, res, next) { var matching = this.param.supportedFile; if (matching.length && !Helper.matchPath(req.url, matching)) { next(); } else { var HOST = (req.connection.encrypted ? "https" : "http") + "://" + (req.hostname || req.host || req.headers.host); this.trace.request(HOST, req.url); var realPath = this.getRealPath(req.url); if (realPath) { var state = fsLib.statSync(realPath); if (state && state.isFile()) { this.compile(realPath, null, function (err, content) { if (!err) { // if (this.param.livereload) { // content = Helper.addLiveReload(content, liveReloadIP, liveReloadPort[req.connection.encrypted ? "https" : "http"]); // } var buff = Helper.encode(content, this.param.charset); res.writeHead(200, { "Access-Control-Allow-Origin": '*', "Content-Type": "text/html; charset=" + this.param.charset, "Content-Length": buff.length, "X-MiddleWare": "essi" }); res.write(buff); res.end(); this.trace.response(realPath, buff); } else { this.trace.error(realPath, err.code); next(); } }.bind(this)); } else { next(); } } else { var errorTPL = Helper.readFileInUTF8(pathLib.join(__dirname, "www/error.tpl")); res.write(J(errorTPL, { url: realPath, code: 404, reason: "Not Found" })); res.end(); this.trace.error(realPath, "404 Not Found"); this.trace.response(HOST + req.url); } } } }; exports = module.exports = ESSI;