Code Monkey home page Code Monkey logo

locomotive's Introduction

Locomotive

Build Coverage Quality Dependencies Tips

http://locomotivejs.org

Locomotive is a framework that brings structure and MVC patterns to web applications using Node and Express.

Installation

$ npm install locomotive

Quick Start

lcm, the command line interface to Locomotive, can be used to generate a starter application. To use it, install Locomotive globally.

$ npm install locomotive -g

Next, create an application and install dependencies.

$ lcm create hello
$ cd hello
$ npm install

Start the server.

$ lcm server

The application is available at localhost:3000.

Start the server with node debug mode

$ lcm server --debug (node --debug mode)
$ lcm server --debug-brk (node --debug-brk mode)

Then you can use debug tools like node-inspector to debug your application as usual.

Guide

The Locomotive Guide is the official source for documentation, and is a handy reference to have available when developing web applications powered by Locomotive.

Datastore Adapters

AdapterDescriptionDeveloper
MongooseMongoose ODM adapter.

Tests

$ npm install
$ make test

Credits

License

The MIT License

Copyright (c) 2011-2017 Jared Hanson <http://jaredhanson.net/>

Sponsor

locomotive's People

Contributors

aejay avatar bs91 avatar deniswolf avatar djensen47 avatar drudge avatar duro avatar gabrielf avatar gh-naylor avatar goddyzhao avatar gothack avatar gotoplanb avatar gstoyanov avatar haxney avatar jameswyse avatar jaredhanson avatar kerihenare avatar kuryaki avatar mekka avatar oldcookie avatar pixelfreak avatar robertklep avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

locomotive's Issues

Allow reuse of environments/initializers across web and worker applications

I think it would be useful to break out the initialization process Locomotive uses so that it can be used in non-web applications as well.

For example, I have a worker process which performs task on a schedule. I would like my job definitions to have the same environment that works so well in my accompanying web app. You can see this in action here: https://gist.github.com/e599a4fe6ff81efea82e

I think the idea is good, but the implementation can/should be more flexible.

Things that would be nice:

  • Selectively loading initializers. There may be initializers used in the web app that aren't needed or aren't compatible with a specific worker.
  • Automatic no-opping of web-specific methods like helpers, dynamicHelpers, engine, locals, etc.

Allow invoking actions from other controllers/middleware

Per our conversation, I think there should be a way to invoke actions from within a controller or express middleware. This would be useful for handling errors, etc.

  • Within a controller, this.invoke() and forward the current req and res objects
  • Outside of a controller, use the longer locomotive.invoke()(req,res,next) way

Alter code before and after to accept array actions

Sample:

PagesController.before(new Array("show","main") , function(next) {
this.title = 'Test';
this.user = this.req.user;
next();
});

Changed the code Controller.js

Before
if (action.constructor === Array) {
_this = this;
action.forEach(function (value) {
_this.pre(value, filter);
});
} else {
this.pre(action, filter);
}

After

if (action.constructor === Array) {
_this = this;
action.forEach(function (value) {
_this.post(value, filter);
});
} else {
this.post(action, filter);
}

Is locomotive active ? And what about cluster?

Hi Jared,

Are you still working with locomotive ? I find it very good and easy to get up and running so a big thanks to you. But with Express 3.0 and future versions coming i am wondering what will happen with locomotive ?

I like the simple design of your MVC-architecture, mabey the geedy models can be handy sometimes, but having a good js framework on the client (like extjs) can overcome this instead.

Also, i am missing an app.js file to bind the models, views and controller and define globals like:

