IPR Cleanup of DLUX code
[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 module.exports = function ( grunt ) {
7   
8   /** 
9    * Load required Grunt tasks. These are installed based on the versions listed
10    * in `package.json` when you do `npm install` in this directory.
11    */
12   grunt.loadNpmTasks('grunt-contrib-clean');
13   grunt.loadNpmTasks('grunt-contrib-copy');
14   grunt.loadNpmTasks('grunt-contrib-jshint');
15   grunt.loadNpmTasks('grunt-contrib-concat');
16   grunt.loadNpmTasks('grunt-contrib-watch');
17   grunt.loadNpmTasks('grunt-contrib-uglify');
18   grunt.loadNpmTasks('grunt-contrib-coffee');
19   grunt.loadNpmTasks('grunt-conventional-changelog');
20   grunt.loadNpmTasks('grunt-bump');
21   grunt.loadNpmTasks('grunt-coffeelint');
22   //grunt.loadNpmTasks('grunt-recess');
23   grunt.loadNpmTasks('grunt-karma');
24   grunt.loadNpmTasks('grunt-ngmin');
25   grunt.loadNpmTasks('grunt-html2js');
26   grunt.loadNpmTasks('grunt-contrib-less');
27   grunt.loadNpmTasks('grunt-contrib-connect');
28   grunt.loadNpmTasks('grunt-open');
29
30   /**
31    * Load in our build configuration file.
32    */
33   var userConfig = require( './build.config.js' );
34
35   /**
36    * This is the configuration object Grunt uses to give each plugin its 
37    * instructions.
38    */
39   var taskConfig = {
40     /**
41      * We read in our `package.json` file so we can access the package name and
42      * version. It's already there, so we don't repeat ourselves here.
43      */
44     pkg: grunt.file.readJSON("package.json"),
45
46     /**
47      * The banner is the comment that is placed at the top of our compiled 
48      * source files. It is first processed as a Grunt template, where the `<%=`
49      * pairs are evaluated based on this very configuration object.
50      */
51     meta: {
52       banner: 
53         '/**\n' +
54         ' * <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' +
55         ' * <%= pkg.homepage %>\n' +
56         ' *\n' +
57         ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
58         ' * Licensed <%= pkg.licenses.type %> <<%= pkg.licenses.url %>>\n' +
59         ' */\n'
60     },
61
62     /**
63      * Creates a changelog on a new version.
64      */
65     changelog: {
66       options: {
67         dest: 'CHANGELOG.md',
68         template: 'changelog.tpl'
69       }
70     },
71
72     /**
73      * Increments the version number, etc.
74      */
75     bump: {
76       options: {
77         files: [
78           "package.json", 
79           "bower.json"
80         ],
81         commit: false,
82         commitMessage: 'chore(release): v%VERSION%',
83         commitFiles: [
84           "package.json", 
85           "client/bower.json"
86         ],
87         createTag: false,
88         tagName: 'v%VERSION%',
89         tagMessage: 'Version %VERSION%',
90         push: false,
91         pushTo: 'origin'
92       }
93     },    
94
95     /**
96      * The directories to delete when `grunt clean` is executed.
97      */
98     clean: [ 
99       '<%= build_dir %>', 
100       '<%= compile_dir %>'
101     ],
102
103     /**
104      * The `copy` task just copies files from A to B. We use it here to copy
105      * our project assets (images, fonts, etc.) and javascripts into
106      * `build_dir`, and then to copy the assets to `compile_dir`.
107      */
108     copy: {
109       build_app_assets: {
110         files: [
111           { 
112             src: [ '**' ],
113             dest: '<%= build_dir %>/assets/',
114             cwd: 'src/assets',
115             expand: true
116           }
117        ]   
118       },
119       build_vendor_assets: {
120         files: [
121           { 
122             src: [ '<%= vendor_files.assets %>' ],
123             dest: '<%= build_dir %>/assets/',
124             cwd: '.',
125             expand: true,
126             flatten: true
127           }
128        ]   
129       },
130       build_appjs: {
131         files: [
132           {
133             src: [ '<%= app_files.js %>' ],
134             dest: '<%= build_dir %>/',
135             cwd: '.',
136             expand: true
137           }
138         ]
139       },
140       build_vendorjs: {
141         files: [
142           {
143             src: [ '<%= vendor_files.js %>' ],
144             dest: '<%= build_dir %>/',
145             cwd: '.',
146             expand: true
147           }
148         ]
149       },
150       build_vendorimages: {
151         files: [
152           {
153             src: [ '<%= vendor_files.images %>' ],
154             dest: '<%= build_dir %>/',
155             cwd: '.',
156             expand: true
157           }
158         ]
159       },
160       build_vendorcss: {
161         files: [
162           {
163             src: [ '<%= vendor_files.css %>' ],
164             dest: '<%= build_dir %>',
165             cwd: '.',
166             expand: true
167           }
168         ]
169       },
170       compile_assets: {
171         files: [
172           {
173             src: [ '**' ],
174             dest: '<%= compile_dir %>/assets',
175             cwd: '<%= build_dir %>/assets',
176             expand: true
177           }
178         ]
179       },
180
181      /* build_vendor_font: {
182         files: [
183           {
184             src: [ '<%= vendor_files.font %>' ],
185             dest: '<%= build_dir %>',
186             cwd: '.',
187             expand: true
188           }
189         ]
190       },*/
191
192       compile_font: {
193         files: [
194           {
195             src: [ '**' ],
196             dest: '<%= compile_dir %>/font',
197             cwd: '<%= build_dir %>/font',
198             expand: true
199           }
200         ]
201       }
202     },
203
204     /**
205      * `grunt concat` concatenates multiple source files into a single file.
206      */
207     concat: {
208       /**
209        * The `build_css` target concatenates compiled CSS and vendor CSS
210        * together.
211        */
212       build_css: {
213         src: [
214           '<%= vendor_files.css %>',
215           '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css'
216         ],
217         dest: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css'
218       },
219       /**
220        * The `compile_js` target is the concatenation of our application source
221        * code and all specified vendor source code into a single file.
222        */
223       compile_js: {
224         options: {
225           banner: '<%= meta.banner %>'
226         },
227         src: [ 
228           '<%= vendor_files.js %>', 
229           'module.prefix', 
230           '<%= build_dir %>/src/**/*.js', 
231           '<%= html2js.common.dest %>', 
232           '<%= html2js.app.dest %>', 
233           'module.suffix' 
234         ],
235         dest: '<%= compile_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.js'
236       }
237     },
238
239     /**
240      * `grunt coffee` compiles the CoffeeScript sources. To work well with the
241      * rest of the build, we have a separate compilation task for sources and
242      * specs so they can go to different places. For example, we need the
243      * sources to live with the rest of the copied JavaScript so we can include
244      * it in the final build, but we don't want to include our specs there.
245      */
246     coffee: {
247       source: {
248         options: {
249           bare: true
250         },
251         expand: true,
252         cwd: '.',
253         src: [ '<%= app_files.coffee %>' ],
254         dest: '<%= build_dir %>',
255         ext: '.js'
256       }
257     },
258
259     /**
260      * `ng-min` annotates the sources before minifying. That is, it allows us
261      * to code without the array syntax.
262      */
263     ngmin: {
264       compile: {
265         files: [
266           {
267             src: [ '<%= app_files.js %>' ],
268             cwd: '<%= build_dir %>',
269             dest: '<%= build_dir %>',
270             expand: true
271           }
272         ]
273       }
274     },
275
276     /**
277      * Minify the sources!
278      */
279     uglify: {
280       compile: {
281         options: {
282           banner: '<%= meta.banner %>'
283         },
284         files: {
285           '<%= concat.compile_js.dest %>': '<%= concat.compile_js.dest %>'
286         }
287       }
288     },
289
290     /**
291      * `recess` handles our LESS compilation and uglification automatically.
292      * Only our `main.less` file is included in compilation; all other files
293      * must be imported from this file.
294      */
295    /**recess: {
296       build: {
297         src: [ '<%= app_files.less %>' ],
298         dest: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css',
299         options: {
300           compile: true,
301           compress: false,
302           noUnderscores: false,
303           noIDs: false,
304           zeroUnits: false
305         }
306       },
307       compile: {
308         src: [ '<%= recess.build.dest %>' ],
309         dest: '<%= recess.build.dest %>',
310         options: {
311           compile: true,
312           compress: true,
313           noUnderscores: false,
314           noIDs: false,
315           zeroUnits: false
316         }
317       }
318     }, **/
319
320       /**
321        * `less` less plugin handles the LESS compilation and minification automatically
322        * this has been changed to the LESS plugin from recess plugin above because of
323        * out of memory issues with the original plugin.
324        */
325
326       less: {
327           development: {
328               options: {
329                   paths: ["assets/css"],
330                   compress: false,
331                   syncImport: true,
332                   strictImports: true
333               },
334               files: {
335                   '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css': '<%= app_files.less %>'
336                   }
337           },
338           production: {
339               options: {
340                   paths: ["assets/css"],
341                   compress: true,
342                   cleancss: true
343               },
344               files: {
345                   '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css': "src/less/main.less"
346               }
347           }
348       },
349
350     /**
351      * `jshint` defines the rules of our linter as well as which files we
352      * should check. This file, all javascript sources, and all our unit tests
353      * are linted based on the policies listed in `options`. But we can also
354      * specify exclusionary patterns by prefixing them with an exclamation
355      * point (!); this is useful when code comes from a third party but is
356      * nonetheless inside `src/`.
357      */
358     jshint: {
359       src: [ 
360         '<%= app_files.js %>'
361       ],
362       test: [
363         '<%= app_files.jsunit %>'
364       ],
365       gruntfile: [
366         'OriginalGruntfile.js'
367       ],
368       options: {
369         curly: true,
370         immed: true,
371         newcap: true,
372         noarg: true,
373         sub: true,
374         boss: true,
375         eqnull: true
376       },
377       globals: {}
378     },
379
380     /**
381      * `coffeelint` does the same as `jshint`, but for CoffeeScript.
382      * CoffeeScript is not the default in ngBoilerplate, so we're just using
383      * the defaults here.
384      */
385     coffeelint: {
386       src: {
387         files: {
388           src: [ '<%= app_files.coffee %>' ]
389         }
390       },
391       test: {
392         files: {
393           src: [ '<%= app_files.coffeeunit %>' ]
394         }
395       }
396     },
397
398     /**
399      * HTML2JS is a Grunt plugin that takes all of your template files and
400      * places them into JavaScript files as strings that are added to
401      * AngularJS's template cache. This means that the templates too become
402      * part of the initial payload as one JavaScript file. Neat!
403      */
404     html2js: {
405       /**
406        * These are the templates from `src/app`.
407        */
408       app: {
409         options: {
410           base: 'src/app'
411         },
412         src: [ '<%= app_files.atpl %>' ],
413         dest: '<%= build_dir %>/templates-app.js'
414       },
415
416       /**
417        * These are the templates from `src/common`.
418        */
419       common: {
420         options: {
421           base: 'src/common'
422         },
423         src: [ '<%= app_files.ctpl %>' ],
424         dest: '<%= build_dir %>/templates-common.js'
425       }
426     },
427
428     /**
429      * The Karma configurations.
430      */
431     karma: {
432       options: {
433         configFile: '<%= build_dir %>/karma-unit.js'
434       },   
435       unit: {
436         runnerPort: 9102,
437         background: true,
438         port: 9877 // IMPORTANT!
439       },
440       continuous: {
441         singleRun: true
442       }
443     },
444
445     /**
446      * The `index` task compiles the `index.html` file as a Grunt template. CSS
447      * and JS files co-exist here but they get split apart later.
448      */
449     index: {
450
451       /**
452        * During development, we don't want to have wait for compilation,
453        * concatenation, minification, etc. So to avoid these steps, we simply
454        * add all script files directly to the `<head>` of `index.html`. The
455        * `src` property contains the list of included files.
456        */
457       build: {
458         dir: '<%= build_dir %>',
459         src: [
460           '<%= vendor_files.js %>',
461           '<%= build_dir %>/src/**/*.js',
462           '<%= html2js.common.dest %>',
463           '<%= html2js.app.dest %>',
464           '<%= vendor_files.css %>',
465           '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css'
466         ]
467       },
468
469       /**
470        * When it is time to have a completely compiled application, we can
471        * alter the above to include only a single JavaScript and a single CSS
472        * file. Now we're back!
473        */
474       compile: {
475         dir: '<%= compile_dir %>',
476         src: [
477           '<%= concat.compile_js.dest %>',
478           '<%= concat.build_css.dest %>'
479           //'<%= recess.compile.dest %>'
480         ]
481       }
482     },
483
484     /**
485      * This task compiles the karma template so that changes to its file array
486      * don't have to be managed manually.
487      */
488     karmaconfig: {
489       unit: {
490         dir: '<%= build_dir %>',
491         src: [ 
492           '<%= vendor_files.js %>',
493           '<%= html2js.app.dest %>',
494           '<%= html2js.common.dest %>',
495           '<%= test_files.js %>'
496         ]
497       }
498     },
499      connect: {
500       livereload: {
501         options: {
502           port: 9000,
503           hostname: '0.0.0.0',
504           middleware: function (connect) {
505             return [
506               mountFolder(connect, 'build'),
507               lrSnippet
508             ];
509           }
510         }
511       },
512       dev: {
513         options: {
514           hostname: '0.0.0.0',
515           port: 9000,
516           base: 'build'
517         }
518       },
519       prod: {
520         options: {
521           port: 9001,
522           base: 'bin',
523           keepalive: true
524         }
525       }
526     },
527     open: {
528       dev: {
529         path: 'http://127.0.0.1:9000/'
530       },
531       prod: {
532         path: 'http://127.0.0.1:9001/'
533       }
534     },
535     /**
536      * And for rapid development, we have a watch set up that checks to see if
537      * any of the files listed below change, and then to execute the listed 
538      * tasks when they do. This just saves us from having to type "grunt" into
539      * the command-line every time we want to see what we're working on; we can
540      * instead just leave "grunt watch" running in a background terminal. Set it
541      * and forget it, as Ron Popeil used to tell us.
542      *
543      * But we don't need the same thing to happen for all the files. 
544      */
545     delta: {
546       /**
547        * By default, we want the Live Reload to work for all tasks; this is
548        * overridden in some tasks (like this file) where browser resources are
549        * unaffected. It runs by default on port 35729, which your browser
550        * plugin should auto-detect.
551        */
552       options: {
553         livereload: true
554       },
555
556       /**
557        * When the Gruntfile changes, we just want to lint it. In fact, when
558        * your Gruntfile changes, it will automatically be reloaded!
559        */
560       gruntfile: {
561         files: 'OriginalGruntfile.js',
562         tasks: [ 'jshint:gruntfile' ],
563         options: {
564           livereload: false
565         }
566       },
567
568       /**
569        * When our JavaScript source files change, we want to run lint them and
570        * run our unit tests.
571        */
572       jssrc: {
573         files: [ 
574           '<%= app_files.js %>'
575         ],
576         tasks: [ 'jshint:src', 'karma:unit:run', 'copy:build_appjs' ]
577       },
578
579       /**
580        * When our CoffeeScript source files change, we want to run lint them and
581        * run our unit tests.
582        */
583       coffeesrc: {
584         files: [ 
585           '<%= app_files.coffee %>'
586         ],
587         tasks: [ 'coffeelint:src', 'coffee:source', 'karma:unit:run', 'copy:build_appjs' ]
588       },
589
590       /**
591        * When assets are changed, copy them. Note that this will *not* copy new
592        * files, so this is probably not very useful.
593        */
594       assets: {
595         files: [ 
596           'src/assets/**/*'
597         ],
598         tasks: [ 'copy:build_assets' ]
599       },
600
601       /**
602        * When index.html changes, we need to compile it.
603        */
604       html: {
605         files: [ '<%= app_files.html %>' ],
606         tasks: [ 'index:build' ]
607       },
608
609       /**
610        * When our templates change, we only rewrite the template cache.
611        */
612       tpls: {
613         files: [ 
614           '<%= app_files.atpl %>', 
615           '<%= app_files.ctpl %>'
616         ],
617         tasks: [ 'html2js' ]
618       },
619
620       /**
621        * When the CSS files change, we need to compile and minify them.
622        */
623       less: {
624         files: [ 'src/**/*.less' ],
625         tasks: [ 'less:development' ]
626       },
627
628       /**
629        * When a JavaScript unit test file changes, we only want to lint it and
630        * run the unit tests. We don't want to do any live reloading.
631        */
632       jsunit: {
633         files: [
634           '<%= app_files.jsunit %>'
635         ],
636         tasks: [ 'jshint:test', 'karma:unit:run' ],
637         options: {
638           livereload: false
639         }
640       },
641
642       /**
643        * When a CoffeeScript unit test file changes, we only want to lint it and
644        * run the unit tests. We don't want to do any live reloading.
645        */
646       coffeeunit: {
647         files: [
648           '<%= app_files.coffeeunit %>'
649         ],
650         tasks: [ 'coffeelint:test', 'karma:unit:run' ],
651         options: {
652           livereload: false
653         }
654       }
655     }
656   };
657
658   grunt.initConfig( grunt.util._.extend( taskConfig, userConfig ) );
659
660   /**
661    * In order to make it safe to just compile or copy *only* what was changed,
662    * we need to ensure we are starting from a clean, fresh build. So we rename
663    * the `watch` task to `delta` (that's why the configuration var above is
664    * `delta`) and then add a new task called `watch` that does a clean build
665    * before watching for changes.
666    */
667   grunt.renameTask( 'watch', 'delta' );
668   grunt.registerTask( 'watch', [ 'build', 'karma:unit', 'delta' ] );
669
670   grunt.registerTask('live', ['build', 'connect:dev', 'delta']);
671   /**
672    * The default task is to build and compile.
673    */
674   grunt.registerTask( 'default', [ 'build', 'compile' ] );
675
676   /**
677    * The `build` task gets your app ready to run for development and testing.
678    */
679   grunt.registerTask( 'build', [
680     'clean', 'html2js', 'jshint', 'coffeelint', 'coffee', 'less:development',
681     'concat:build_css', 'copy:build_app_assets', 'copy:build_vendor_assets',
682     'copy:build_appjs', 'copy:build_vendorimages', 'copy:build_vendorjs', 'copy:build_vendorcss', /*'copy:build_vendor_font',*/ 'index:build'/*, 'karmaconfig',
683     'karma:continuous'  */
684   ]);
685
686   /**
687    * The `compile` task gets your app ready for deployment by concatenating and
688    * minifying your code.
689    */
690   grunt.registerTask( 'compile', [
691       'less:development', 'copy:compile_assets', 'ngmin:compile', 'concat:compile_js', 'uglify', 'index:compile'
692   ]);
693
694   /**
695    * A utility function to get all app JavaScript sources.
696    */
697   function filterForJS ( files ) {
698     return files.filter( function ( file ) {
699       return file.match( /\.js$/ );
700     });
701   }
702
703   /**
704    * A utility function to get all app CSS sources.
705    */
706   function filterForCSS ( files ) {
707     return files.filter( function ( file ) {
708       return file.match( /\.css$/ );
709     });
710   }
711
712   /** 
713    * The index.html template includes the stylesheet and javascript sources
714    * based on dynamic names calculated in this Gruntfile. This task assembles
715    * the list into variables for the template to use and then runs the
716    * compilation.
717    */
718   grunt.registerMultiTask( 'index', 'Process index.html template', function () {
719     var dirRE = new RegExp( '^('+grunt.config('build_dir')+'|'+grunt.config('compile_dir')+')\/', 'g' );
720     var jsFiles = filterForJS( this.filesSrc ).map( function ( file ) {
721       return file.replace( dirRE, '' );
722     });
723     var cssFiles = filterForCSS( this.filesSrc ).map( function ( file ) {
724       return file.replace( dirRE, '' );
725     });
726
727     grunt.file.copy('src/index.html', this.data.dir + '/index.html', { 
728       process: function ( contents, path ) {
729         return grunt.template.process( contents, {
730           data: {
731             scripts: jsFiles,
732             styles: cssFiles,
733             version: grunt.config( 'pkg.version' )
734           }
735         });
736       }
737     });
738
739     grunt.file.copy('src/login.html', this.data.dir + '/login.html', { 
740       process: function ( contents, path ) {
741         return grunt.template.process( contents, {
742           data: {
743             scripts: jsFiles,
744             styles: cssFiles,
745             version: grunt.config( 'pkg.version' )
746           }
747         });
748       }
749     });
750   });
751
752   /**
753    * In order to avoid having to specify manually the files needed for karma to
754    * run, we use grunt to manage the list for us. The `karma/*` files are
755    * compiled as grunt templates for use by Karma. Yay!
756    */
757   grunt.registerMultiTask( 'karmaconfig', 'Process karma config templates', function () {
758     var jsFiles = filterForJS( this.filesSrc );
759     
760     grunt.file.copy( 'karma/karma-unit.tpl.js', grunt.config( 'build_dir' ) + '/karma-unit.js', { 
761       process: function ( contents, path ) {
762         return grunt.template.process( contents, {
763           data: {
764             scripts: jsFiles
765           }
766         });
767       }
768     });
769   });
770
771 };