Beans: Rubygems for Javascript

December 8, 2009
Javascript does not generally natively allow loading dependencies. This tends to mean that Javascript development is less modular than it could/should be. Code is ‘copied and pasted’ rather than ‘required’, which leads to code drift.
Beans is a development tool that attempts to fix this, by bringing Rubygems-like functionality to Javascript development, using a local (beans) server to act as the equivalent binary (e.g. gem), in particular Beans:
  • can be used in any environment (Ruby, Python, HTML).
  • has automatic dependency resolution, both global and relative
  • can be accessed from any page or server, even a vanilla HTML page
  • scripts are included simply by using <script> tag
  • javascripts are provided either as
    • a single concatenated script (e.g. for production)
    • multiple separate scripts (e.g. for debugging in development)
  • Entirely cross browser and works well with tools such as Firebug

Interacting with Bean Server

A Sinatra server (perhaps it should be a Node server :-) acts as a system wide provider for the javascript.

I tend to run the server under Passenger, and have it associated with http://beans/

http://beans/

  • Returns HTML page listing each file in the repos

http://beans/?.js

  • Returns HTML page showing each file who’s path matches “.js”

http://beans/path/to/my_file.ext

  • Finds a file with path /path/to/my_file.ext and returns it inline
  • This can be js, css, jpg or any file
  • No dependency resolution will occur
  • If there’s more than one repo that matches, it will return the first it finds

http://beans/=lib_a.js,lib_b.js

  • Searches the repo for two files, who’s paths matches lib_a.js and lib_b.js
  • If the files are javascripts, it will resolve dependencies (see below).
  • In this instance, let’s say that
    • lib_a depends on dep1, dep2
    • lib_b depends on dep1, dep3
  • Therefore the final scripts to load in order will be
    • dep1, dep2, lib_a, dep3, lib_b
  • There are multiple scripts to return, it will return a single script that writes out inclusion via document.write:
  • <script src=’http://beans/path/to/dep1.js’ ></script>
  • <script src=’http://beans/path/to/dep2.js’ ></script>
  • <script src=’http://beans/path/to/lib_a.js’ ></script>
  • <script src=’http://beans/path/to/dep3.js’ ></script>
  • <script src=’http://beans/path/to/lib_b.js’ ></script>

http://beans/=lib_a.js,lib_b.js?concat=true

  • If the option concat=true is passed, the bean-server will return the scripts as a single concatenated script.

http://beans/=lib_a.js,lib_b.js?paths=/abs/path,/abs/another/path

  • The paths option allows multiple temporary (absolute) load path

Dependencies

The syntax for declaring dependencies is the similar as Sprockets, ie they are entered within inline comments.
A slight difference is that the comments must be placed at the top of the file, before any code. This is because of the way Beans can provide each script separately and also speeds up the script parsing as the server can break as soon as a non-code line is reached.

//= require <my_lib>

This will do a global search in all load paths for a file matching my_lib.js and include it before this script

//= require “relative/path/to/my_file”

This will look for a file relatively to the current script.

Installation

git clone git://github.com/weepy/bean-server.git
cd bean-server
ruby app.rb

point browser at http://localhost:4567/test-beanz.html

Config

Currently there’s a simple settings.rb file that only contains the location of various repos

Javascript, CSS and HTML

The beans server is designed for serving particular javascript, however it can also search for and server css and HTML. E.g. http://beans/qunit/lib/test-suite.css will server up the Qunit test suite css. This is useful, among other things for writing and running tests in HTML to be bundled along with the source.

Comparison with other systems

Sprockets tries to achieve similar but not identical goals:

  • Beans uses a similar dependancy syntax as Sprockets
  • Beans is not tied to any language or framework, whereas Sprockets is invoked from Ruby
  • Sprockets includes the Javascript by concatenating into one single file. Beans can do this or optionally include each script as a separate file for ease of debugging.
  • Beans doesn’t (yet?) support providing assets from javascripts, although the server can search and return any other type of file
CommonJS
  • CommonJS provides a framework using require and exports
  • It is functionally different from Beans as it inserts the files into a closure, where as Beans evaluates everything in the global scope
  • CommonJS is suited more to server side development, whereas Beans is aimed at client side development (tho it can be used server side e.g. I’m using it on ChessTwit)

Project

Github: http://github.com/weepy/bean-server

Todo

Potential features that are not yet addressed:

  • Versioning, ownership
  • Canonical external resource (e.g. rubyforge, gemcutter)
  • minification
Advertisement

4 Responses to “Beans: Rubygems for Javascript”

  1. Ricardo Says:

    nooo! get rid of document.write! this sounds great.

  2. foxparker Says:

    Document write actually works really well here. If you set concatenation on, it’s not used.


  3. [...] Beans: Rubygems for Javascript « ninja sumos (tags: javascript webdevelopment) [...]

  4. Dana Gottron Says:

    Hey, I found this blog article while searching for help with JavaScript. I have recently switched browsers from Opera to Microsoft Internet Explorer 5. Now I seem to have a problem with loading JavaScript. Everytime I go on a page that needs Javascript, the site doesn’t load and I get a “runtime error javascript.JSException: Unknown name”. I cannot seem to find out how to fix it. Any aid is greatly appreciated! Thanks


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.