locomotive.application({
name: 'myApp',

appFolder: 'app',

controllers: [
'Users'
],
models:[
'Users''
],
launch: function() {
..
}

In here i would like to use some native nodejs function like cluster etc.How do use use cluster/workers with locomotive ?

After all, doing some work just to learn is fine, but do i dare to use locomotive on a real web app ?

Using Express' vhost with Locomotive

I am trying to use Express' vhost with Locomotive. I am following the example here and I am stumped because in the example, the vhost function expects an express app in the 2nd argument, like so:

app.use(express.vhost('localhost', myApp));

But in Locomotive, the app is created inside the boot function and is not available until the callback returns. What is the right way to do this? Thanks!

Add LESS support to documentation

This is just a suggestion, but it would be helpful to document that switching to LESS (and presumably Stylus and others) is a simple install and one-line configuration change.

this.use(require('less-middleware')({ src: __dirname + '/../../public' }));

I'm just getting familiar with node and I ended up pulling that line from a server generated by the express CLI.

Helpers not available outside controllers

I was trying to find the best way to handle showing pretty error pages in my app. I've done the usual express error handler middleware after the router, but none of my helpers are available there. I'm using helpers for things like localization.

My thinking is it would be the cleanest to handle this with a controller, rather than force a middleware. I thought something like this in routes would be nice:

this.match('*', { controller: 'error', action: 'show' , via: '*' });

The only issue here is that there there is no access to the error that has been next()'d. Perhaps it could be passed to a controllers action?

ErrorController.show = function(err) {
  if (!err) {
    this.redirect('/');
    return;
  }

  switch(err.status) {
    case 403:
      this.title = 'Access Forbidden';
      this.render('403');
      break;
    case 404:
      this.title = 'File Not Found';
      this.render('404');
      break;
    default:
    case 500:
      this.title = 'Error';
      this.render('500');
      break;
  }
};

What do you think is the best way to handle this?

More useful error messages from controllers?

Right now, if I throw an exception in the body of a controller file (not inside an action function) or if something is wrong with the syntax, I simply get a "500 RouterError: No controller for..." Not a very useful error message.
I don't know if this is possible to fix, or if it's an issue with how node is laid out and how locomotive is designed, but this is causing me a lot of unnecessary headaches.

Changing middleware parameters in environment config

I've found several situations where it would be helpful to be able to change configuration parameters passed to middleware in environment-level configuration files. What do you think about something like the following? (I don't like the function names, but just an example.)

In all.js

this.placeholder('session', express.session, { secret: 'foo' });

In some environment, e.g. development.js

this.update('session', { secret: 'bar' });

The first parameter to placeholder is a key which can be referenced in the environment config, the second is a middleware factory function, and the last is a dictionary of options. This dictionary gets updated in the environment config. As far as implementation goes, I think this.placeholder could return a function which, the first time it was called, executes the middleware factory function with the final option dictionary and caches the result.

Controller name clash when using Locomotive with Express vhost

I have multiple Locomotive apps on multiple domain with Express vhost. If I use the same controller filename on multiple apps, they seem to override each other.

Is there a way to fix this? Maybe Locomotive should store the full path of the filename instead when registering them?

Rendering middleware

Was thinking about adding some sort of rendering middleware to dynamically alter rendering behaviour.

Some use cases I have in mind are:

  1. Web components a la web2py - Load an action with a .load extension, in which case the page is rendered without a layout, using the template action.load.ejs. (Assuming you are using ejs as the view engine.)
  2. Json rendering - Specify "json" or "api" somewhere int he url i.e. user/edit.json or api/user/edit and have those rendered accordingly.

I can do it by wrapping Controller.render() with my own render function, but thought it would be a nice feature to have within the framework. It's really more a way to auto select rendering options based on request parameters, rather than having to pass them in explicitly on each action. Something akin to controller filters would probably work.

Any opinions on this?

Locomotive and MySQL

Is it possible to use Locomotive with MySQL? I read on Stack Overflow that you can't, but that Locomotive might not be related to this one :)

If it does work, do you have any recommendation on what module I should use?

Thanks!

Content blocks not rendered in Jade

Using "extends layout" in Jade subviews will render the specified layout, but not the subview's content block. I hope I'm just doing something wrong.

Better support for "limited" route parameters

Routing:

this.namespace('objects/:type', function () {
  this.match(':id', 'objects#show');
}

Works well when generating urls:

this.urlFor({ controller: 'objects/objects', action: 'show', type: 'my_type', id: 'my_id' });

But:

this.namespace('objects/:type(my_type|another_type|that_type)', function () {
  this.match(':id', 'objects#show');
}

using the same urlFor call generates:

/objects/:type(ping%7Chttp%7Chttps)?/my_id

TypeError: Cannot read property 'html' of undefined

I'm running node 0.8.8 on Ubuntu 12.04 64 bit.

Steps to reproduce:

lcm create loco
cd loco && npm install

Both run without errors.

lcm server

then opening the root results in

Express
500 TypeError: Cannot read property 'html' of undefined

    at Controller.render (/home/alex/loco/loco/node_modules/locomotive/lib/locomotive/controller.js:115:34)
    at Controller.PagesController.main (/home/alex/loco/loco/app/controllers/pages_controller.js:8:8)
    at Controller._invoke (/home/alex/loco/loco/node_modules/locomotive/lib/locomotive/controller.js:360:15)
    at Locomotive. (/usr/lib/node_modules/locomotive/lib/locomotive/router.js:417:14)
    at callbacks (/usr/lib/node_modules/locomotive/node_modules/express/lib/router/index.js:272:11)
    at param (/usr/lib/node_modules/locomotive/node_modules/express/lib/router/index.js:246:11)
    at pass (/usr/lib/node_modules/locomotive/node_modules/express/lib/router/index.js:253:5)
    at Router._dispatch (/usr/lib/node_modules/locomotive/node_modules/express/lib/router/index.js:280:5)
    at Object.middleware [as handle] (/usr/lib/node_modules/locomotive/node_modules/express/lib/router/index.js:45:10)
    at next (/usr/lib/node_modules/locomotive/node_modules/express/node_modules/connect/lib/http.js:204:15)

Any idea?

Please drop the convention to name templates *.html.ext (ie. options.format in controller.render)

I realize that Locomotive is going the convention over configuration route, but this is a convention which I believe is overly opinionated and unnecessary. I use Jade and I don't see any advantage to being forced to name my templates according to a name.html.jade pattern. The alternative, namely specifying every template name and an options object on every call to render, is no more attractive.

Enforcing this convention also goes against the template lib's conventions creating potential confusion. For example, I'd normally name my layout template layout.jade. I'd reference that in partials like so:

extends ../layout

With Locomotive, I either have to use a mixed naming scheme, or go against Jade's convention and reference my layout like so:

extends ../layout.html

I propose that this convention should be removed as it adds no real value to Locomotive and forces users to break the conventions of their template library of choice.

Running multiple Locomotive apps using http-proxy?

I'm having problems running Locomotive through a proxy. My http-proxy server runs on port 80 then routes a domain name to local lcm server on port 1234, but the server crashes unless I visit the app by explicitly appending the port to the url (e.g. foo.com:1234).

Before realizing I could post here on github, I a question with detail on stackoverflow: stackoverflow.com/questions/13522708

Creating dynamic and static helpers

Hi,

I've tried to find out how to create helpers in Locomotive but can't get my head around it.

Can someone please explain it and then add it to the README?

Thanks,

Viktor

Development/Production variables

It doesn't seem like you can declare variables in the production.js/development.js files and then use them in the initializers since the environments get loaded after the initializers.

I was looking at the locomotive boilerplate app in its use of passport.

Move generators and tasks to grunt.js

I'm willing to write the code for this but I wanted to make sure that people thought it was a good idea first. I think that we should move the server tasks as well as the generator to a locomotive grunt.js plugin

Major Wins

  • Developers get sane defaults but can customize the behavior how they want
  • The sample app can be removed out from being generated by default
  • We can create a snippet directory similar to Padrino's recipes

If people like this, I will write the patches to locomotive to remove that behavior and have it load grunt.js by default. Some things that I will do in the first release are

  • Configure grunt to handle assets correctly
  • Generators for models and routes
  • Generate client side helpers

Allow dash for folder and file names?

If I do this:

this.match('find-a-product', 'find-a-product#index');

It'll look for views/find_a_product/index.jade. Is it possible to use dash instead?

Is it a common naming convention in Node.js to use underscore?

Thanks!

Form validation

I'm looking for a way to do form validation. My situation is as follows (I'm pretty new to node dev, so I may not be doing things entirely right, but here we go...)

I have a 'create' route on a controller as follows:

AccountsController.create = function() {
  var account = new Account();
  account.email = this.param('email');
  account.password = this.param('password');

  var self = this;
  account.register(function (err) {
    // There was a validation problem!
    return self.redirect(self.urlFor({  action: 'new' }));
  },function(model){
    // we're good - the model was created... crack on.
    return self.redirect(self.urlFor({ action: 'login' }));
  });
};

Account is a mongo model - The register method should probably be static, but I think the general gist is there...

If register returns validation problems (from mongo - lack of required fields etc) they are contained in the err argument passed to me fail callback.

I think I would like to register the problems on the response then redirect and have them available in the view. eg:

account.register(function (err) {
    self.addFormErrors(err);
    return self.redirect(self.urlFor({  action: 'new' }));
  },function(model){
    return self.redirect(self.urlFor({ action: 'login' }));
  });

addFormState method adds the errors object to some property available in the view -> in this case it is the mongo error - probably not so cool because I don't want to couple to mongo error messages... I think error object available on the view needs to be an array of something like:

{ formFieldName: 'email', errorMessage: 'email address required'}

Does this seem a reasonable approach?

if so I am up for having a punt at creating some code for this sort of thing, or helping out on an effort. As I said - new to node, so may not get it right, but I can have a go.

Do you think there are any other requirements form validation might need, or perhaps a better way of addressing this problem?

Thanks!

Paul

Allow namespace'd id params to be overridden.

For example, these routes:

this.match('devices/:deviceLibraryIdentifier/registrations/:passTypeIdentifier', 'registrations#index');
this.match('devices/:deviceLibraryIdentifier/registrations/:passTypeIdentifier/:serialNumber', 'registrations#create', { via: 'post'});
this.match('devices/:deviceLibraryIdentifier/registrations/:passTypeIdentifier/:serialNumber', 'registrations#destroy', { via: 'delete'});

could be declared using namespaces, except namespaces would use params:

device_id
pass_id
id

Create a server.js file to allow running on Heroku

As per title, need server.js to enable running a loco app on Heroko (or using nodemon etc for development)

What are the benefits of being forced to run lcm server to run the app?
To me, seems like overhead?

Sample Project

Is there any sample locomotive project I can look at to better understand the framework? Something that's more than the auto-generated files.

Thanks!

Forward render

It would be helpful to forward render to express. In my case, I'm looking to use this for sending email.

Allow error handling middleware in before/after actions

Currently, only function(req, res, next) style middleware is being handled.

See https://github.com/jaredhanson/locomotive/blob/master/lib/locomotive/controller.js#L425 and https://github.com/jaredhanson/locomotive/blob/master/lib/locomotive/controller.js#L476

Here is the code I was testing with:

SomeAPIController.after('*', function(err, req, res, next) { .. });
  if (!err) {
    return next();
  }

  this.response.send(500, {message: err.message});
});

