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