UNPKG

springbokjs-base

Version:
536 lines (470 loc) 20.1 kB
/* jshint maxlen: 200 */ process.on('uncaughtException', function(err) { console.error('uncaughtException:', err && (err.stack || err.message || err)); }); require('es6-shim/es6-shim'); var S = require('springbokjs-utils'); var fs = require('springbokjs-utils/fs'); var tinylr = require('tiny-lr'); var rimraf = require('rimraf'); var plugins = require('gulp-load-plugins')({ config: __dirname + '/package.json' }); var gutil = require('gulp-util'); // var recess = require('gulp-recess'); // var rename = require('gulp-rename'); var notifier = require('node-notifier'); // var INotifyWait = require('inotifywait'); var argv = require('minimist')(process.argv.slice(2), { alias: { production: 'prod' } }); var startport, startlivereloadPort; var init = function(gulp, options) { init = function() {}; gulp.task('define-port', function(done) { if (startport || argv['socket-folder']) { return done(); } var portscanner = require('portscanner'); startport = argv.startport || 3000; portscanner.findAPortNotInUse(startport, startport + 50, '127.0.0.1', function(error, port) { startport = port; done(); }); }); gulp.task('define-livereload-port', function(done) { if (startlivereloadPort) { return done(); } var portscanner = require('portscanner'); startlivereloadPort = argv.startlivereloadPort || 3100; portscanner.findAPortNotInUse(startlivereloadPort, startlivereloadPort + 50, '127.0.0.1', function(err, port) { startlivereloadPort = port; done(); }); }); }; var spawnGulp = !argv.spawnedProcess && function(gulp) { return function() { var spawn = require('child_process').spawn; var childProcess, closed = true; var args = process.argv.slice(1); args.push('--spawnedProcess'); var spawnChildren = function(e) { console.log('spawn child'); // kill previous spawned process if (!closed && childProcess) { childProcess.on('close', function(code, signal) { setTimeout(spawnChildren, 1000); }); childProcess.kill(); return; } // `spawn` a child `gulp` process linked to the parent `stdio` closed = false; childProcess = spawn(process.argv[0], args, { stdio: 'inherit' }); childProcess.on('close', function(code, signal) { console.log('child process terminated due to receipt of signal ' + signal); closed = true; }); }; // gulp.watch('gulpfile.js', spawnChildren); spawnChildren(); }; }; module.exports = function(pkg, gulp, options) { var _notify = function(title, message) { notifier.notify({ // https://github.com/mikaelbr/node-notifier/blob/master/lib/notifiers/notify-send.js message: message === undefined ? title : message, title: title || 'Gulp', // expire: 2000, hint: 'int:transient:1' }); }; var logAndNotify = function(notifyMessage, doNotLog) { return function(err) { _notify('Gulp ERROR', notifyMessage || err); if (!doNotLog) { if (err && !err.fileName && !err.lineNumber && err.message && err.message !== '[object Object]') { console.warn(err.message); console.log(notifyMessage, typeof err.message, err); } else if (err.stack) { gutil.log(err.plugin); gutil.log(err.stack); } else { gutil.log(err); } } }; }; /* OPTIONS */ if (options.es6to5Options) { throw new Error('set options.babelOptions now, es6to5 is deprecated.'); } if (options.es6to5BrowserOptions) { throw new Error('set options.babelBrowserOptions now, es6to5 is deprecated.'); } options.babelOptions = options.babelOptions || {}; options.babelOptions = Object.assign(options.babelOptions, { blacklist: options.babelOptions.blacklist || [ 'regenerator' ], modules: options.babelOptions.modules || 'common' }); options.babelBrowserOptions = { }; var paths = Object.assign({ scripts: '**/*.js', templatesEJS: '**/*.ejs', templatesJSX: '**/*.jsx', public: 'public/', browser: {}, server: 'src/server/', config: 'src/config/', stylesIncludePath: ['bower_components/'] }, options.paths); paths.common = Object.assign({ src: false,/*{ browser: 'src/common/browser/', common: 'src/common/common/', server: 'src/common/server/', }*/ dest: 'lib/common/', // destination for server-side. }, paths.common); paths.browser = Object.assign({ src: 'src/browser/', dist: 'public/dist/', js: 'js/', mainscripts: pkg.name + '.js', styles: 'style/', templates: 'templates/', iconfont: 'iconfont/', mainstyle: 'main.less', images: 'images', }, paths.browser); if (!Array.isArray(paths.browser.mainscripts)) { paths.browser.mainscripts = [ paths.browser.mainscripts ]; } paths.server = paths.server !== false && Object.assign({ common: 'src/common/', dist: 'lib/', startfile: 'server.js', configdest: 'lib/' }, S.isString(paths.server) ? { src: paths.server } : paths.server); var prefix = options.prefix = options.prefix || ''; options.paths = paths; options.argv = argv; /* Config */ gulp.task(prefix + 'init-config', function(done) { if (!argv.env) { return done(); } fs.mkdir(paths.server.configdest) .catch(function() {}) .then(function() { return Promise.all([ fs.readYamlFile(paths.config + 'common.yml').catch(function() { }), fs.readYamlFile(paths.config + argv.env + '.yml'), fs.readYamlFile(paths.config + 'local.yml').catch(function() { }), ]).then(function(results) { var config = {}; var includes = results[0] && results[0].includes || []; if (results[1].include) { includes.push.apply(includes, results[1].include); } if (results[2] && results[2].include) { includes.push.apply(includes, results[2].include); } return Promise.all(includes.map(function(file) { return fs.readYamlFile(paths.config + file + '.yml'); })).then(function(configs) { configs.push.apply(configs, results); 'common browser server'.split(' ').forEach(function(key) { config[key] = config[key] || {}; configs.forEach(function(configPart) { if (configPart && configPart[key]) { Object.assign(config[key], configPart[key]); } }); }); options.browserConfig = Object.assign({ basepath: '/', }, config.common || {}, config.browser || {}); options.browserConfig.webpath = options.browserConfig.webpath || options.browserConfig.basepath; options.serverConfig = Object.assign(config.common || {}, config.server || {}); return Promise.all([ fs.writeFile(paths.server.configdest + 'config.js', 'module.exports = ' + JSON.stringify(options.serverConfig, null, 4) + ';'), fs.writeFile(paths.browser.src + 'config-browser.js', '// Auto generated file from yaml\n' + 'module.exports = ' + JSON.stringify(options.browserConfig, null, 4) + ';'), ]); }); }); }) .then(function() { done(); }) .catch(function(err) { console.error(err.stack || err.message || err); done(err); }); }); /* Init : tasks only applied once */ init(gulp, options); var tasks = [ /* public */ require('./tasks/browser-public.js'), /* Styles */ require('./tasks/browser-styles.js'), /* iconfont */ require('./tasks/browser-iconfont.js'), /* Lint Scripts */ require('./tasks/lint-scripts.js'), /* Browser scripts */ require('./tasks/browser-scripts.js'), /* Server scripts */ require('./tasks/server-scripts.js'), /* Browser Templates */ require('./tasks/browser-templates.js'), /* Server Templates */ require('./tasks/server-templates.js'), ]; var watchTasks = []; tasks.forEach(function(task) { var result = task(gulp, plugins, options, logAndNotify, pkg); if (result) { watchTasks.push(result); } }); /* Images */ gulp.task(prefix + 'browser-images', function() { return gulp.src( paths.browser.src + paths.browser.images + '/**/*', { base: paths.browser.src + paths.browser.images } ) .pipe(gulp.dest(paths.public + 'images/')); }); gulp.task(prefix + 'browser-imagesmin', [prefix + 'browser-images'], function() { return gulp.src( paths.browser.src + paths.browser.images + '/**/*', { base: paths.browser.src + paths.browser.images } ) .pipe(plugins.imagemin({ progressive: true })) .pipe(gulp.dest(paths.public + 'images/')); }); /* Tasks */ if (argv['no-lint']) { gulp.task(prefix + 'browser-js', [prefix + 'browserifyjs']); } else { gulp.task(prefix + 'browser-js', [prefix + 'browser-lintjs', prefix + 'browserifyjs']); } // gulp.task(prefix + 'browser-css', [prefix + 'browser-concatcss']); if (paths.server) { if (argv['no-lint']) { gulp.task(prefix + 'server-js', [prefix + 'server-buildjs']); } else { gulp.task(prefix + 'server-js', [prefix + 'server-lintjs', prefix + 'server-buildjs']); } } // gulp.task('build', ['cssmin', 'jsmin', 'ejsmin', 'imagesmin']); var tasksPrebuild = [ prefix + 'browser-iconfont' ]; var tasksBuild = [ prefix + 'browser-public', prefix + 'browser-styles', prefix + 'browser-js', prefix + 'browser-templates', prefix + 'browser-images' ]; if (paths.browser.independantStyles) { tasksBuild.push(prefix + 'browser-independant-styles'); } if (argv.env) { tasksBuild.unshift(prefix + 'init-config'); } if (paths.server !== false) { tasksBuild.push.apply(tasksBuild, [ prefix + 'server-js', prefix + 'server-templates', ]); } gulp.task(prefix + 'pre-build', tasksPrebuild); gulp.task(prefix + 'build', tasksBuild); gulp.task(prefix + 'default', ['build']); gulp.task(prefix + 'lint', [prefix + 'lintjs']); gulp.task(prefix + 'clean', function(done) { Promise.all([ paths.server && paths.server.dist, paths.common && paths.common.dist, paths.server && paths.server.configdest && paths.server.configdest + 'config.js', paths.browser.dist, ].map(function(path) { if (path) { console.log('Removing ' + path); return new Promise(function(resolve, reject) { rimraf(path, function(err) { if (err) { reject(err); } else { resolve(err); } }); }); } })).then(function() { done(); }).catch(done); }); /* Watcher */ if (spawnGulp) { gulp.task(prefix + 'watch', spawnGulp(gulp)); } else { gulp.task( prefix + 'watch', ['define-port', 'define-livereload-port', prefix + 'init-config', prefix + 'default'], function() { var logfileChanged = function(from) { return function(file) { console.log('[watch] ' + from + ': ' + file.path); }; }; var port = startport + (options.multiIndex || 0); var livereloadPort = startlivereloadPort + (options.multiIndex || 0); console.log('create livereload server on port ' + livereloadPort); var livereloadServer = tinylr({ port: livereloadPort }); var changed = function(filePath) { if (filePath.substr(-4) === '.map') { // ignore reload for source map files return; } console.log('[livereload] ' + filePath); livereloadServer.changed({ params: { files: [ filePath ] } }); }; var daemon; if (paths.server) { var socketFolder = argv['socket-folder'] && argv['socket-folder'].replace(/\/+$/, '') + '/'; var socketName = prefix && prefix.replace(/[\-_]+$/, '') || 'socket'; daemon = require('springbokjs-daemon').node([ '--harmony', paths.server.dist + paths.server.startfile, '--livereloadPort=' + livereloadPort, socketFolder ? '--socket-path=' + socketFolder + socketName + '.sock' : '--port=' + port, ]); process.on('exit', function(code) { daemon.stop(); livereloadServer.close(); }); } watchTasks.forEach(function(task) { task(logfileChanged); }); gulp.watch(paths.browser.src + paths.browser.images, [prefix + 'browser-images']) .on('change', logfileChanged('images')); livereloadServer.listen(livereloadPort, function() { if (paths.server) { daemon.start(); gulp.watch(paths.config + '*.yml', [prefix + 'init-config']); var restart = function(done) { console.log('restart asked'); daemon.restart(); daemon.once('stdout', function(data) { var string = data.toString().toLowerCase(); if (string.indexOf('listening') !== -1) { if (done) { done(); } _notify((prefix ? prefix + ': ' : '') + 'Server restarted'); } }); }; gulp.watch([ paths.server.dist + '**/*', paths.common.dest + '**/*' , paths.server.configdest + 'config.js', ]).on('change', function(file) { if (file.path.substr(-4) === '.map') { // ignore reload for source map files return; } logfileChanged('server')(file); restart(function() { changed(file.path); }); }); /* var nodeModulesDirectory = process.cwd() + '/node_modules'; var _timeoutRestart; var timeoutRestart = function() { if (_timeoutRestart) { clearTimeout(_timeoutRestart); } _timeoutRestart = setTimeout(restart, 600); }; var addWatcher = function(directory) { directory = fs.realpathSync(directory); console.log('add watcher ' + directory); var watcher = new INotifyWait(directory, { recursive: true }); watcher.on('error', console.error); watcher.on('add', function(filename) { console.log(filename + ' added'); timeoutRestart(); }); watcher.on('change', function(filename) { console.log(filename + ' changed'); timeoutRestart(); }); }; var watchNodeModules = new INotifyWait(nodeModulesDirectory, { recursive: false }); watchNodeModules.on('error', console.error); watchNodeModules.on('add', function(filename, stats) { console.log(filename + ' added'); if (stats.isDir) { addWatcher(filename); } }); var nodeModulesDirectories = fs.readdirSync(nodeModulesDirectory); nodeModulesDirectories.forEach(function(nodeModuleDirectory) { addWatcher(nodeModulesDirectory + '/' + nodeModuleDirectory + '/'); }); */ } else { var express = require('express'); var app = express(); app.use(express.static(paths.public)); app.use('/src', express.static('src/')); app.listen(port, gutil.log.bind(null, 'static server started, listening on port ' + gutil.colors.magenta(port))); } }); gulp.watch(['data/**/*', paths.browser.dist + '**/*']) .on('change', function(file) { logfileChanged('data&dist')(file); changed(file.path); }); } ); } }; module.exports.multi = function(pkg, gulp, multi) { var prefixes = Object.keys(multi); prefixes.forEach(function(prefix, index) { var options = multi[prefix]; options.prefix = prefix + '-'; options.multiIndex = index; module.exports(pkg, gulp, options); }); 'default pre-build build watch clean lint'.split(' ').forEach(function(task) { var tasks = prefixes.map(function(prefix) { return prefix + '-' + task; }); if (task === 'watch') { if (spawnGulp) { tasks = spawnGulp(gulp); } else { tasks.unshift('define-livereload-port'); tasks.unshift('define-port'); } } gulp.task(task, tasks); }); };