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 refreshedIn 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.