Add Cluster Support

Since the API for node cluster has settled down, we should get cluster support built into locomotivejs.

@jaredhanson If you can provide some insight into implementing this, I could take on the work.

Docu for config/initializers

Currently I have a models.js file which does the Mongoose Schema creation and exports the models. I'm requiring the models.js in every controller.

How would I use config/initializers to make this easier? When I put the models.js inside and have the following code:

module.exports = function() {
    this.models = {
        User: User
    };
};

how do I access my model in the controller? Because I guess in the function this is the app, whereas inside the controller functions it's specific to the current request. Is the app exposed inside the controllers?

Pipes

Hello, Jared

Do you plan to add deployment pipes functionality into this framework.

  1. Bundling & minimization of front-end javascript/css.
  2. Deployment to popular hosting services: Heroku / SFTP.
  3. Deployment statics to Amazon S3?

Thanks,
Vyacheslav

file watching...

I think it would be good to have the 'lcm server' command fire nodemon so we get recompilation (or whatever it is in node world) when a file changes.

Boot sequence change breaks initializers

Just upgraded Locomotive and found that my initializers are running after the environment setup which breaks my setup as Mongoose, Passport, etc are being initialised after the app. Is this the intended new order or can we revert this back to the original? If it's how things will work from now on I'm going to have to modify a few apps :P

