Monday 31 March 2014

MEAN stack build system

MEAN stack build system

The MEAN stack is [M]ongo, [E]xpress, [A]ngular, [N]ode.
Back end:
The server is built using Express, which is built on top of Node.
The database used by the server is MongoDB.
Front end:
The client is built using Angular.
The less version of Bootstrap is used for CSS.
I use Yeoman and the angular-fullstack generator to generate my MEAN stack scaffold.
yo angular-fullstack [app]
Development tools:
npm is used for the server dependencies; these are listed in package.json
Bower is used for the client dependencies; these are listed in bower.json
Grunt is used for the build system. The configuration is stored in Gruntfile.js
The file system structure is as follows:
site/
  app/            # client source code 
  lib/            # server source code
  test/           # tests
  public/         # client production build destination
  Gruntfile.js    # Grunt configuration
  package.json    # server dependencies
  bower.json      # client dependencies
  server.js       # Express server entry-point
Grunt plugins:
grunt-bower-install:
When new dependencies are added with bower, grunt-bower-install will automatically inject their css and js into index.html.
In the grunt.initConfig block of Gruntfile.js:
'bower-install': {
    app: {
        html: '<%= yeoman.app %>/index.html',
        ignorePath: '<%= yeoman.app %>/'
    }
},
grunt-file-blocks:
When new front end components added in the source tree, grunt-file-blocks will automatically inject the javascript into index.html and the less into main.less.
In the grunt.initConfig block of Gruntfile.js:
fileblocks: {
    options: {
        removeFiles: true,
        templates: {
            less: '@import \'${file}\';'
        }
    },
    js: {
        src: 'app/index.html',
        blocks: {
            components: { cwd: 'app', src: 'components/**/*.js' }
        }
    },
    less: {
        src: 'app/css/main.less',
        blocks: {
            components: { cwd: 'app', src: 'components/**/*.less' }
        }
    }
},
Development workflow:
File are monitored for changes and the front or back end are reloaded as required.
nodemon and LiveReload are run concurrently:
In the grunt.initConfig block of Gruntfile.js:
concurrent: {
    dev: {
        tasks: ['nodemon', 'watch'],
        options: {
            logConcurrentOutput: true
        }
    }
},
Back end changes are monitored by nodemon. If a file required by the server is changed, node will be relaunched, restarting the server.
In the grunt.initConfig block of Gruntfile.js:
nodemon: {
    dev: {
        options: {
            file: 'server.js',
            ignoredFiles: ['app', 'test', 'node_modules'],
            watchedExtensions: ['js']
        }
    }
},
Front end changes are monitored by LiveReload. If a file required by the client is changed, assets will be rebuild (eg less converted to css) and the browser will be refreshed
In the grunt.initConfig block of Gruntfile.js:
watch: {
    app: {
        options: { livereload: true },
        files: [
            'app/index.*',
            'app/css/*',
            'app/components/**/*.js',
            'app/images/*'
        ]
    },
    less: {
        tasks: ['less'],
        files: ['app/css/main.less', 'app/components/**/*.less']
    }
},
less: {
    build: {
        files: { 'app/css/main.css': 'app/css/main.less' }
    }
}
This article is inspired by Shawn Dahlen’s post on the build system 4dashes uses.

No comments:

Post a Comment