On-the-fly concatenation, minification and dependency resolution for JavaScript.
Gracie is a lightweight file server aimed at serving JavaScript files in an optimized way. It does the following things:
Gracie is written in Node.js. You can integrate Gracie into your Node.js projects instead of using the bundled server if you want.
Gracie is very simple. You can used it with your existing JavaScript with no modifications. Just start up the Gracie server and request your change your script tags to source their JavaScript from the Gracie server. Optionally, you can use the //require syntax to specify which files depend on which other files. Then you don't have to keep track of a long list of files to load. Gracie will resolve the dependencies for you.
Gracie is also well unit tested and performs quite well. See Perforamnce.
npm install gracie
Gracie comes with a bundled server. You have a few options when running the server.
$ gracie --help Usage: gracie [options] SRC_DIR [SRC_DIR...] Options: --port | -p What port to bind to. Defaults to 7763. --host | -h Limit to connections to this host if specified. --help Show this message.
Note that you can specify several source directories for your JS files. Think of this like a PATH for your JS files.
Typically you'll be running your webserver already on port 80 and will not dedicate a host for Gracie. Therefore, you'll need to run it on some port other than 80. Having your JS served from a weird port really isn't a big deal, so I suggest just using the default port and running it on your existing webserver. But if you really want to, you could dedicate a server to this and run it on port 80. I would not suggest running this behind apache.
Note: Cached requests are automatically purged when underlying files are changed. Therefore, you can can change files during development and test without restarting Gracie.
To request JavaScript from Gracie, just sent a GET request to the Gracie URL.
http://$hostname:$port/gracie?sources=source1.js,source2.js&minify=1
The sources param is a comma-delimited list of JavaScript sources relative to the paths you privided the Gracie server when you started it. If the file is in a subfolder, just write the whole path here.
http://$hostname:$port/gracie?sources=vend/jquery.js,other.js&minify=1
The minify parameter is optional. If omitted, the output will NOT be minified. Minification is performed using UglifyJS.
If your project is written in Node.js and you are using connect, then you have two more options. First, set up the connect middleware.
app.configure(function() {
...
require('gracie').connect('/js', ['/path/to/js'])
...
});
The first parameter is the pathname that Gracie should handle. The second is an array of javascript source directories. With this in place, you can use your existing connect server to serve your js.
<script type="text/javascript" src="http://www.mysite.com/js?sources=a.js,b.js,c.js"></script>
The connect middleware will also make the Gracie Server instance available on all requests so you can request JavaScript content on-the-fly and embed it directly in the page. To do this, you'll want to generate the JavaScript in your controller and pass it to your view.
var minify = true;
req.gracieServer.getContent(['cool.js'], function(err, gracieResponse) {
res.render('myview.ejs', {
locals: { jsCode: gracieResponse.content }
});
}, minify);
Then, in your view, display the content. Be sure not to escape it.
<script type="text/javascript"><%- jsCode %></script>
Gracie allows you to make one file depend on (or "require") another file. This prevents you from having to request a long list of JavaScript files for a given page. In general, you'll probably just have one file for a given page and everything else will be loaded automatically.
The require syntax is dead simple.
//require vend/jquery.js
The require statement itself is commented out so that it does not cause any problems. There are just a few rules to understand about the require statments.
If multiple files depend on a common file (as will be common with libraries such as jQuery), the common library will only be included once. You don't need to worry about the ordering in which Gracie includes the files. Gracie is smart. It will "just work". The only thing you can do wrong is to set up a cyclic dependency. Don't do that.
Gracie performs quite well. Here's why:
On a Core 2 Duo laptop with 4GB RAM, Gracie can handle about 800-1200 requests per second. Cached requests are served in no more than a few milliseconds, rising up to ~50ms when load is very high. Uncached minified requests take ~300ms. You could easily prime the cache if this is unacceptable for you. Unminified requests very fast even when uncached.
In these tests, Gracie only consumed one CPU and a small portion of the RAM. It could be beefed up a lot of needed by running multiple instances of Gracie using spark or cluster and of course by using more serious hardware or using multiple servers.