Update items menu
[dlux.git] / Gruntfile.js
1 var lrSnippet = require('connect-livereload')();
2 var mountFolder = function (connect, dir) {
3     return connect.static(require('path').resolve(dir));
4 };
5
6 /*global module:false*/
7 module.exports = function (grunt) {
8   require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
9
10   /**
11    * Load in our build configuration file.
12    */
13   var userConfig = require( './build.config.js' );
14
15   // Project configuration.
16   var taskConfig = {
17     // Metadata.
18     pkg: grunt.file.readJSON('package.json'),
19     meta: {
20         banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
21           '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
22           '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
23           '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
24           ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
25     },
26     clean: [
27       '<%= build_dir %>',
28       '<%= compile_dir %>'
29     ],
30     copy: {
31       build_app_assets: {
32         files: [
33           {
34             src: [ '**' ],
35             dest: '<%= build_dir %>/assets/',
36             cwd: 'src/assets',
37             expand: true
38           }
39         ]
40       },
41       build_vendor_assets: {
42         files: [
43           {
44             src: [ '<%= vendor_files.assets %>' ],
45             dest: '<%= build_dir %>/assets/',
46             cwd: '.',
47             expand: true,
48             flatten: true
49           }
50        ]
51       },
52       build_appjs: {
53         files: [
54           {
55             src: [ '<%= app_files.js %>' ],
56             dest: '<%= build_dir %>/',
57             cwd: '.',
58             expand: true
59           }
60         ]
61       },
62       build_vendorjs: {
63         files: [
64           {
65             src: [ '<%= vendor_files.js %>' ],
66             dest: '<%= build_dir %>/',
67             cwd: '.',
68             expand: true
69           }
70         ]
71       },
72       build_vendorcss: {
73         files: [
74           {
75             src: [ '<%= vendor_files.css %>' ],
76             dest: '<%= build_dir %>',
77             cwd: '.',
78             expand: true
79           }
80         ]
81       },
82       build_vendorassets: {
83         files: [
84           {
85             src: [ '<%= vendor_files.assets %>' ],
86             dest: '<%= build_dir %>',
87             cwd: '.',
88             expand: true
89           }
90         ]
91       },
92       compile_assets: {
93         files: [
94           {
95             src: [ '**' ],
96             dest: '<%= compile_dir %>/assets',
97             cwd: '<%= build_dir %>/assets',
98             expand: true
99           }
100         ]
101       }
102     },
103
104     // JS Tasks
105     concat: {
106       /**
107        * The `build_css` target concatenates compiled CSS and vendor CSS
108        * together.
109        */
110       build_css: {
111         src: [
112           '<%= vendor_files.css %>',
113           '<%= recess.build.dest %>'
114         ],
115         dest: '<%= recess.build.dest %>'
116       },
117       /**
118        * The `compile_js` target is the concatenation of our application source
119        * code and all specified vendor source code into a single file.
120        */
121       compile_js: {
122         options: {
123           banner: '<%= meta.banner %>'
124         },
125         src: [
126           '<%= vendor_files.js %>',
127           'module.prefix',
128           '<%= build_dir %>/src/**/*.js',
129           '<%= html2js.app.dest %>',
130           '<%= html2js.common.dest %>',
131           'module.suffix'
132         ],
133         dest: '<%= compile_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.js'
134       }
135     },
136
137     /**
138      * Compile Coffee scripts
139      */
140     coffee: {
141       source: {
142         options: {
143           bare: true
144         },
145         expand: true,
146         cwd: '.',
147         src: [ '<%= app_files.coffee %>' ],
148         dest: '<%= build_dir %>',
149         ext: '.js'
150       }
151     },
152
153     /**
154      * `ng-min` annotates the sources before minifying. That is, it allows us
155      * to code without the array syntax.
156      */
157     ngmin: {
158       compile: {
159         files: [
160           {
161             src: [ '<%= app_files.js %>' ],
162             cwd: '<%= build_dir %>',
163             dest: '<%= build_dir %>',
164             expand: true
165           }
166         ]
167       }
168     },
169
170    /**
171      * Minify the sources!
172      */
173     uglify: {
174       compile: {
175         options: {
176           banner: '<%= meta.banner %>'
177         },
178         files: {
179           '<%= concat.compile_js.dest %>': '<%= concat.compile_js.dest %>'
180         }
181       }
182     },
183
184     // Style tasks
185     /**
186      * Minify CSS
187      */
188     cssmin: {
189       combine: {
190         files: {
191           'target/<%= pkg.name %>-combined.css': ['src/css/*.css']
192         }
193       }
194     },
195
196     /**
197      * Compile LESS templates to css
198      */
199     recess: {
200       build: {
201         src: [ '<%= app_files.less %>' ],
202         dest: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css',
203         options: {
204           compile: true,
205           compress: false,
206           noUnderscores: false,
207           noIDs: false,
208           zeroUnits: false
209         }
210       },
211       compile: {
212         src: [ '<%= recess.build.dest %>' ],
213         dest: '<%= recess.build.dest %>',
214         options: {
215           compile: true,
216           compress: true,
217           noUnderscores: false,
218           noIDs: false,
219           zeroUnits: false
220         }
221       }
222     },
223
224     /**
225      * `jshint` defines the rules of our linter as well as which files we
226      * should check. This file, all javascript sources, and all our unit tests
227      * are linted based on the policies listed in `options`. But we can also
228      * specify exclusionary patterns by prefixing them with an exclamation
229      * point (!); this is useful when code comes from a third party but is
230      * nonetheless inside `src/`.
231      */
232     jshint: {
233       src: [
234         '<%= app_files.js %>'
235       ],
236       test: [
237         '<%= app_files.jsunit %>'
238       ],
239       gruntfile: [
240         'Gruntfile.js'
241       ],
242       options: {
243         curly: true,
244         immed: true,
245         newcap: true,
246         noarg: true,
247         sub: true,
248         boss: true,
249         eqnull: true,
250         globals: {
251           "angular": true,
252           "document": true,
253           "dlux": true,
254           "_": true,
255           "require": true,
256           "define": true,
257           "requirejs": true,
258           "describe": true,
259           "expect": true,
260           "it": true
261         }
262       }
263
264     },
265
266     // Coffe linting
267     coffeelint: {
268       src: {
269         files: {
270           src: [ '<%= app_files.coffee %>' ]
271         }
272       },
273       test: {
274         files: {
275           src: [ '<%= app_files.coffeeunit %>' ]
276         }
277       }
278     },
279
280     /**
281      * HTML2JS is a Grunt plugin that takes all of your template files and
282      * places them into JavaScript files as strings that are added to
283      * AngularJS's template cache. This means that the templates too become
284      * part of the initial payload as one JavaScript file. Neat!
285      */
286     html2js: {
287       /**
288        * These are the templates from `src/app`.
289        */
290       app: {
291         options: {
292           base: 'src/app'
293         },
294         src: [ '<%= app_files.atpl %>' ],
295         dest: '<%= build_dir %>/templates-app.js'
296       },
297
298       /**
299        * These are the templates from `src/common`.
300        */
301       common: {
302         options: {
303           base: 'src/common'
304         },
305         src: [ '<%= app_files.ctpl %>' ],
306         dest: '<%= build_dir %>/templates-common.js'
307       }
308     },
309
310     /**
311      * The Karma configurations.
312      */
313     karma: {
314       options: {
315         configFile: '<%= build_dir %>/karma-unit.js'
316       },
317       unit: {
318         runnerPort: 9101,
319         background: true
320       },
321       continuous: {
322         singleRun: true
323       }
324     },
325
326     /**
327      * The `index` task compiles the `index.html` file as a Grunt template. CSS
328      * and JS files co-exist here but they get split apart later.
329      */
330     index: {
331
332       /**
333        * During development, we don't want to have wait for compilation,
334        * concatenation, minification, etc. So to avoid these steps, we simply
335        * add all script files directly to the `<head>` of `index.html`. The
336        * `src` property contains the list of included files.
337        */
338       build: {
339         dir: '<%= build_dir %>',
340         src: [
341           '<%= vendor_files.js %>',
342           '<%= build_dir %>/src/**/*.js',
343           '<%= html2js.common.dest %>',
344           '<%= html2js.app.dest %>',
345           '<%= vendor_files.css %>',
346           '<%= recess.build.dest %>'
347         ]
348       },
349
350       /**
351        * When it is time to have a completely compiled application, we can
352        * alter the above to include only a single JavaScript and a single CSS
353        * file. Now we're back!
354        */
355       compile: {
356         dir: '<%= compile_dir %>',
357         src: [
358           '<%= concat.compile_js.dest %>',
359           '<%= vendor_files.css %>',
360           '<%= recess.compile.dest %>'
361         ]
362       }
363     },
364
365     /**
366      * This task compiles the karma template so that changes to its file array
367      * don't have to be managed manually.
368      */
369     karmaconfig: {
370       unit: {
371         dir: '<%= build_dir %>',
372         src: [
373           '<%= vendor_files.js %>',
374           '<%= html2js.app.dest %>',
375           '<%= html2js.common.dest %>',
376           '<%= test_files.js %>'
377         ]
378       }
379     },
380
381     connect: {
382       livereload: {
383         options: {
384           port: 9000,
385           hostname: '0.0.0.0',
386           middleware: function (connect) {
387             return [
388               mountFolder(connect, 'build'),
389               lrSnippet
390             ];
391           }
392         }
393       },
394       dev: {
395         options: {
396           hostname: '0.0.0.0',
397           port: 9000,
398           base: 'build'
399         }
400       },
401       prod: {
402         options: {
403           port: 9001,
404           base: 'bin',
405           keepalive: true
406         }
407       }
408     },
409     open: {
410       dev: {
411         path: 'http://127.0.0.1:9000/'
412       },
413       prod: {
414         path: 'http://127.0.0.1:9001/'
415       }
416     },
417     delta: {
418       /**
419        * By default, we want the Live Reload to work for all tasks; this is
420        * overridden in some tasks (like this file) where browser resources are
421        * unaffected. It runs by default on port 35729, which your browser
422        * plugin should auto-detect.
423        */
424       options: {
425         livereload: true
426       },
427
428       /**
429        * When the Gruntfile changes, we just want to lint it. In fact, when
430        * your Gruntfile changes, it will automatically be reloaded!
431        */
432       gruntfile: {
433         files: 'Gruntfile.js',
434         tasks: [ 'jshint:gruntfile' ],
435         options: {
436           livereload: false
437         }
438       },
439
440       /**
441        * When our JavaScript source files change, we want to run lint them and
442        * run our unit tests.
443        */
444       jssrc: {
445         files: [
446           '<%= app_files.js %>'
447         ],
448         tasks: [
449           'jshint:src',
450           'copy:build_appjs'
451         ]
452       },
453
454       /**
455        * When assets are changed, copy them. Note that this will *not* copy new
456        * files, so this is probably not very useful.
457        */
458       assets: {
459         files: [
460           'src/assets/**/*'
461         ],
462         tasks: [ 'copy:build_assets' ]
463       },
464
465       /**
466        * When index.html changes, we need to compile it.
467        */
468       html: {
469         files: [ '<%= app_files.html %>' ],
470         tasks: [ 'index:build' ]
471       },
472
473       /**
474        * When our templates change, we only rewrite the template cache.
475        */
476       tpls: {
477         files: [
478           '<%= app_files.atpl %>',
479           '<%= app_files.ctpl %>'
480         ],
481         tasks: [ 'html2js' ]
482       },
483
484       /**
485        * When the CSS files change, we need to compile and minify them.
486        */
487       less: {
488         files: [ 'src/**/*.less' ],
489         tasks: [ 'build_styles' ]
490       },
491
492       /**
493        * When a JavaScript unit test file changes, we only want to lint it and
494        * run the unit tests. We don't want to do any live reloading.
495        */
496       jsunit: {
497         files: [
498           '<%= app_files.jsunit %>'
499         ],
500         tasks: [
501           'jshint:test',
502         ],
503         options: {
504           livereload: false
505         }
506       },
507
508       /**
509        * When a CoffeeScript unit test file changes, we only want to lint it and
510        * run the unit tests. We don't want to do any live reloading.
511        */
512       coffeeunit: {
513         files: [
514           '<%= app_files.coffeeunit %>'
515         ],
516         tasks: [
517           'coffeelint:test'
518         ],
519         options: {
520           livereload: false
521         }
522       }
523     }
524   };
525
526   grunt.initConfig( grunt.util._.extend( taskConfig, userConfig ) );
527
528   /**
529    * In order to make it safe to just compile or copy *only* what was changed,
530    * we need to ensure we are starting from a clean, fresh build. So we rename
531    * the `watch` task to `delta` (that's why the configuration var above is
532    * `delta`) and then add a new task called `watch` that does a clean build
533    * before watching for changes.
534    */
535   grunt.renameTask( 'watch', 'delta' );
536   grunt.registerTask('watch', [ 'build', 'delta' ] );
537
538   // task to do both vendor less compile and css concat.
539   grunt.registerTask('build_styles', ['recess:build', 'concat:build_css']);
540
541   grunt.registerTask('live', ['build', 'connect:dev', 'open:dev', 'delta']);
542
543   /**
544    * The default task is to build and compile.
545    */
546   grunt.registerTask( 'default', [ 'build', 'compile' ] );
547
548   /**
549    * The `build` task gets your app ready to run for development and testing.
550    */
551   grunt.registerTask( 'build', [
552     'clean', 'html2js', 'coffeelint', 'coffee', 'build_styles',
553     'copy:build_app_assets', 'copy:build_vendor_assets',
554     'copy:build_appjs', 'copy:build_vendorjs', 'index:build'
555   ]);
556    // 'copy:build_assets', 'copy:build_appjs', 'copy:build_vendorjs', 'copy:build_vendorcss', 'copy:build_vendorassets',
557
558
559   /**
560    * The `compile` task gets your app ready for deployment by concatenating and
561    * minifying your code.
562    */
563   grunt.registerTask( 'compile', [
564     'recess:compile', 'copy:compile_assets', 'ngmin', 'concat:compile_js', 'uglify', 'index:compile'
565   ]);
566
567   /**
568    * A utility function to get all app JavaScript sources.
569    */
570   function filterForJS ( files ) {
571     return files.filter( function ( file ) {
572       return file.match( /\.js$/ );
573     });
574   }
575
576   /**
577    * A utility function to get all app CSS sources.
578    */
579   function filterForCSS ( files ) {
580     return files.filter( function ( file ) {
581       return file.match( /\.css$/ );
582     });
583   }
584
585   /**
586    * The index.html template includes the stylesheet and javascript sources
587    * based on dynamic names calculated in this Gruntfile. This task assembles
588    * the list into variables for the template to use and then runs the
589    * compilation.
590    */
591   grunt.registerMultiTask( 'index', 'Process index.html template', function () {
592     var dirRE = new RegExp( '^('+grunt.config('build_dir')+'|'+grunt.config('compile_dir')+')\/', 'g' );
593     var jsFiles = filterForJS( this.filesSrc ).map( function ( file ) {
594       return file.replace( dirRE, '' );
595     });
596     var cssFiles = filterForCSS( this.filesSrc ).map( function ( file ) {
597       return file.replace( dirRE, '' );
598     });
599
600     grunt.file.copy('src/index.html', this.data.dir + '/index.html', {
601       process: function ( contents, path ) {
602         return grunt.template.process( contents, {
603           data: {
604             scripts: jsFiles,
605             styles: cssFiles,
606             version: grunt.config( 'pkg.version' )
607           }
608         });
609       }
610     });
611   });
612
613   /**
614    * In order to avoid having to specify manually the files needed for karma to
615    * run, we use grunt to manage the list for us. The `karma/*` files are
616    * compiled as grunt templates for use by Karma. Yay!
617    */
618   grunt.registerMultiTask( 'karmaconfig', 'Process karma config templates', function () {
619     var jsFiles = filterForJS( this.filesSrc );
620
621     grunt.file.copy( 'karma/karma-unit.tpl.js', grunt.config( 'build_dir' ) + '/karma-unit.js', {
622       process: function ( contents, path ) {
623         return grunt.template.process( contents, {
624           data: {
625             scripts: jsFiles
626           }
627         });
628       }
629     });
630   });
631
632 };