Start an Express.js web server using grunt.js
JavaScript
Pull request Compare This branch is 2 commits ahead, 63 commits behind blai:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
lib
tasks
test
.editorconfig
.gitattributes
.gitignore
.jshintrc
.npmignore
.travis.yml
Gruntfile.js
README.md
package.json

README.md

grunt-express Build Status

Start an express/connect web server. This plugin is largely based on grunt-contrib-connect. It aims to solve the following use cases that grunt-contrib-connect does not seem to have an answer for:

  1. Enabling custom express/connect server, especially in cases when socket.io is in the mix (https://github.com/yeoman/express-stack/issues/15#issuecomment-13217532)
  2. Watch for changes to the server script(s) and restart the express/connect server (https://github.com/yeoman/express-stack/issues/7)

Sample app

grunt-express-example is a minimal example that shows how you can use grunt-express to run a basic express/socket.io server set. It will auto-restart server when change is detected.

Philosophy

The philosophy behind the birth of this mutant of grunt-contrib-connect is:

  1. Flexibility. I learned a few lessons from working on some enhancement to Yeoman's server task. Express.js and Connect are so flexible that the only way to accommodate their full flexibility seems to be accepting a custom module that actually exports such object. An extreme case of this comes from Socket.io, which forces http.Server, express/connect, and socket.io be instanciate in a very specific way.
  2. Grunt/Yeoman is mainly for development/deployment. When rung web server in dev environment, following features are in high demand:
    • auto-rebuild/auto-reload (both web browser and server), livereload solved only half of this demand. While it may not be common, livereload on the browser end is also a demand for production environment, so I prefer using tiny-rl to manage that in my server bootstrap script, rather than a grunt task.
    • use different base directories where static contents are served. Since development/deployment process is managed by a set of grunt task (and some of the tasks are opinionated), it would seem logical to let grunt task decide which directories to load static contents from.

Getting Started

This plugin requires Grunt ~0.4.0

If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:

npm install grunt-express --save-dev

Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:

grunt.loadNpmTasks('grunt-express');

Express task

express (main task, Multi Tasks)

Run this task with the grunt express command.

Configure one or more servers for grunt to start, the minimal config would be:

  grunt.initConfig({
    express: {
      default_option: {}
    }
  });

  grunt.loadNpmTasks('grunt-express');

  grunt.registerTask('default', ['express']);

express-stop

You may use this to stop one (or all) of the servers you have specified in express main task. If you do grunt.task.run('express-stop'), it will go ahead and stop all servers started by express multi task. You may also stop a particular server using grunt.task.run('express-stop:SERVER_NAME')

express-restart

Similar to express-stop, except that your server will be started again after stopping.

express-keepalive

Note that this server only runs as long as grunt is running. Once grunt's tasks have completed, the web server stops. This behavior can be changed by appending a express-keepalive task at the end of your task list like so

grunt.registerTask('myServer', ['express', 'express-keepalive']);

Now when you run grunt myServer, your express server will be kept alive until you manually terminate it.

Such feature can also be enabled ad-hoc by running the task like grunt express express-keepalive.

This design gives you the flexibility to use grunt-express in conjunction with another task that is run immediately afterwards, like the grunt-contrib-qunit plugin qunit task. If we force express task to be always async, such use case can no longer happen.

Options

port

Type: Integer Default: 3000

The port on which the webserver will respond. The task will fail if the specified port is already in use.

hostname

Type: String Default: 'localhost'

The hostname the webserver will use.

bases

Type: String|Array Default: '.'

The bases (or root) directories from which files will be served. Defaults to the project Gruntfile's directory.

monitor

Type: Object Default: null

Under the hood grunt-express uses forever-monitor to manage individual servers in separate child processes. This makes restarting the server automatically possible. This property allow you to pass in the forever-monitor options. When specified, the object will be used as the options hash when creating the forever monitor to manage the server in child process.

keepalive (WARN: no longer availabe in 0.20+)

Please use a trailing express-keepalive task instead

Type: Boolean Default: false

Keep the server alive indefinitely. Note that if this option is enabled, any tasks specified after this task will never run. By default, once grunt's tasks have completed, the web server stops. This option changes that behavior.

debug

Type: Boolean Default: false

Turning this option on will make the "supervised" express|connect instance output more debugging messages.

server

Type: String Default: null

This option allows you to specify a path to a Node.js module that exports a "connect-like" object. Such object should have the following two functions:

  1. use(route, fn) (https://github.com/senchalabs/connect/blob/master/lib/proto.js#L62)
  2. listen() (https://github.com/senchalabs/connect/blob/master/lib/proto.js#L227) note: you DO NOT want to call the listen() from within your server module, express task will take care of that for you

The simplest example would be:

var connect = require('connect');
module.exports = connect();

or if you prefer express.js

var express = require('express');
var app = express();
app.get('/', function(req, res) {
  res.send('hello!');
});
module.exports = app;

or if you want to use both express and socket.io

var app = require('express')()
  , server = require('http').createServer(app)
  , io = require('socket.io').listen(server);

app.get('/', function (req, res) {
  res.sendfile(__dirname + '/index.html');
});

io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});

exports = module.exports = server;
// delegates user() function
exports.use = function() {
  app.use.apply(app, arguments);
};

When server option is not set, express task will generate a plain connect object for you.

note: express task will generate static and directory middleware for each of the bases you specified, and load them onto your server (or the generated server) object by calling use() function

Usage examples

Basic Use

In this example, grunt express (or more verbosely, grunt express:server) will start a static web server at http://localhost:9001/, with its base path set to the www-root directory relative to the gruntfile, and any tasks run afterwards will be able to access it.

// Project configuration.
grunt.initConfig({
  express: {
    server: {
      options: {
        port: 9001,
        bases: 'www-root'
      }
    }
  }
});

You may specify more than one bases like so. Enhancing the above example, now your server will server static content from both www-root folder and app/public folder (both are relative path to the Gruntfile.js)

// Project configuration.
grunt.initConfig({
  express: {
    server: {
      options: {
        port: 9001,
        bases: ['www-root', 'app/public']
      }
    }
  }
});

If you want your web server to use the default options, just omit the options object. You still need to specify a target (uses_defaults in this example), but the target's configuration object can otherwise be empty or nonexistent. In this example, grunt express (or more verbosely, grunt express:uses_defaults) will start a static web server using the default options.

// Project configuration.
grunt.initConfig({
  connect: {
    uses_defaults: {}
  }
});

Multiple Servers

You can specify multiple servers to be run alone or simultaneously by creating a target for each server. In this example, running either grunt connect:site1 or grunt connect:site2 will start the appropriate web server, but running grunt connect will run both. Note that any server for which the keepalive option is specified will prevent any task or target from running after it.

// Project configuration.
grunt.initConfig({
  express: {
    site1: {
      options: {
        port: 9000,
        bases: 'www-roots/site1'
      }
    },
    site2: {
      options: {
        port: 9001,
        bases: 'www-roots/site2'
      }
    }
  }
});

Custom express

Like the Basic Use example, this example will start a static web server at http://localhost:9001/, with its base path set to the www-root directory relative to the gruntfile. Unlike the other example, this will use your custom server script as referred to by server! We also set keepalive and watchChanges to true, so the server will run forever (until you terminate the command), also the server will restart when you apply any changes to your server script.

// Project configuration.
grunt.initConfig({
  express: {
    custom: {
      port: 9001,
      bases: 'www-root',
      supervisor: true,
      watchChanges: true,
      server: path.resolve('./server/main')
    }
  }
});

any in your server/main.js, we reuse the previous sample server script

var express = require('express');
var app = express();
app.get('/', function(req, res) {
  res.send('hello!');
});
module.exports = app;

(open localhost:9001 and you should see "hello!")

Now let's change server/main.js's content to:

var express = require('express');
var app = express();
app.get('/', function(req, res) {
  res.send('bonjour!');
});
module.exports = app;

(refresh browser and you should see "bonjour!")

Release History

  • 2013-03-14 v0.3.0 support 'debug-brk' option for launching server in child process (so it can be linked to a remote debugger); also point forever-monitor dependency to its github verion (has fix for accepting 'debug-brk' options)
  • 2013-03-13 v0.2.2 do not defalt hostname to "localhost" when none is provided as that will prevent access to the server through IP addres
  • 2013-03-11 v0.2.1 Make static directories not browsable as it breaks twitter bootstrap (suggested by @hmalphettes)
  • 2013-02-28 v0.2.0 Switch to use forever-monitor (instead of node-supervisor). Removed "keepalive" option, instead enable the feature using "express-keepalive" task.
  • 2013-02-25 v0.1.3 Fixes #1, changing option "watchChanges" to "supervisor".
  • 2013-02-24 v0.1.1 Added missing "connect" dependency, factored out some logic to util.js.
  • 2013-02-23 v0.1.0 first draft.