When a Locomotive application is started, it proceeds through a sequence of steps:
Configure the Environment
In this step, config/environments/all.js
is executed followed by the
configuration file for the current environment. For instance, when running
in development, config/environments/development.js
is executed.
Invoke Initializers
After the environment has been configured, initializers are invoked. Initializers are used to configure sub-systems and connect to databases, message queues, and other services utilized by the application.
Draw Routes
The routes in config/routes.js
are drawn.
Start HTTP Server
Finally, the HTTP server is started and the application begins handling requests.
An environment configuration exports a single function which is invoked when the application is started:
module.exports = function() {
this.set('view engine', 'ejs');
this.use(poweredBy('Locomotive'));
this.use(express.logger());
this.use(express.static(__dirname + '/../../public'));
this.use(express.cookieParser());
this.use(express.bodyParser());
this.use(express.session({ secret: 'keyboard cat' }));
this.use(passport.initialize());
this.use(passport.session());
this.use(this.router);
}
Within the function, the this
context is set to the application, which
conforms to the Express API.
Environments are typically used to configure settings and use middleware.
After the environment is configured, initializers are run. Initializers are identical to environments, in that they export a single function.
module.exports = function() {
// initialize something...
}
Initializers can also be asynchronous, in which case they accept a single done
argument that must be called once initialization is complete.
module.exports = function(done) {
// async initialize something...
setTimeout(function() {
done(); // or done(err) if an error occurred
}, 1000);
}
Within the function, the this
context is set to the application, which
conforms to the Express API.
Initializers are typically used to connect to databases and configure sub-systems. Each initializer executes sequentially, ensuring that the previous one completes before the next one is invoked.
The following initializer connects to MongoDB using Mongoose and defines models.
module.exports = function() {
switch (this.env) {
case 'development':
mongoose.connect('mongodb://mongodb.example.com/dev');
break;
case 'production':
mongoose.connect('mongodb://mongodb.example.com/prod');
break;
}
mongoose.model('User', schemas.UserSchema);
mongoose.model('Post', schemas.PostSchema);
}
The following initializer configures Passport strategies used for authentication.
module.exports = function() {
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.validPassword(password)) { return done(null, false); }
return done(null, user);
});
}
));
}