Error handling is broken in the controller

Hey guys,

Taking a look at the controller error handler

Note that err and e when logged are both null. This stops any error handling middleware useless since they bypass null errors.

Controller.prototype.error = function(err) {
var self = this;
// Give controller-level after filters an opportunity to handle the error. If
// not handled, pass control out to Express for application-level handling.
this._devoke(err, function(e) {
console.log('Calling middleweare', err, e);
return self.__next(e);
});
}

FIX::: Controller.prototype._invoke = function(action) {
...
...
Line 451
try {
selfaction;
return;
} catch (e) {
return self.error(err); <-------- Should be e
}

Support for HTTP PATCH

Backbone 0.9.10 provides support of HTTP patch.

And locomotive.js - does not.

Any changes about this?

Can't use all.js, development.js, production.js for error handling?

I am trying to write a middleware error handling where in all environments the same output response is produced and on production, an extra logging is performed.

I find that this is not doable in the environment js since if you do a response.send in all.js, next(err) will no longer work, therefore development.js and production.js will not get hit. You can call next(err) before response.send, but that will change the order of things.

In general, error handling should be handled at the bottom of all other middlewares. So what I end up doing is creating a 99_error.js file inside /initializers and handle everything there.

Do you think this is the right way to do it or is there a better one?

Thanks!

Middleware defined in router

Been thinking and playing some more and have come across a scenario where I need to disable csrf on a particular route. Even in express this is difficult, but you can add routes with the csrf middleware attached to each one (painful, but logical).

Would it be possible to create routing something like the below?

var csrf = express.csrf();

this.root('pages#main');

this.resource('account', csrf, function () {
  this.resources('blah');
});

Just an idea, would make routing & middleware more flexible :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.