Please consider rocket to be no longer under active development. It is now only maintained and modified to support Wavo.me.
If you're still looking for a good development framework for node.js, please consider Meteor or the more mature Express Engine.
Rocket was a amazing experiment, and although I'd do things differently if I was to program it again, I am very proud of what has been achieved.
Finally, I'd like to thank all of those who supported the project and that helped me work on it.
Gabriel Lespérance
##The rapid development framework for node.js web applications
RocketJS.net a.k.a. node-Rocket is a project created by Gabriel Lespérance during the “Startupfier Summer Kick-off: Hackathon” in order to allow rapid development of real-time web applications using node.js.
Highly inspired by Ruby on Rails and cakePHP, Rocket puts forward the convention over configuration principle in order to simplify and speedup the software development process and allow easier scalability by leveraging node.js asynchronous behavior as well as its javascript nature.
Central to RocketJS is the principle of having a single point of contact between the programmer and the underlying application and resources. Hence, RocketJS aims to blur and reduce as much as possible the separation between the client (browser) and the server (node.js) while maximizing the scaling potential (for instance by allowing code sharing between the server and the client) and improving the performance of the resulting web application.
Built on top of express -- node.js’ high performance web development framework -- RocketJS provides a robust structure on which to build your web applications without sacrificing any of your freedom.
- Automatic routing of your controllers
- Automatic mapping of your views to their corresponding controller
- Easy web-socket / comet application support through dnode
- Easy server / client code sharing allowing the client to use RequireJS
require()
command to import/use server JS libraries - High focus on RESTful controller conventions
- Client-side support for jade template
- Automagic optimization of client javascript modules and CSS files
- Easy i18n localization
- Automatic reloading of modules when a modification is detected allowing easy and fast development.
- View rendering and partials support
- Connect middleware support
- Built on top of express
$ npm install rocket
rocket -I MyRocketProject; cd MyRocketProject; npm update
While in your project's directory simply do :
node launcher.js
./
|
|-- client
| # Contains all the files used by the client, including CSS, Javascript libraries and
| # static files.
|
|-- controllers
| # Contains your application's controllers.
|
|-- exports
| # Contains your application's modules that will be exported to the client.
|
|-- libs
| # Contains all your (other) application's libraries.
|
|-- locales
| # Contains all your localization files.
|
|-- models
| # Contains all your applications's models.
|
|-- views
| # Contains your applications's main layout, template files and associated
| # partials.
|
|- launcher.js
./client/
|
|-- css
| # Contains all the CSS files that are exported to the client.
|
|-- js
| # Contains all the javascript files that are exported (through requireJS)
| # to the client. All these files can then be accessed via `require()`
|
|-- static
# Contains all your static files.
./client/js/
|
|-- libs
| # Contains all your client side libraries used by your client modules.
|
|-- vendors
| # Contains all 3rd party libraries used by your application.
|
|-- templates
| # Contains all your client jade partial files
|
|- require.config.json
# This file contains all your custom requireJS modules paths
# configuration. This is extremely handy to make sure you always use
# the latest CDN version of a public module.
Each files/folders located under the ./client/libs/
directory of your project
are made available to the client's browser by Rocket via the require()
command.
The modules are referenced by their relative path from the ./client/js/
folder.
e.g. To require a module located at ./clients/js/a.js from the browser:
require(['./a'], function(a) { /* ... */ });
The modules can also be located further down the ./client/js
directory tree.
Hence you can require the file located at ./client/js/nested/dirs/b.js
by
doing :
//NB do **NOT** put the `.js` after the filename !!
require(['./client/libs/nested/dirs/b'], function(b) { /* ... */ });
Usual RequireJS conventions apply to the modules.
In view of reducing the friction between the programmer and its environment to a minimum, rocket allows the use of jade templates on the client side.
To do so, simply put all you jade partials files in the client/js/templates
directory and let rocket compile, and bundle those for you to use in the browser.
To use your template, simply require it and use it !
e.g. To use the template located at client/js/templates/dialog.jade
you do :
require(['jade-runtime', 'templates/dialog.jade'], function(__, dialog) {
var html = dialog({ title: 'Hello World !', message: 'This works!!' })
;
/* now use your compiled template ! */
);
In order to speedup page loads and to further comply to DRYness principles, rocket allows you to use CDN modules as if they were local, making sure you can still benefit from all the requireJS optimizations.
To do so you simply need to list those modules in your require.config.json file
located at the root of your client/js
directory.
E.g. to use the google's CDN jquery, jquery-ui and cdnJS's version of underscore, you'd need the following definitions in your require.config.json file :
{
"paths" : {
"jquery" : "//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min"
, "jqueryui" : "//ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min"
, "underscore" : "//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.1.7/underscore-min"
}
}
Note that we omitted '.js' extension for the modules...
To further optimize browser load times, you can start rocket in production mode by defining the following environment variable at start:
NODE_ENV='production'
When in production mode, rocket (1) bundles all your javascript client files at
the root of your client/js
directory with their dependencies, and then uglifies
them.
Thus, when those are used on the browser, only one request is needed to fetch them.
Rocket also (2) bundles your CSS files by resolving their @import statement. The resulting CSS files are also minified.
Note that since your client jade template are compiled before being sent to the browser, they are optimized too !
All those optimizations are provided by RequireJS r.js utility.
All files located under the ./client/static/
directory are statically served
by Rocket under the http://example.com/static/
URL.
Putting forth the use of conventions common to all Rocket projects, every
project is initially created with the following files/dirs in ./client/static/
:
./client/static/
|
|-- font
|
|-- img
|
|-- apple-touch-icon.png
|
|-- favicon.ico
By using a modified version of the powerful express-resource plugin, Rocket provides you with a robust way of automatically mapping your controllers to your routes.
Each time you launch your application, Rocket takes all the ./controllers/[controller_name]_controller.js
modules, and maps their exported functions as follows :
GET /[controller_name] -> index
GET /[controller_name]/new -> new
POST /[controller_name] -> create
GET /[controller_name]/:forum -> show
GET /[controller_name]/:forum/edit -> edit
PUT /[controller_name]/:forum -> update
DELETE /[controller_name]/:forum -> destroy
e.g.:
GET /forums -> require('./controllers/forums_controller').index
GET /forums/new -> require('./controllers/forums_controller').new
POST /forums -> require('./controllers/forums_controller').create
GET /forums/:forum -> require('./controllers/forums_controller').show
GET /forums/:forum/edit -> require('./controllers/forums_controller').edit
PUT /forums/:forum -> require('./controllers/forums_controller').update
DELETE /forums/:forum -> require('./controllers/forums_controller').destroy
Where {index, new, create, show, edit, update, destroy} are normal express callbacks functions :
function(req,res) { /* ... */ }
It is important to note that
./controllers/root_controller.js
is used as the /
controller.
For more info see the express-resource readme.
Controller names must :
- be plural
- be all lower case
- be underscored
- have a _controller suffix
Hence,
./controller/hyper_beams_controller.js
is valid whereas
./controller/hyper_beams.js
- and
./controller/hyper_beam_controller.js
are not.
In cases where you might need to derive from the RESTful conventions, Rocket provides to you a way to add custom actions to your controllers by mapping any exported function but {index, new, create, show, edit, update, destroy} as follows:
{GET, POST, PUT, DELETE} /[controller_name]/myAction ---------------> myAction
You can also be more specific in your mapping by making myAction
an object:
GET /[controller_name]/myAction/ ---------------------------------> myAction.get
/[controller_name]/myAction/:[singular_controller_name] ------> myAction.get
POST /[controller_name]/myAction/ ---------------------------------> myAction.post
/[controller_name]/myAction/:[singular_controller_name] ------> myAction.post
PUT /[controller_name]/myAction/ ---------------------------------> myAction.put
/[controller_name]/myAction/:[singular_controller_name] ------> myAction.put
DELETE /[controller_name]/myAction/ ---------------------------------> myAction.destroy
/[controller_name]/myAction/:[singular_controller_name] ------> myAction.destroy
By default Rocket ignores all exported functions prefixed with an underscore _
.
This can be used for example if you want to be able to require()
and extend a
base controller from which you want to inherit some property or methods.
It is possible -- via express-resource -- to auto-load the data associated with
a specific id
for your controller to use.
Simply put, this can be done by exporting the function in question as_load
in
the controller module.
Auto-loading functions take the following form:
exports._load = function(id, cb) {
var err
, obj
;
//(1) -- load the object with the specified id
//(2) -- call the callback
cb(err, obj);
}
For more info see express-resource readme.
By using nowjs, rocket allows you to export server objects and make them accessible to the client.
To export a module, simply create a javascript file in your exports
directory
and rocket will automagically, export it for you.
e.g.
The exports/chat.js
file :
exports.sendMsg = function(msg) { /*...*/ }
will be accessible through nowjs in the client by doing :
require(['now'], function(dnode) {
now.ready(function() {
now.chat.sendMsg('Hello world!');
});
});
Starting with version 0.1.x, rocket is database agnostic. If you're looking forward to using a noSQL DB, we recommend you to use mongoDB in conjunction with mongoose.
Essential to any production application is the need to have localization support.
As with controllers and views, rocket puts forward conventions that will allow you to better manage your projects, making sure everything is at its right place.
To do so, rocket leverage the jade-i18n library by taking each javascript
packages it finds in the ./locales
directory and then define the phrases it contains.
For example, to define the phrase WELCOME_MESSAGE in en_CA you simply create
a file named en_CA.js (in the ./locales
directory) containing the following:
module.exports = {
WELCOME_MESSAGE : 'Hello world !'
, GOODBYE_MESSAGE : 'Bye world !'
}
One of the suggested pattern to better leverage jade-i18n in your controllers
is to use a middleware in order to (1) Detect the language of the client and (2)
provide a version of rocket._
(jade-i18n _
helper) with a pre-appended
lang
argument in order to allow your controllers to simply call req._
to
translate messages in the client's language.
Such middleware would look like :
function(req, res, next) {
var current_lang = guessLang(req)
;
req._ = function(text) {
return rocket._(current_lang, text);
}
next();
}
You can use the _
dynamic helper just like you would with jade-i18n.
The jade-i18n package is available through rocket.i18n
and its _
dynamic
helper is available through rocket._
Rocket takes care of matching your views to your controllers so you do not have to define these redundant relationship.
Controllers without view simply returns the JSON passed to res.send()
.
Rocket maps controllers to their views in the following way :
./controllers/root_controller.js
|
|- exports.index = function(req,res) { /* ... */ } --> views/root/root.index.jade
|
|- exports.custom = {
get : function(req, res) { /* ... */ } --> views/root/root.custom.get.jade
, post : function(req, req) { /* ... */ } --> views/root/root.custom.post.jade
}
In order to serve as RESTful access points, every controller returns JSON instead of its rendered view, when it is queried via XHR (ajax).