Running an Express server with Grunt and Yeoman: Part 2

Update: The grunt-express-workflow project has been updated to include a full front-end and back-end testing framework by leveraging Grunt, Karma, Mocha, and Istanbul. Read all about how to test your code easily in part 3 of this series.

In part 1 of this series I introduced a small number of tools that make a web engineer’s life easier: Grunt, Yeoman, Express, and Nodemon. In this second part of the series I’ll explain how to get started using them together. You’ll soon have a server running with LiveReload that’s capable of automatic browser and app server reboots for rapid development.

Getting the Right Tools

The first thing you should do is download and install Node.js if you haven’t already. It should come with a package manager called npm. You’ll need to install the proper tools with it:

$ npm install -g yo node-inspector nodemon grunt-cli bower karma istanbul

I recommend having a tool like nvm to manage multiple local installations of node with user privileges.

Quick Start

I’ve set up a repository of all the files you need to be up and running. Be sure to read the repository’s README.md to get an idea of what it’s all about. As I fleshed out this project, I realized how much I had changed of the original Yeoman scaffold. If you’re interested to see what an initial Yeoman project directory would look like, type yo webapp into a terminal that’s inside of an empty directory, follow the prompts, and poke around a bit.

What we’ll be referencing from here on are these repository files I’ve heavily modified from that initial Yeoman scaffold.

Start with:

$ git clone https://github.com/darvelo/grunt-express-workflow

Now you have a copy of the repository to play with.

$ cd grunt-express-workflow
$ npm install
$ bower install

These will install all your server-side and client-side dependencies. Then:

$ grunt server

I won’t be going into great detail about Grunt or the included Grunt plugins in this post — for that you can research the Grunt documentation and the documentation of each plugin — but by poking at the files in this project and reading Gruntfile.js you can get a pretty good idea of how it all works together.

Now your Express server is running from server.js with a minimalistic client-side app, and with tests! Expand on it to your heart’s content and watch happiness spread out across the land.

What’s Included?

Popular client-side libraries included and configured:

Server-side libraries included and configured:

Testing Libraries included and configured:

Grunt plugins I included in package.json and configured in Gruntfile.js are:

Caveats

  1. If you want to grunt build for a production-ready build of the project with Handlebars included, you’ll need to change the Handlebars runtime library code from the initial var Handlebars = {}; to this.Handlebars = {}; so that it’ll be attached to the window and found by RequireJS modules. It seems this is being fixed upstream with the Handlebars developers at the time of this writing.

  2. There’s an issue in the grunt-contrib-watch task where if two targets are watching the same file(s), only the last defined target will run if the file(s) change. Right now this means client-side tests will run and livereload will not when client-side scripts are saved. You can switch this behavior by altering the watch target order in Gruntfile.js. Watch grunt-contrib-watch issue #25 and upgrade your local copy of that library using npm when it’s fixed. The grunt-contrib-watch package has been updated and grunt-express-workflow now uses the new version. Many thanks to the maintainers!

  3. If you want to test your media queries in old IE with respond.js, be sure to modify your Gruntfile.js to switch your compass:server options from debugInfo: true to debugInfo: false. This removes Compass’ ability to inject certain media queries into your CSS, which would make it easier for you to debug your styles in modern browser debuggers, but confuse the logic of respond.js.

Differences to yo webapp

Since Yeoman is being worked on for a 1.0 release, there are a few things that we can upgrade in the meantime to make a better experience for ourselves. Here’s what I did:

How does it work?

At a very high level, the grunt server command will start a bunch of tasks that do quite a few things:

Client-side files

In the root directory is a folder called app/. That’s where all your client-side files go. The app/scripts/ directory is for scripts, and has three folders:

When you run grunt server, your client-side files will automatically be watched for changes, with unit tests and code coverage run and the browser refreshed when they’re changed. In the case of SASS changes, the grunt watch task will compile the CSS and inject it into the page without a refresh required. When edited and saved, any watched files that are compilable will automatically be compiled into .tmp/ with an identical file structure. The server is configured to also serve files out of .tmp/ (along with app/) during development. Files watched are:

The app/images/sprites/ folder is special. Each folder you create in it should represent a spritesheet you’d like to create for production that’s composed of the images inside. You can tell Compass to create these spritesheets using Compass’ sprite helpers. Once you do a grunt build, what’s left inside the dist/app/images/sprites/ folder is your compiled spritesheets, named by the original folder name. An example of this is in the project. Try it out for yourself!

The dist/ folder is automatically regenerated every time you run grunt build. It’ll hold all your usemin-updated Jade templates in dist/views/, and in dist/app/ will hold your compiled SASS and Handlebars templates, and concatenated and minified scripts and libraries, along with efficiently-processed images. After a build you can freely delete the usemin.html file in the dist/ folder, and if you’re using almond with RequireJS, the components/requirejs folder. The cssmin task in Gruntfile.js determines which CSS files in .tmp/ are combined and placed in dist/styles/.

Server-side files

With grunt server, Express will run with the env environment variable set to 'development' by default, which you can detect in your server scripts with app.get('env') === 'development' in order to branch into a different set of behaviors, such as setting certain variables in your views for more verbose error-handling. Files will be served out of app/ and .tmp/.

The grunt nodemon task generates a .nodemonignore file in your project root and is configured to ignore your client-side files when watching for changes that will restart the server. You can edit which files are ignored in Gruntfile.js.

After a build with grunt build, you can invoke your node server directly for a production environment with $ node server.js production or $ NODE_ENV=production node server.js. The dist/ folder will be used for serving files, and not app/ or .tmp/. If your server-side views with Jade are set up with usemin to process your css and js files, the switchover should be seamless.

The file node-inspector.js exists so that node-inspector can be spawned by nodemon when running grunt server.

If you prefer not to use Jade, simply remove the app.get blocks in server.js referencing res.render(). All html files in the app/ directory will still be served as expected. You’ll be missing out on all sorts of wonderfulness, though!

Tests

Karma, Istanbul, and Mocha run automated tests and coverage for the frontend and backend. This happens when development files or test files are changed during a grunt server run, or when the grunt test command is run on the command line. See part 3 for an in-depth explanation.

Debugging the Server with node-inspector

Once you run grunt server you can debug your node server on the fly by opening a new tab in a WebKit-based browser and navigating to http://127.0.0.1:8080/debug?port=5858. Since nodemon starts node in --debug mode, grunt is configured to run a separate node-inspector process that will attach to that debug session and relay requests on that URL to a WebKit Inspector view, where you can use breakpoints and step debugging just like you’re used to on the client-side.

For instance, if you set a breakpoint in the app.get('/') block and refresh another tab running your client-side app — http://localhost:9000 in this case — the response from the server will be paused while you switch to your node-inspector tab and step through the server code to squash bugs. Resuming script execution will finally send the response, even if the request has already timed out. This is all really amazingly cool and saves countless time debugging your server application, so I encourage you to read the node-inspector documentation and use it to amazing effect.

Conclusion

On to part 3 for how to work with unit tests and code coverage!

Comments