rtyler

V8 and FastCGI, Exploring an Idea

Over the past couple years I've talked a lot of trash about JavaScript (really, a lot) but I've slowly started to come around to a more neutral stance, I actually hate browsers, I like JavaScript just fine by itself! While the prototype-based object system is a little weird at first coming from a more classical object-oriented background, the concept grows on you the more you use it.

Since I hate browsers so much (I really do), I was pleased as punch to hear that Google's V8 JavaScript Engine was embeddable. While WebKit's JavaScriptCore is quite a nice JavaScript engine, it doesn't lend itself to being embedded the same way that V8 does. The only immediate downside to V8 is that it's written entirely in C++, which does provide some hurdles to embedding (for example, I'm likely never going to be able to embed it into a Mono application), but for the majority of cases embedding the engine into a project shouldn't be all that difficult.

A few weekends ago I started exploring the possibility of running server-side JavaScript courtesy of V8, after reading about mod_v8 I felt more confident to try my project: FastJS.

In a nutshell, FastJS is a FastCGI server to process server-side JavaScript, this means FastJS can hook up to Lighttpd, Nginx, or even Apache via mod_fcgi. Currently FastJS is in a state of "extremely unstable and downright difficult", there's not a lot there as I'm exploring what should be provided by the FastJS server-side software, and what should be provided by JavaScript libraries. As it stands now, FastJS preloads the environment with jQuery 1.3.2 and a "fastjs" object which contains some important callbacks like:
fastjs.write() // write to the output stream

fastjs.log() // write to the FastCGI error.lgo
fastjs.source() // Include and execute other JavaScript files


On the server side, a typical request looks something like this (for now):
2009-03-09 05:04:06: (response.c.114) Response-Header:

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-type: text/html
X-FastJS-Request: 1
X-FastJS-Process: 11515
X-FastJS-Engine: V8
Date: Mon, 09 Mar 2009 09:04:06 GMT
Server: lighttpd/1.4.18


Below is an example of the current test page "index.fjs":


var index = new Object();

index.header = function() {
fastjs.write("FastJS");
fastjs.write("");
fastjs.write("

FastJS Test Page


");
};

index.footer = function() {
fastjs.write("");
};

index.dump_attributes = function(title, obj) {
fastjs.write("
");
fastjs.write(title);
fastjs.write("


");

for (var k in obj) {
fastjs.write(k + " = ");

if (typeof(obj[k]) != "string")
fastjs.write(typeof(obj[k]));
else
fastjs.write(obj[k]);

fastjs.write("
\n");
}
};

(function() {
index.header();

fastjs.source("pages/test.fjs");

index.dump_attributes("window", window);
index.dump_attributes('location', location);
index.dump_attributes("fastjs.env", fastjs.env);
index.dump_attributes("fastjs.fcgi_env", fastjs.fcgi_env);


index.footer();

fastjs.log("This should go into the error.log");
})();

The code above generates a page that looks pretty basic, but informative nonetheless (click to enlarge):


Pretty fun in general to play with, I think I'm near on the point where I can stop writing more of my terrible C/C++ code and get back into the wonderful land of JavaScript. As it stands now, here's what still needs to be done:
  • Proper handling of erroring scripts via an informative 500 page that reports on the error
  • Templating? Lots of fastjs.write() calls are likely to drive you mad
  • Performance concerns? As of now, the whole stack (jQuery + .fjs) are evaluated every page request.
  • Tests! I should really get around to writing some level of integration tests to make sure that FastJS is returning expected results for particular chunks of .fjs scripts


The project is hosted on GitHub right now, here and is under a 2-clause BSD license.