Compiling a Node Project with Grunt

In the previous chapter, we used Grunt to compile our CoffeeScript files into JavaScript (and source maps) to be served to the browser. For this chapter’s project, we’ll have two kinds of CoffeeScript files: files that define JavaScript to be sent to the browser, and files that should be run locally in Node. So we’ll keep them in two separate directories, /assets and /src. We’ll use our Node server to serve our compiled assets to the browser. Any time any of our files change, we’ll restart the Node server to ensure that it reflects our changes.

We’ll keep our assets that don’t have to be compiled (our CSS and HTML files, as well as the external JS we’ll install through Bower) in the assets directory as well, and copy them into /lib with everything else we would need to deploy our project (except for the third-party packages in /node_modules). To do that, we’ll use another Grunt plugin, grunt-contrib-copy.[45]

To manage our local Node server, we’ll use the grunt-nodemon[46] plugin, which wraps around the excellent nodemon.[47] nodemon watches files and restarts our Node server.

One wrinkle: both grunt-contrib-watch (which we’ll be using to automatically recompile our project when source files change, as in the previous chapter) and grunt-nodemon keep running indefinitely, and Grunt tasks normally run in a one-at-a-time fashion. To run them at the same time, we need to use yet another plugin, grunt-concurrent.[48]

If you think this sounds quite complicated, well, you’re right. Setting up the perfect Grunt configuration for a project can take quite a bit of work, because the possibilities for custom tailoring are endless. But once it’s set up, the dividends (compared to compiling manually) are enormous.

As in the last chapter, let’s start by setting up our project directory:

 $ ​​mkdir​​ ​​coffee-tasks
 $ ​​cd​​ ​​coffee-tasks
 $ ​​npm​​ ​​init

And now let’s install Grunt and the plugins we need, including the ones from the previous chapter:

 $ ​​npm​​ ​​install​​ ​​-g​​ ​​grunt-cli
 $ ​​npm​​ ​​install​​ ​​--save-dev​​ ​​grunt
 $ ​​npm​​ ​​install​​ ​​--save-dev​​ ​​grunt-eco
 $ ​​npm​​ ​​install​​ ​​--save-dev​​ ​​grunt-concurrent
 $ ​​npm​​ ​​install​​ ​​--save-dev​​ ​​grunt-contrib-watch
 $ ​​npm​​ ​​install​​ ​​--save-dev​​ ​​grunt-contrib-copy
 $ ​​npm​​ ​​install​​ ​​--save-dev​​ ​​grunt-contrib-coffee
 $ ​​npm​​ ​​install​​ ​​--save-dev​​ ​​grunt-nodemon

Whew! Okay, that’s all set. Now here’s our Gruntfile:

 module.exports = (grunt) ->
  grunt.loadNpmTasks(​'grunt-eco'​)
  grunt.loadNpmTasks(​'grunt-concurrent'​)
  grunt.loadNpmTasks(​'grunt-contrib-watch'​)
  grunt.loadNpmTasks(​'grunt-contrib-copy'​)
  grunt.loadNpmTasks(​'grunt-contrib-coffee'​)
  grunt.loadNpmTasks(​'grunt-nodemon'​)
 
  grunt.initConfig
  watch:
  coffeeAssets:
  files: ​'assets/coffee/*.coffee'
  tasks: [​'coffee:compileAssets'​]
  coffeeServer:
  files: ​'src/*.coffee'
  tasks: [​'coffee:compileServer'​]
  eco:
  files: ​'assets/templates/*.eco'
  tasks: [​'eco:compile'​]
  css:
  files: ​'assets/css/*.css'
  tasks: [​'copy:css'​]
  html:
  files: ​'assets/html/*.html'
  tasks: [​'copy:html'​]
 
  coffee:
  compileAssets:
  expand: true
  flatten: true
  options:
  sourceMap: true
  cwd: ​'assets/coffee/'
  src: [​'*.coffee'​]
  dest: ​'lib/public/js/'
  ext: ​'.js'
  compileServer:
  expand: true
  flatten: true
  options:
  sourceMap: true
  cwd: ​'src/'
  src: [​'*.coffee'​]
  dest: ​'lib/'
  ext: ​'.js'
 
  eco:
  compile:
  options:
  basePath: ​'assets'
  src: ​'assets/templates/*.eco'
  dest: ​'lib/public/js/templates.js'
 
  copy:
  css:
  files: [{
  expand: true
  cwd: ​'assets/css/'
  src: [​'*.css'​]
  dest: ​'lib/public/css/'
  }]
  html:
  files: [{
  expand: true
  cwd: ​'assets/html/'
  src: [​'*.html'​]
  dest: ​'lib/public/'
  }]
  bower:
  files: [{
  expand: true
  flatten: true
  cwd: ​'bower_components/'
  src: [
 'jquery/dist/jquery.js'
 'underscore/underscore.js'
 'backbone/backbone.js'
  ]
  dest: ​'lib/public/js/'
  }]
 
  nodemon:
  dev:
  script: ​'lib/server.js'
  watch: ​'lib'
  ext: ​'*'
  options:
  nodeArgs: [​'--debug'​]
 
  concurrent:
  dev:
  tasks: [​'nodemon'​, ​'watch'​]
  options:
  logConcurrentOutput: true
 
  grunt.registerTask(​'build'​, [​'coffee'​, ​'eco'​, ​'copy'​])
  grunt.registerTask(​'default'​, [​'build'​, ​'concurrent'​])

It’s a lot to take in, but in practice it should feel pretty straightforward: you’ll be editing files in /src (for the server) and /assets (for the front end), all of which will go into /lib. The root of /lib is reserved for the files that make up our Node server, while the contents of /lib/public will be directly available to the browser. This new directory structure allows us to simplify our index.html nicely:

 <!DOCTYPE html>
 <html>
 <head>
  <title>CoffeeTasks</title>
 
 <!-- Libraries -->
  <script src=​"js/jquery.js"​></script>
  <script src=​"js/underscore.js"​></script>
  <script src=​"js/backbone.js"​></script>
 
 <!-- Templates -->
  <script src=​"js/templates.js"​></script>
 
 <!-- Backbone models/views -->
  <script src=​"js/card.js"​></script>
  <script src=​"js/column.js"​></script>
  <script src=​"js/board.js"​></script>
 
 <!-- Application core -->
  <script src=​"js/application.js"​></script>
 
 <!-- Stylesheets -->
  <link rel=​"stylesheet"​ href=​"css/normalize.css"​>
  <link rel=​"stylesheet"​ href=​"css/style.css"​>
 </head>
 <body>
 <!-- All content is rendered client-side -->
 </body>
 </html>

In the next section, we’ll get our server up and running.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.101.109