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