Skip to content

glesperance/node-rocket

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

!!! IMPORTANT NOTICE !!! Rocket is no longer maintained.

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

Rocket (node-rocket)

##The rapid development framework for node.js web applications

Node Rocket Rocks!

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.

RocketJS Features

  • 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

Installation

$ npm install rocket

Initializing Your Project

rocket -I MyRocketProject; cd MyRocketProject; npm update

Launching Your Project

While in your project's directory simply do :

node launcher.js

Directory Structure of a Rocket Project

./
|
|-- 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

Structure of the Client directory

./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.

Allow the browser to require() your javascript modules with ./client/js/

Structure of the client/js directory

./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.

Using jade templates in the browser

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 ! */
 
);

Requiring javascript files from a CDN via require.config.json

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...

Production mode & Optimizations

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.

Serving static files via ./client/static

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

Controllers

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.

Conventions on controller names

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.

Defining custom actions for your controllers

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

Exporting functions of a controller without mapping them to a route

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.

Auto-loading resource for your controller

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.

Now.js exports

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!');
  });
});

Models

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.

Locales

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 !'
}

Using locales in my controllers

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();
  
}

Using locales in my views

You can use the _ dynamic helper just like you would with jade-i18n.

Using locales anywhere (else)

The jade-i18n package is available through rocket.i18n and its _ dynamic helper is available through rocket._

Views

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().

Controller/Views mapping

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
       }

Bypassing view generation with XHR queries

In order to serve as RESTful access points, every controller returns JSON instead of its rendered view, when it is queried via XHR (ajax).

About

The rapid development framework for node.js web apps.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published