Uglify
is a pretty nifty javascript minifier but it also has the lesser-known ability
to generate and walk the AST.
Unfortunately, uglify's traverser is
a bit cumbersome to use
so I wrote a library using
my own traverser
to make it easy!
Introducing
burrito,
a crazy new library to make AST traversals and manipulations crazy easy.
Given this snippet of code:
f() && g(h());
foo();
It's super easy to wrap all the function calls in another function call,
qqq():
var burrito = require('burrito');
var src = burrito('f() && g(h())\nfoo()', function (node) {
if (node.name === 'call') node.wrap('qqq(%s)');
});
console.log(src);
$ node wrap.js
qqq(f()) && qqq(g(qqq(h())));
qqq(foo());
Or maybe dive in and surgically replace that
&&
with a
||, how about!
var burrito = require('burrito');
var src = burrito('f() && g(h())\nfoo()', function (node) {
if (node.name === 'binary') node.wrap('%a || %b');
});
console.log(src);
$ node wrap.js
f() || g(h());
foo();
Plus you can .microwave() your burrito too, which
evals the code using node's vm.runInNewContext()
(which even runs in the browser thanks to
browserify).
var burrito = require('burrito');
var res = burrito.microwave('Math.sin(2)', function (node) {
if (node.name === 'num') node.wrap('Math.PI / %s');
});
console.log(res);
This snippet takes the expression Math.sin(2) and
replaces the 2 with Math.PI /
2 thanks to some %s interpolation.
And since Math.sin(Math.PI / 2) evaluates at 1, the code should print as much...
$ node microwave.js
1
And it does! Hooray!
This craziness makes an amazing number of things possible, like
stack traces
that work in all the browsers without relying on a stack trace API or code
coverage tools without any binary extensions!
Give burrito a spin!
npm install burrito
or get the code on github!
Just off the plane from the first ever nodeconf
where I
gave a talk
about dnode
culminating in a
live dnode-powered markov rap battle,
I headed down to
Music Hack Day, San Francisco
with Marak to represent node.js.
Music Hack Day is a 24 hour hacking contest for musical hacks.
I got in late but stayed the whole night and managed to hack up
singsong,
interface on top of festival's little-known singing voice synthesizer plugin.
You can click on the staff to plop notes down and then use the text boxes
below to associate bits of text with them.
Sample output:
[ ogg ]
|
[ wav ]
It's not quite ideal since you've got to break up the words by syllables
yourself. I wrote
a lib
that can do this automatically but didn't hack it in.
Good enough for 24 hours at least.
Check it out on github.
Announcing browserify,
a node.js module that bundles up all your javascript into a single file so you
can use node.js-style require() from the browser.
Check this:
server.js
var connect = require('connect');
var server = connect.createServer();
server.use(connect.static(__dirname));
server.use(require('browserify')(__dirname + '/js'));
server.listen(9797);
js/foo.js
var bar = require('./bar');
module.exports = function (x) {
return x * bar.coeff(x);
};
js/bar.js
exports.coeff = function (x) {
return Math.log(x) / Math.log(2) + 1;
};
index.html
<html>
<head>
<script type="text/javascript" src="/browserify.js"></script>
<script type="text/javascript">
var foo = require('./foo');
window.onload = function () {
document.getElementById('result').innerHTML = foo(100);
};
</script>
</head>
<body>
foo = <span id="result"></span>
</body>
</html>
Then fire up the server (node server.js) and load up
http://localhost:9797/

Amazing! Browserify just hosted all of those files at
/browserify.js and made
require() work just like in node.js!
But wait! There's more! You can specify npm modules to use and then you can
require() those too! Just pass the "require" parameter
to browserify:
server.js
var connect = require('connect');
var server = connect.createServer();
server.use(connect.static(__dirname));
server.use(require('browserify')({
require : [ 'traverse' ]
}));
server.listen(9797);
Then spew out some HTML:
index.html
<html>
<head>
<script type="text/javascript" src="/browserify.js"></script>
<script type="text/javascript">
var Traverse = require('traverse');
window.onload = function () {
var obj = { a : 1, b : [ 2, 3, 4 ], c : [ { d : 5, e : 6 } ] };
var leaves = Traverse(obj).reduce(function (acc, x) {
if (this.isLeaf) acc.push(x);
return acc;
}, [])
;
document.getElementById('result').innerHTML = leaves.join(', ');
};
</script>
</head>
<body>
<span id="result"></span>
</body>
</html>
Then fire up the server and check http://localhost:9797/

Success! It pulled out the leaves from that pesky nested data structure using
traverse!
If the npm modules have dependencies, those dependencies will get bundled along
recursively!
Plus, browserify looks for the "browserify" field in
package.json files up on
npm, so you can serve up custom browser versions
of packages. Here's the "browserify" part of
dnode's package.json:
"browserify" : {
"name" : "dnode",
"main" : "./browser/index.js",
"base" : "./browser",
"require" : [ "dnode-protocol" ]
},
With this field in the package.json and "dnode" in the "require" list,
require('dnode') serves up the browser-side dnode
code!
Here are some packages that have been tested with browserify:
And that's not all!
-
Browserify bundles with
es5-shim
by default so you can use shiny new javascript features like
Function.prototype.bind()
even if your browser doesn't have those yet!
-
You can specify post-filters on the bundled source to run your code
through javascript minifiers!
-
If you have
.coffee
files in your base directory they are parsed automatically so you can
require() them too!!
-
Browserify comes with compatability wrappers so you can
require('events').EventEmitters,
require('path'),
and process.nextTick()
just like in node.js, to name a few!
What an amazing amount of features!
Check it out on github!
Want to make sure your browserified code runs on all the browsers?
Check out my startup, browserling!
Cross-browser testing from your browser!
I gave a talk at parisoma in San Francisco about
dnode, my asynchronous RPC system that we use at my startup, browserling.
Check out the slides or the LaTeX source used to generate the slides below:
Fuck yeah, callbacks!
The node.js community has been growing like crazy with 995 packages on
npm at the time of this writing.
$ npm --loglevel=silent ls latest | wc -l
995
For fun I graphed the dependencies between npm modules with
graphviz.
Here are the results with the fdp and twopi graphing algorithms:
Check out the code on github
Or npm install npmdep!