Use the Google Closure Service With Node.js
Here's a short Node.js method for compressing javascript
with Google's Closure Compiler Service. Besides being
practical, it's a good example of sending a POST request using Node's
http
module.
First, here's an example application that compresses itself. The
script reads itself into a string and passes result to
closure.compile()
. If an error is passed to the callback, it's
thrown. Otherwise, the result is logged to the console.
var fs = require('fs'),
closure = require('../lib/closure'),
self = fs.readFileSync(__filename);
closure.compile(self, function(err, code) {
if (err) throw err;
var smaller = Math.round((1 - (code.length / self.length)) * 100);
console.log('Myself, compiled (%d% smaller)', smaller);
console.dir(code);
});
The compile()
procedure accepts a string of javascript code
and a
next
procedure. Most of the work is setting up the request and
processing the response. The http.createClient()
and
Client.request()
methods are used to start a POST
request.
HTTP-level and service-level errors are converted to node Error
objects and passed directly to next
.
function compile(code, next) {
try {
var qs = require('querystring'),
http = require('http'),
host = 'closure-compiler.appspot.com',
body = qs.stringify({
js_code: code.toString('utf-8'),
compilation_level: 'ADVANCED_OPTIMIZATIONS',
output_format: 'json',
output_info: 'compiled_code'
}),
client = http.createClient(80, host).on('error', next),
req = client.request('POST', '/compile', {
'Host': host,
'Content-Length': body.length,
'Content-Type': 'application/x-www-form-urlencoded'
});
req.on('error', next).end(body);
req.on('response', function(res) {
if (res.statusCode != 200)
next(new Error('Unexpected HTTP response: ' + res.statusCode));
else
capture(res, 'utf-8', parseResponse);
});
function parseResponse(err, data) {
err ? next(err) : loadJSON(data, function(err, obj) {
var error;
if (err)
next(err);
else if ((error = obj.errors || obj.serverErrors || obj.warnings))
next(new Error('Failed to compile: ' + sys.inspect(error)));
else
next(null, obj.compiledCode);
});
}
} catch (err) {
next(err);
}
}
The capture
and loadJSON
methods are helpers that convert a
Stream
to a string and JSON to an Object
.
Get the code here.