3ec87742e8bd80e42947da75bf18404add84398a
[src/app-framework-demo.git] / afm-client / gulpfile.js
1 // BUG Symlink not working
2
3 var gulp = require('gulp');
4 var debug = require('gulp-debug');
5 var plugins = require('gulp-load-plugins')();
6 var del = require('del');
7 var es = require('event-stream');
8 var bowerFiles = require('main-bower-files');
9 var print = require('gulp-print');
10 var Q = require('q');
11 var imagemin = require('gulp-imagemin'), pngquant = require('imagemin-pngquant');
12 var taskListing = require('gulp-task-listing');
13 var symlink = require('gulp-sym');
14 var rename = require("gulp-rename");
15
16 // addon for Foundation6
17 var router   = require('front-router');
18
19 // == PATH STRINGS ========
20 var appdir  = "./app/";   // Warning to not forget trailling '/'
21 config=require (appdir + "etc/_Config"); // upload user local preferences if any
22
23 // Run node in debug mode in developpement mode ?
24 var nodeopts = config.DEBUG !== undefined ? '--debug='+config.DEBUG : ''; 
25 var frontend= appdir + config.FRONTEND;
26 var backend = appdir + config.BACKEND;
27
28 var paths = {
29     application : frontend,
30     scripts     : frontend+'/**/*.js',
31     appStyles   : [frontend+'/**/*.scss', '!'+frontend+'/styles/*/*-conf.scss'],
32     globalStyles: [frontend+'/styles/**/*.scss'],
33     images      : [frontend+'/**/*.png',frontend+'/**/*.jpg',frontend+'/**/*.jpeg',frontend+'/**/*.svg',frontend+'/**/*.ttf'],
34     index       : frontend+'/index.html',
35     partials    : [frontend + '/**/*.html', '!' + frontend +'/index.html'],
36     distDev     : './dist.dev',
37     distProd    : './dist.prod',
38     scriptsDevServer: backend + '/**/*.js',
39     sass:  [frontend+'/styles', 'bower_components/foundation-apps/scss','bower_components/foundation-icon-fonts'],
40     fonts: ['bower_components/**/*.woff'],
41     favicon: frontend+'/favicon.ico'
42 };
43
44 paths['distAppDev']  = paths.distDev + config.URLBASE;
45 paths['distAppProd'] = paths.distProd + config.URLBASE;
46
47 // Run node in debug mode in developpement mode ?
48 var nodeopts = config.DEBUG !== undefined ? '--debug='+config.DEBUG : ''; 
49
50 // == PIPE SEGMENTS ========
51 var pipes = {};
52
53 pipes.orderedVendorScripts = function() {
54     return plugins.order(['jquery.js', 'angular.js']);
55 };
56
57 pipes.orderedAppScripts = function() {
58     return plugins.angularFilesort();
59 };
60
61 pipes.minifiedFileName = function() {
62     return plugins.rename(function (path) {
63         path.extname = '.min' + path.extname;
64     });
65 };
66
67 pipes.validatedAppScripts = function() {
68     return gulp.src(paths.scripts)
69         .pipe(plugins.replace('@@APPNAME@@', config.APPNAME))
70         .pipe(plugins.jshint())
71         .pipe(plugins.jshint.reporter('jshint-stylish'));
72 };
73
74 pipes.builtAppScriptsDev = function() {
75     return pipes.validatedAppScripts()
76         .pipe(gulp.dest(paths.distAppDev));
77 };
78
79 pipes.builtAppScriptsProd = function() {
80     var scriptedPartials = pipes.scriptedPartials();
81     var validatedAppScripts = pipes.validatedAppScripts();
82
83     return es.merge(scriptedPartials, validatedAppScripts)
84         .pipe(plugins.ngAnnotate())
85         .pipe(pipes.orderedAppScripts())
86         .pipe(plugins.sourcemaps.init())
87         .pipe(plugins.concat(config.APPNAME+'.min.js'))
88         .pipe(plugins.uglify({compress: {drop_console: true}}))
89         .pipe(plugins.sourcemaps.write())
90         .pipe(gulp.dest(paths.distAppProd));
91 };
92
93 pipes.builtVendorScriptsDev = function() {
94     return gulp.src(bowerFiles())
95         .pipe(gulp.dest( paths.distDev +'/bower_components'));
96 };
97
98 pipes.builtVendorScriptsProd = function() {
99     return gulp.src(bowerFiles('**/*.js'))
100         .pipe(pipes.orderedVendorScripts())
101         .pipe(plugins.concat('vendor.min.js'))
102         .pipe(plugins.uglify())
103         .pipe(gulp.dest(paths.distProd+ '/bower_components'));
104 };
105
106 pipes.validatedDevServerScripts = function() {
107     return gulp.src(paths.scriptsDevServer)
108         .pipe(plugins.jshint())
109         .pipe(plugins.jshint.reporter('jshint-stylish'));
110 };
111
112 pipes.validatedPartials = function() {
113     return gulp.src(paths.partials)
114         .pipe(plugins.htmlhint({'doctype-first': false}))
115         .pipe(router({path: paths.application+'/etc/routes.js', root: paths.application}))
116         .pipe(plugins.htmlhint.reporter());
117 };
118
119 pipes.builtPartialsDev = function() {
120     return pipes.validatedPartials()
121         .pipe(gulp.dest(paths.distAppDev));
122 };
123
124 pipes.scriptedPartials = function() {
125     return pipes.validatedPartials()
126         .pipe(plugins.htmlhint.failReporter())
127         .pipe(plugins.htmlmin({collapseWhitespace: true, removeComments: true}))
128         .pipe(plugins.ngHtml2js({
129             moduleName: config.APPNAME,
130             template: "(function() {"
131                + "angular.module('<%= moduleName %>').run(['$templateCache', function($templateCache) {"
132                + "$templateCache.put('<%= template.url %>',\n    '<%= template.escapedContent %>');"
133                + "}]);\n"
134                + "})();\n"
135         }));    
136 };
137
138 pipes.builtAppStylesDev = function() {
139     return gulp.src(paths.appStyles)
140         .pipe(plugins.sass({includePaths: paths.sass}))
141         .pipe(gulp.dest(paths.distAppDev + '/styles'));
142 };
143
144 pipes.builtglobalStylesDev = function() {
145     return gulp.src(paths.globalStyles)
146         .pipe(plugins.sass({includePaths: paths.sass}))
147         .pipe(gulp.dest(paths.distDev  + '/global_styles'));
148 };
149
150 pipes.builtAppStylesProd = function() {
151     return gulp.src(paths.appStyles)
152         .pipe(plugins.sourcemaps.init())
153         .pipe(plugins.sass({includePaths: frontend + '/styles'}))
154         // .pipe(debug({title: '***** appStyle:'}))
155         .pipe(plugins.minifyCss())
156         .pipe(plugins.concat(config.APPNAME+'.css'))
157         .pipe(plugins.sourcemaps.write())
158         .pipe(pipes.minifiedFileName())
159         .pipe(gulp.dest(paths.distAppProd));
160 };
161
162 pipes.builtglobalStylesProd = function() {
163     return gulp.src(paths.globalStyles)
164         .pipe(plugins.sourcemaps.init())
165         .pipe(plugins.sass({includePaths: paths.sass}))
166         .pipe(plugins.minifyCss())
167         .pipe(plugins.sourcemaps.write())
168         .pipe(pipes.minifiedFileName())
169         .pipe(rename(function (path) {path.dirname="";return path;}))
170         .pipe(gulp.dest(paths.distProd + '/global_styles'));
171 };
172
173 pipes.processedFontsDev = function() {
174     return gulp.src(paths.fonts)
175         .pipe(rename(function (path) {path.dirname="";return path;}))
176         .pipe(gulp.dest(paths.distDev+'/bower_components'));
177 };
178
179 pipes.processedFontsProd = function() {
180     return gulp.src(paths.fonts)
181         .pipe(rename(function (path) {path.dirname="";return path;}))
182         .pipe(gulp.dest(paths.distProd+'/bower_components'));
183 };
184
185
186 pipes.processedImagesDev = function() {
187     return gulp.src(paths.images)
188         .pipe(gulp.dest(paths.distAppDev));
189 };
190
191 pipes.processedFaviconDev = function() {
192     return gulp.src(paths.favicon)
193         .pipe(gulp.dest(paths.distDev));
194 };
195
196 pipes.processedImagesProd = function() {
197     return gulp.src(paths.images)
198        .pipe(imagemin({
199             progressive: true,
200             svgoPlugins: [{removeViewBox: false}],
201             use: [pngquant()]
202         }))
203         .pipe(gulp.dest(paths.distAppProd));
204 };
205
206 pipes.processedFaviconProd = function() {
207     return gulp.src(paths.favicon)
208         .pipe(gulp.dest(paths.distProd));
209 };
210
211 // Create an Symlink when config.URLBASE exist
212 pipes.createDevSymLink = function() {
213     return gulp.src(paths.distDev).pipe(symlink(paths.distDev+config.URLBASE, {force: true}));
214 };
215
216 pipes.createProdSymLink = function() {
217     return gulp.src(paths.distProd).pipe(symlink(paths.distDev+config.URLBASE,{force: true}));
218 };
219
220 pipes.validatedIndex = function() {
221     return gulp.src(paths.index)       
222         .pipe(plugins.replace('@@APPNAME@@', config.APPNAME))
223         .pipe(plugins.replace('@@URLBASE@@', config.URLBASE))
224         .pipe(plugins.htmlhint())
225         .pipe(plugins.htmlhint.reporter());
226 };
227
228 pipes.builtIndexDev = function() {
229
230     var orderedVendorScripts = pipes.builtVendorScriptsDev()
231         .pipe(pipes.orderedVendorScripts());
232
233     var orderedAppScripts = pipes.builtAppScriptsDev()
234         .pipe(pipes.orderedAppScripts());
235
236     var appStyles    = pipes.builtAppStylesDev();
237     var globalStyles = pipes.builtglobalStylesDev();
238
239     return pipes.validatedIndex()
240          // Vendor and Global should have absolute path to rootdir application one are relative to BaseURL
241         .pipe(plugins.inject(orderedVendorScripts, {relative: false, ignorePath: "/dist.dev", name: 'bower'}))
242         .pipe(plugins.inject(globalStyles, {relative: false, ignorePath: "/dist.dev", name:'vendor'}))
243         .pipe(gulp.dest(paths.distAppDev)) // write first to get relative path for inject
244         .pipe(plugins.inject(orderedAppScripts, {relative: true}))
245         .pipe(plugins.inject(appStyles, {relative: true, name: 'appli'}))
246         .pipe(gulp.dest(paths.distAppDev));
247 };
248
249 pipes.builtIndexProd = function() {
250
251     var vendorScripts= pipes.builtVendorScriptsProd();
252     var appScripts   = pipes.builtAppScriptsProd();
253     var appStyles    = pipes.builtAppStylesProd();
254     var globalStyles = pipes.builtglobalStylesProd();
255
256     return pipes.validatedIndex()
257          // Vendor and Global should have absolute path to rootdir application one are relative to BaseURL
258         .pipe(plugins.inject(vendorScripts, {relative: false, ignorePath: "/dist.prod", name: 'bower'}))
259         .pipe(plugins.inject(globalStyles, {relative: false, ignorePath: "/dist.prod", name:'vendor'}))
260         .pipe(gulp.dest(paths.distAppProd)) // write first to get relative path for inject
261         .pipe(plugins.inject(appScripts, {relative: true}))
262         .pipe(plugins.inject(appStyles, {relative: true, name:'appli'}))
263         .pipe(plugins.htmlmin({collapseWhitespace: true, removeComments: true}))
264         .pipe(gulp.dest(paths.distAppProd));
265 };
266
267 pipes.builtAppDev = function() {
268     return es.merge(pipes.builtIndexDev(), pipes.builtPartialsDev(), pipes.processedFaviconDev(), pipes.processedImagesDev(), pipes.processedFontsDev() );
269 };
270
271 pipes.builtAppProd = function() {
272     return es.merge(pipes.builtIndexProd(), pipes.processedFaviconProd(), pipes.processedImagesProd(), pipes.processedFontsProd());
273 };
274
275
276 // == TASKS ========
277
278 // Add a task to render the output 
279 gulp.task('help', taskListing.withFilters(/-/));
280    
281 // clean, build of production environement
282 gulp.task('build', ['clean-build-app-prod', 'validate-devserver-scripts']);
283
284 gulp.task('run', function() {
285     // start nodemon to auto-reload the dev server
286     plugins.nodemon({ script: 'server.js', ext: 'js', watch: ['devServer/']})
287         .on('change', ['validate-devserver-scripts'])
288         .on('restart', function () {
289             console.log('[nodemon] restarted dev server');
290         });
291 });       
292
293 // removes all compiled dev files
294 gulp.task('clean-dev', function() {
295     var deferred = Q.defer();
296     del(paths.distDev, function() {
297         deferred.resolve();
298     });
299     return deferred.promise;
300 });
301
302 // removes all compiled production files
303 gulp.task('clean-prod', function() {
304     var deferred = Q.defer();
305     del(paths.distProd, function() {
306         deferred.resolve();
307     });
308     return deferred.promise;
309 });
310
311 // checks html source files for syntax errors
312 gulp.task('validate-partials', pipes.validatedPartials);
313
314 // checks index.html for syntax errors
315 gulp.task('validate-index', pipes.validatedIndex);
316
317 // moves html source files into the dev environment
318 gulp.task('build-partials-dev', pipes.builtPartialsDev);
319
320 // converts partials to javascript using html2js
321 gulp.task('convert-partials-to-js', pipes.scriptedPartials);
322
323 // runs jshint on the dev server scripts
324 gulp.task('validate-devserver-scripts', pipes.validatedDevServerScripts);
325
326 // runs jshint on the app scripts
327 gulp.task('validate-app-scripts', pipes.validatedAppScripts);
328
329 // moves app scripts into the dev environment
330 gulp.task('build-app-scripts-dev', pipes.builtAppScriptsDev);
331
332 // concatenates, uglifies, and moves app scripts and partials into the prod environment
333 gulp.task('build-app-scripts-prod', pipes.builtAppScriptsProd);
334
335 // compiles app sass and moves to the dev environment
336 gulp.task('build-app-styles-dev', pipes.builtAppStylesDev);
337
338 // compiles and minifies app sass to css and moves to the prod environment
339 gulp.task('build-app-styles-prod', pipes.builtAppStylesProd);
340
341 // moves vendor scripts into the dev environment
342 gulp.task('build-vendor-scripts-dev', pipes.builtVendorScriptsDev);
343
344 // concatenates, uglifies, and moves vendor scripts into the prod environment
345 gulp.task('build-vendor-scripts-prod', pipes.builtVendorScriptsProd);
346
347 // validates and injects sources into index.html and moves it to the dev environment
348 gulp.task('build-index-dev', pipes.builtIndexDev);
349
350 // validates and injects sources into index.html, minifies and moves it to the dev environment
351 gulp.task('build-index-prod', pipes.builtIndexProd);
352
353 // builds a complete dev environment
354 gulp.task('build-app-dev', pipes.builtAppDev);
355
356 // builds a complete prod environment
357 gulp.task('build-app-prod', pipes.builtAppProd);
358
359 // cleans and builds a complete dev environment
360 gulp.task('clean-build-app-dev', ['clean-dev'], pipes.builtAppDev);
361
362 // cleans and builds a complete prod environment
363 gulp.task('clean-build-app-prod', ['clean-prod'], pipes.builtAppProd);
364
365 // clean, build, and watch live changes to the dev environment
366 gulp.task('watch-dev', ['clean-build-app-dev', 'validate-devserver-scripts'], function() {
367
368     // start nodemon to auto-reload the dev server
369     plugins.nodemon({  exec: 'node ' + nodeopts, script: backend+'/server.js', ext: 'js', watch: [backend], env: {NODE_ENV : 'dev'} })
370         .on('change', ['validate-devserver-scripts'])
371         .on('restart', function () {
372             console.log('[nodemon] restarted dev server');
373         });
374
375     // start live-reload server
376     plugins.livereload.listen({ start: true });
377
378     // watch index
379     gulp.watch(paths.index, function() {
380         return pipes.builtIndexDev()
381             .pipe(plugins.livereload());
382     });
383
384     // watch app scripts
385     gulp.watch(paths.scripts, function() {
386         return pipes.builtAppScriptsDev()
387             .pipe(plugins.livereload());
388     });
389
390     // watch html partials
391     gulp.watch(paths.partials, function() {
392         return pipes.builtPartialsDev()
393             .pipe(plugins.livereload());
394     });
395     
396     // watch Images
397     gulp.watch(paths.images, function() {
398         return pipes.processedImagesDev()
399             .pipe(plugins.livereload());
400     });
401
402     // watch styles
403     gulp.watch(paths.appStyles, function() {
404         return pipes.builtAppStylesDev()
405             .pipe(plugins.livereload());
406     });
407
408 });
409
410 // clean, build, and watch live changes to the prod environment
411 gulp.task('watch-prod', ['clean-build-app-prod', 'validate-devserver-scripts'], function() {
412
413     // start nodemon to auto-reload the dev server
414     plugins.nodemon({ script: backend +'/server.js', ext: 'js', watch: [backend], env: {MODE : 'prod'} })
415         .on('change', ['validate-devserver-scripts'])
416         .on('restart', function () {
417             console.log('[nodemon] restarted dev server');
418         });
419
420     // start live-reload server
421     plugins.livereload.listen({start: true});
422
423     // watch index
424     gulp.watch(paths.index, function() {
425         return pipes.builtIndexProd()
426             .pipe(plugins.livereload());
427     });
428
429     // watch app scripts
430     gulp.watch(paths.scripts, function() {
431         return pipes.builtAppScriptsProd()
432             .pipe(plugins.livereload());
433     });
434
435     // watch hhtml partials
436     gulp.watch(paths.partials, function() {
437         return pipes.builtAppScriptsProd()
438             .pipe(plugins.livereload());
439     });
440     
441     // watch Images
442     gulp.watch(paths.images, function() {
443         return pipes.processedImagesProd()
444             .pipe(plugins.livereload());
445     });
446
447     // watch styles
448     gulp.watch(paths.appStyles, function() {
449         return pipes.builtAppStylesProd()
450             .pipe(plugins.livereload());
451     });
452     
453 });
454
455 // default task builds for prod
456 gulp.task('default', ['clean-build-app-prod']);