sourcemint-loader-js
Version:
277 lines (234 loc) • 8.52 kB
JavaScript
var CONNECT = require("connect"),
FS = require("fs"),
PATH = require("path"),
CRYPTO = require("crypto"),
QUERYSTRING = require("querystring");
HTTP = require("http"),
FS = require("fs"),
ZLIB = require("zlib");
const ROOT_PATH = PATH.dirname(__dirname);
const PORT = 8080;
exports.main = function()
{
var server = CONNECT();
server.use(CONNECT.router(function(app)
{
app.get(/^\/$/, function(req, res)
{
res.writeHead(302, {
"Location": "http://127.0.0.1:" + PORT + "/workspace/www/"
});
res.end();
});
app.get(/^\/loader.js$/, function(req, res)
{
res.setHeader("Content-Type", "text/javascript");
res.end(getRawSource());
});
app.get(/^\/loader.stripped.js$/, function(req, res)
{
res.setHeader("Content-Type", "text/plain");
res.end(getStrippedSource());
});
app.get(/^\/loader.min.js/, function(req, res)
{
res.setHeader("Content-Type", "text/plain");
getMinifiedSource(function(source)
{
res.end(source);
});
});
app.get(/^\/loader.crush.js/, function(req, res)
{
res.setHeader("Content-Type", "text/plain");
getCrushedSource(function(source)
{
res.end(source);
});
});
app.get(/^\/loader.min.js.gz/, function(req, res)
{
res.setHeader("Content-Type", "application/x-javascript");
res.setHeader("Content-Encoding", "gzip");
getMinifiedSource(function()
{
var raw = FS.createReadStream(ROOT_PATH + "/loader.min.js.gz");
res.writeHead(200, {
"content-encoding": "gzip"
});
raw.pipe(res);
});
});
app.get(/^\/loader.crush.js.gz/, function(req, res)
{
res.setHeader("Content-Type", "application/x-javascript");
res.setHeader("Content-Encoding", "gzip");
getCrushedSource(function()
{
var raw = FS.createReadStream(ROOT_PATH + "/loader.crush.js.gz");
res.writeHead(200, {
"content-encoding": "gzip"
});
raw.pipe(res);
});
});
app.get(/^\/.*/, CONNECT.static(ROOT_PATH));
}));
server.listen(PORT, "127.0.0.1");
console.log("Workspace running. Open browser to: http://127.0.0.1:" + PORT + "/");
}
if (require.main === module) {
exports.main();
}
function getRawSource()
{
return FS.readFileSync(ROOT_PATH + "/loader.js").toString();
}
function getStrippedSource()
{
var source = getRawSource();
source = source.split("\n").filter(function(line)
{
return !(/\/\*DEBUG\*\//.test(line));
}).join("\n");
source = "\n\n// WARNING: DO NOT EDIT THIS FILE! IT IS AUTO-GENERATED FROM ./loader.js BY STRIPPING '/*DEBUG*/' LINES.\n\n\n" + source;
FS.writeFileSync(ROOT_PATH + "/loader.stripped.js", source);
return source;
}
var minifying = false;
function getMinifiedSource(callback)
{
var source = getStrippedSource(),
sourceHash = md5Hash(source),
fileHash = false;
function done()
{
callback(FS.readFileSync(ROOT_PATH + "/loader.min.js").toString());
}
if (PATH.existsSync(ROOT_PATH + "/workspace/www/loader.stripped.js.md5"))
{
fileHash = FS.readFileSync(ROOT_PATH + "/workspace/www/loader.stripped.js.md5").toString();
}
if (sourceHash != fileHash && minifying === false)
{
minifying = true;
console.log("Minifying loader.js using Google Closure ...");
compileSource(source, function(compiledSource)
{
FS.writeFileSync(ROOT_PATH + "/loader.min.js", compiledSource);
FS.writeFileSync(ROOT_PATH + "/workspace/www/loader.min.js-size", ""+compiledSource.length);
writeZip(compiledSource, ROOT_PATH + "/loader.min.js.gz", function(result)
{
FS.writeFileSync(ROOT_PATH + "/workspace/www/loader.min.js.gz-size", ""+result.length);
var readme = FS.readFileSync(ROOT_PATH + "/README.md").toString();
readme = readme.replace(/\*\*\d* bytes\*\* \*\(minified and zipped\)\*/, "**" + result.length + " bytes** *(minified and zipped)*");
FS.writeFileSync(ROOT_PATH + "/README.md", readme);
console.log("... OK");
// TMP: Bypass for now cos it is so slow.
/*
console.log("Crushing loader.min.js using JSCrush ...");
crushSource(compiledSource, function(crushedSource)
{
FS.writeFileSync(ROOT_PATH + "/loader.crush.js", crushedSource);
FS.writeFileSync(ROOT_PATH + "/workspace/www/loader.crush.js-size", ""+crushedSource.length);
writeZip(crushedSource, ROOT_PATH + "/loader.crush.js.gz", function(result)
{
FS.writeFileSync(ROOT_PATH + "/workspace/www/loader.crush.js.gz-size", ""+result.length);
FS.writeFileSync(ROOT_PATH + "/workspace/www/loader.stripped.js.md5", sourceHash);
console.log("... OK");
*/
minifying = false;
done();
/*
});
});
*/
});
});
}
else
{
done();
}
}
function getCrushedSource(callback)
{
getMinifiedSource(function()
{
callback(FS.readFileSync(ROOT_PATH + "/loader.crush.js").toString());
});
}
function md5Hash(data)
{
var shasum = CRYPTO.createHash("md5");
shasum.update(data);
return shasum.digest("hex");
}
function writeZip(source, zipPath, callback)
{
ZLIB.gzip(new Buffer(source), function(err, result)
{
FS.writeFileSync(zipPath, result.toString("binary"));
var out = FS.createWriteStream(zipPath);
out.on("close", function()
{
callback(result);
});
out.end(result);
});
}
function compileSource(codestring, callback)
{
// @credit http://stackoverflow.com/questions/6158933/http-post-request-in-node-js
var post_data = QUERYSTRING.stringify({
'compilation_level' : 'SIMPLE_OPTIMIZATIONS',
'output_format': 'json',
'output_info': 'compiled_code',
'js_code' : codestring
});
// An object of options to indicate where to post to
var post_options = {
host: 'closure-compiler.appspot.com',
port: '80',
path: '/compile',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length
}
};
// Set up the request
var post_req = HTTP.request(post_options, function(res) {
res.setEncoding('utf8');
var data = [];
res.on('data', function(chunk) {
data.push(chunk);
});
res.on('end', function() {
callback(JSON.parse(data.join("")).compiledCode);
});
});
// post the data
post_req.write(post_data);
post_req.end();
}
/* @source http://www.iteral.com/jscrush/ */
function crushSource(codestring, callback)
{
// b.innerHTML="Javascript source<br><textarea rows=12 cols=80></textarea><br><button>CRUSH</button> <b></b><br><textarea rows=12 cols=80></textarea>"+b.innerHTML;
Q=[];
for(i=127;--i;i-10&&i-13&&i-34&&i-39&&i-92&&Q.push(String.fromCharCode(i)));
// setTimeout("b.children[1].value=eval(b.children[9].innerHTML.replace(/eval\\(_\\)/,'_'));L()");
// b.children[3].onclick=L=
callback(function(s) {
i=s=s.replace(/([\r\n]|^)\s*\/\/.*|[\r\n]+\s*/g,'').replace(/\\/g,'\\\\'),B=s.length/2,m='';
for(S=encodeURI(i).replace(/%../g,'i').length;;m=c+m){for(c=0,i=122;!c&&--i;!~s.indexOf(Q[i])&&(c=Q[i]));if(!c)break;
for(o={},M=N=e=Z=t=0;++t<=B;)for(i=0;++i<s.length-t;)if(!o[x=s.substr(j=i,t)])
if(~(j=s.indexOf(x,j+t)))for(Z=t,o[x]=1;~j;o[x]++)j=s.indexOf(x,j+t);B=Z;
for(i in o){j=encodeURI(i).replace(/%../g,'i').length;if(j=(R=o[i])*j-R-j-1)if(j>M||j==M&&R>N)M=j,N=R,e=i}if(!e)break;
s=s.split(e).join(c)+c+e}c=s.split('"').length<s.split("'").length?(B='"',/"/g):(B="'",/'/g);
return '_='+B+s.replace(c,'\\'+B)+B+';for(Y=0;$='+B+m+B+'[Y++];)with(_.split($))_=join(pop());eval(_)';
// i=encodeURI(i).replace(/%../g,'i').length;
// b.children[4].innerHTML=S+'B to '+i+'B ('+(i=i-S)+'B, '+((i/S*1e4|0)/100)+'%)'
}(codestring));
}