-
Notifications
You must be signed in to change notification settings - Fork 4
/
gulpfile.js
313 lines (279 loc) · 10.5 KB
/
gulpfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
var gulp = require('gulp'),
$ = require('gulp-load-plugins')(),
shell = require('gulp-shell'),
nodemon = require('gulp-nodemon'),
childProcess = require('child_process'),
mkdirp = require('mkdirp'),
mongoose = require('mongoose'),
express = require('express'),
protractor = require('gulp-protractor').protractor,
rimraf = require('rimraf'),
sequence = require('run-sequence'),
config = require('./config'),
fs = require('fs');
// GLOBAL CONFIGURATION
// - - - - - - - - - - - - - - -
var environment = 'development';
var envConfig = {
development: {
sassStyle: 'nested',
compress: false,
beautify: true,
comments: true,
mangle: false
},
staging: {
sassStyle: 'compressed',
compress: true,
beautify: false,
comments: false,
mangle: true
},
production: {
sassStyle: 'compressed',
compress: true,
beautify: false,
comments: false,
mangle: true
}
};
// MAIN TASKS
// - - - - - - - - - - - - - - -
// Default task: builds the app, starts a server, and recompiles assets when they change
// Used in development
gulp.task('default', ['start']);
// Run the end-to-end tests
// Note this does not work on Windows, you must run 'gulp' and 'webdriver-manager start' manually
// followed by 'gulp protractor'
gulp.task('tests', ['protractor'], function () {
// Quit all running proccesses on test completion
process.exit();
});
// TEARDOWN HANDLING
// - - - - - - - - - - - - - - -
// Process handles are global variables so we can kill them on exit from this process
var mongoProcess;
var webdriverProcess;
// Terminate any spawned processes as part of the tidy up when this process exits
process.on('exit', function () {
if (mongoProcess) {
mongoProcess.kill();
}
if (webdriverProcess) {
// Kill all processes in the webdriver group, as it spawns a child process
process.kill(-webdriverProcess.pid);
}
});
// DEVELOPMENT TASKS
// - - - - - - - - - - - - - - -
// Starts MongoDB, waits for mongo to have started fully
gulp.task('mongo', function (callback) {
mkdirp.sync('./db');
mongoProcess = childProcess.spawn('mongod', ['--dbpath=db', '--smallfiles']);
mongoProcess.stdout.on('data', function (data) {
// Uncomment the below if you need to debug mongo startup problems
//console.log('mongoSTDOUT:' + data);
if (String(data).indexOf('waiting for connections on port 27017') !== -1) {
callback();
} else if (String(data).indexOf('addr already in use') !== -1) {
// Linux machines start mongo with an init.d script
// Use the existing instance if it's running
console.log('BUILDSCRIPT: Mongo already running, script will utilise existing instance');
callback();
}
});
mongoProcess.stderr.on('data', function (data) {
console.log('mongoSTDERR:' + data);
});
});
// Starts the server, which you can view at http://localhost:8080
gulp.task('start', ['mongo', 'build'], function () {
// Watch for changes in HTML files
gulp.watch(['./public/*.html',
'./public/modules/**/*.html',
'./public/img/*'], ['build-copy']);
// Watch Sass
gulp.watch(['./public/scss/**/*'], ['build-sass']);
// Watch for javascript changes
gulp.watch(appJS, ['build-javascript']);
return nodemon({
script: 'server.js',
ext: 'js',
// Must specify default directories due to a bug in nodemon
ignore: ['.sass-cache/*',
'bower_components/*',
'build/*',
'node_modules',
'public/*',
'tests/*'],
env: { 'NODE_ENV': 'development' },
// Enable the node debugger
nodeArgs: ['--debug']
});
});
// TEST TASKS
// - - - - - - - - - - - - - - -
// Drop the database
gulp.task('database-drop', ['mongo'], function (callback) {
// Get the environment from the express environment variable for consistency with the app
var app = express();
var environment = app.get('env');
mongoose.connect(config.mongodb[environment].url);
mongoose.connection.on('open', function () {
mongoose.connection.db.dropDatabase(function (err) {
if (err) {
callback(err);
} else {
mongoose.connection.close(callback);
}
});
});
});
// Start the selenium webdriver
gulp.task('webdriver', function (callback) {
// The webdriver spanws child processes so make it the group leader so we can kill them all on exit
webdriverProcess = childProcess.spawn('webdriver-manager', ['start'], {detached: true});
var webdriverStartedString = 'Started org.openqa.jetty.jetty.Server';
webdriverProcess.stdout.on('data', function (data) {
console.log('webdriverSTDOUT:' + data);
});
webdriverProcess.stderr.on('data', function (data) {
// For some reason the web driver writes its output to standard error
if (String(data).indexOf(webdriverStartedString) !== -1) {
callback();
}
});
});
// Run the protractor tests
gulp.task('protractor', ['database-drop', 'start', 'webdriver'], function () {
// Must pass no files to gulp protractor so we can order tests in the protractor conf
return gulp.src([])
.pipe(protractor({
configFile: "./tests/protractor.conf.js",
args: ['--baseUrl', 'http://localhost:8080']
}))
.on('error', function (e) {
throw e });
});
// PRODUCTION TASKS
// - - - - - - - - - - - - - - -
// Performs a production build, pass in callback so we can block until the build is complete
gulp.task('production-build', function (callback) {
environment = 'production';
sequence('build', callback);
});
// STAGING TASKS
// - - - - - - - - - - - - - - -
// Performs a staging build, pass in callback so we can block until the build is complete
gulp.task('staging-build', function (callback) {
environment = 'staging';
sequence('build', callback);
});
// BUILD CONFIGURATION
// - - - - - - - - - - - - - - -
// Sass will check these folders for files when @import is used
var sassPaths = [
'./public/scss',
'./bower_components/foundation-apps/scss'
];
// These files include Foundation for Apps, AngularJS and external javascript libraries.
var librariesJS = [
// JQuery must come before Angular so it is used rather than the built in jQuery Lite
'./bower_components/jquery/dist/jquery.js',
'./bower_components/fastclick/lib/fastclick.js',
'./bower_components/viewport-units-buggyfill/viewport-units-buggyfill.js',
'./bower_components/tether/tether.js',
'./bower_components/angular/angular.js',
'./bower_components/hammerjs/hammer.js',
'./bower_components/angular-animate/angular-animate.js',
'./bower_components/angular-resource/angular-resource.js',
'./bower_components/angular-sanitize/angular-sanitize.js',
'./bower_components/angular-ui-router/release/angular-ui-router.js',
'./bower_components/foundation-apps/js/vendor/**/*.js',
'./bower_components/foundation-apps/js/angular/**/*.js',
'!./bower_components/foundation-apps/js/angular/app.js'
];
// Application Javascript, ensure AngularJS modules are defined before controllers
var appJS = [
'./public/modules/**/module.js',
'./public/modules/**/controller.js',
'./public/modules/**/*.js' // Any other javascript
];
// BUILD TASKS
// - - - - - - - - - - - - - - -
// Cleans the build directory
gulp.task('build-clean', function (callback) {
rimraf('./build', callback);
});
// Creates the build directory
gulp.task('build-create-dir', function () {
if (!fs.existsSync('./build')) {
fs.mkdirSync('./build');
}
});
// Copies application files and Foundation assets
gulp.task('build-copy', function () {
// Main application HTML and images
gulp.src(['./public/*.html',
'./public/modules/**/*.html'], {
base: './public/'
})
.pipe(gulp.dest('./build'));
// Application images
gulp.src('./public/img/*')
.pipe(gulp.dest('./build/assets/img/'));
// Foundation's Angular partials
return gulp.src(['./bower_components/foundation-apps/js/angular/components/**/*.html'])
.pipe(gulp.dest('./build/components/'));
});
// Compiles Sass
gulp.task('build-sass', function () {
return gulp.src('./public/scss/app.scss')
.pipe($.sass({
includePaths: sassPaths,
style: envConfig[environment].sassStyle,
errLogToConsole: true
}))
.pipe($.autoprefixer({
browsers: ['last 2 versions', 'ie 10']
}))
.pipe(gulp.dest('./build/assets/css/'));
});
// Copies the Foundation for Apps / Angular JavaScript and the application javascript
// Ensures the application javascript is concatenated before this task runs
gulp.task('build-javascript', function () {
// External library JavaScript
gulp.src(librariesJS)
.pipe($.uglify({
compress: envConfig[environment].compress,
output: {
beautify: envConfig[environment].beautify,
comments: envConfig[environment].comments
},
mangle: envConfig[environment].mangle
}).on('error', function(e) {
console.log(e);
}))
.pipe($.concat('external.js'))
.pipe(gulp.dest('./build/assets/js/'));
// App JavaScript
return gulp.src(appJS)
.pipe($.uglify({
compress: envConfig[environment].compress,
output: {
beautify: envConfig[environment].beautify,
comments: envConfig[environment].comments
},
mangle: envConfig[environment].mangle
}).on('error', function(e) {
console.log(e);
}))
.pipe($.concat('internal.js'))
.pipe(gulp.dest('./build/assets/js/'));
});
// Builds the entire app, pass in callback so we can block until build is complete
gulp.task('build', function (callback) {
sequence('build-clean',
'build-create-dir',
['build-copy', 'build-sass', 'build-javascript'], callback);
});