var extend = require('extend'), runSequence = require('run-sequence'), fs = require('fs'), moment = require('moment'), less = require('gulp-less'), cssmin = require('gulp-cssmin'), csscomb = require('gulp-csscomb'), autoprefixer = require('gulp-autoprefixer'), concat = require('gulp-concat'), header = require('gulp-header'), uglify = require('gulp-uglify'), rename = require('gulp-rename'), lessPluginCleanCSS = require('less-plugin-clean-css'), mkdirp = require('mkdirp'), del = require('del'), format = require('string-format').extend(String.prototype), colors = require('colors'), gulp = require('gulp'), zui = require('./zui.json'), pkg = require('./package.json'); // Disable the 'possible EventEmitter memory leak detected' warning. gulp.setMaxListeners(0); // try load zui.custom.json and merge into zui. try { var zuicustom = require('./zui.custom.json'); if(zuicustom) extend(true, zui, zuicustom); } catch(e) {} var today = moment(); var typeSet = ['less', 'js', 'resource'], lib = zui.lib, builds = zui.builds, banner = ('/*!\n' + ' * {title} - v{version} - {date}\n' + ' * {homepage}\n' + ' * GitHub: {repo} \n' + ' * Copyright (c) {year} {author}; Licensed {license}\n' + ' */\n\n').format({ title: pkg.title || pkg.name, version: pkg.version, date: today.format('YYYY-MM-DD'), homepage: pkg.homepage, repo: pkg.repository.url, year: today.format('YYYY'), author: pkg.author, license: pkg.license }), statement = '/* Some code copy from Bootstrap v3.0.0 by @fat and @mdo. (Copyright 2013 Twitter, Inc. Licensed under http://www.apache.org/licenses/)*/\n\n'; function tryStatSync(path) { try { return fs.statSync(path); } catch(e) { return false; } } function isFileExist(path) { var stats = tryStatSync(path); return stats && stats.isFile(); } function getItemList(list, items, ignoreDpds) { items = items || []; if (Array.isArray(list)) { list.forEach(function(name) { getItemList(name, items, ignoreDpds); }); } else { var item = lib[list]; if (item && items.indexOf(list) < 0) { if (!ignoreDpds && item.dpds) { getItemList(item.dpds, items, ignoreDpds); } if (item.src) items.push(list); } } return items; } function getBuildSource(build) { var list = []; var sources = { less: [], js: [], resource: [] }; if (!Array.isArray(list)) list = [list]; if (build.basicDpds) list = getItemList(build.basicDpds, list); list = getItemList(build.includes, list, build.ignoreDpds); list.forEach(function(item) { var libItem = lib[item]; if (libItem && libItem.src) { typeSet.forEach(function(type) { if (libItem.src[type]) { libItem.src[type].forEach(function(file) { if (sources[type].indexOf(file) < 0) { sources[type].push(file); } }); } }); } }); return sources; } function getSourceConfig(src) { var idx = src.lastIndexOf('//'); if (idx > 0) { return { base: src.substr(0, idx + 1), src: src.replace(/\/\//g, '/') }; } idx = src.lastIndexOf('/'); return { base: src.substr(0, idx + 1), src: src } } function getBuildPath(build, type) { var path = build.dest; if (build.subdirectories) { path += '/' + type + '/'; } if(path.indexOf('.') !== 0) { path = './' + path; } return path.replace(/\/\//g, '/').replace(/\/\//g, '/'); } function getBuildDestFilename(build, type, suffix) { var file = getBuildPath(build, type); file += '/' + build.filename + '.' + (suffix || type); return file.replace(/\/\//g, '/'); } function buildBundle(name, callback, type) { name = name|| 'all'; var build = builds[name]; // clean files if(name === 'dist') { del.sync('./dist/**/*'); } else if(name === 'doc') { del.sync([ './docs/js/**/*', './docs/css/**/*', './docs/fonts/**/*']); } if(!build) { if(name === 'all') { console.log('========== BUILD ALL =========='.blue.bold); var buildList = Object.keys(builds); var taskList = []; buildList.forEach(function(nm) { build = builds[nm]; if(build && !build.bundles) { var taskName = 'build:' + nm; gulp.task(taskName, function(cb) { buildBundle(nm, cb, type) }); taskList.push(taskName); } }); if(taskList.length) runSequence(taskList, function() { console.log(('√ Build ' + 'ALL'.bold + ' success! ').green); callback && callback(); }); return; } else { var buildLib = lib[name]; if (buildLib) { build = { title: buildLib.name, dest: 'dist/lib/' + name + '/', filename: name, includes: [name], thirdpart: buildLib.thirdpart }; } else { console.log(('Cannot found the build config: ' + name).red); return false; } } } else if (build.bundles) { console.log(('=== BUILD BUNDLES ' + name.toUpperCase() + ' (' + build.title + ') ===').blue.bold); var taskList = []; build.bundles.forEach(function(bundleName) { build = builds[bundleName]; if(build) { var taskName = 'build:' + bundleName; gulp.task(taskName, function(cb) { buildBundle(bundleName, cb, type); }); taskList.push(taskName); } }); if(taskList.length) runSequence(taskList, function() { console.log(('√ Build BUNDLES ' + name.toUpperCase().bold + ' (' + build.title + ') success! ').green); callback && callback(); }); return; } console.log(('--- build ' + name + ' ---').cyan.bold); var source = getBuildSource(build), bannerContent = build.thirdpart ? '' : banner + (build.bootstrapStatement ? statement : ''), taskList = [], depTaskList = []; if(source.js && source.js.length && (!type || type === 'js')) { console.log(('+ Ready to process ' + source.js.length + ' javascript files.').bold); source.js.forEach(function(f, idx) { if(f.indexOf('~/') === 0) { source.js[idx] = f = 'src/js/' + f.substr(2); } console.log((' - ' + f).italic); }); //ar taskName = 'build:' + name + ':js'; gulp.task('build:' + name + ':js', function() { var destPath = getBuildPath(build, 'js'); return gulp.src(source.js) .pipe(concat(build.filename + '.js')) .pipe(header(bannerContent)) .pipe(gulp.dest(destPath)) .pipe(uglify()) .pipe(rename({suffix: '.min'})) .pipe(header(bannerContent)) .pipe(gulp.dest(destPath)); }); taskList.push('build:' + name + ':js'); } if(source.less && source.less.length && (!type || type === 'less')) { var lessFileContent = '// \n// ' + build.title + '\n// Build config: ' + name + '\n//\n// This file generated by ZUI builder automatically at ' + today.toString() + '.\n//\n\n'; console.log(('+ Ready to process ' + source.less.length + ' less files.').bold); source.less.forEach(function(f, idx) { if(f.indexOf('~/') === 0) { source.less[idx] = f = 'src/less/' + f.substr(2); } if(isFileExist(f)) { lessFileContent += '@import "'; lessFileContent += '../../' + f; lessFileContent += '";\n'; console.log((' - ' + f).italic); } else { lessFileContent += '// @import "'; lessFileContent += '../../' + f; lessFileContent += '" // FILE NOT FOUND;\n'; console.log((' ! ' + f + ' [NOT FOUND]').red.italic); } }); gulp.task('build:' + name + ':less', function() { var buildSourceFilePath = './build/less/' + build.filename + '.less'; var destPath = getBuildPath(build, 'css'); mkdirp.sync('./build/less/'); fs.writeFileSync(buildSourceFilePath, lessFileContent); return gulp.src(buildSourceFilePath) .pipe(less()) .pipe(autoprefixer({browsers: ['> 1%'], cascade: true})) .pipe(csscomb()) .pipe(header(bannerContent)) .pipe(rename(build.filename + '.css')) .pipe(gulp.dest(destPath)) .pipe(cssmin()) .pipe(rename({suffix: '.min'})) .pipe(header(bannerContent)) .pipe(gulp.dest(destPath)); }); taskList.push('build:' + name + ':less'); } if(source.resource && source.resource.length && (!type || type === 'resource')) { console.log(('+ Ready to process ' + source.resource.length + ' resource files.').bold); var destPath = getBuildPath(build, ''); source.resource.forEach(function(f, idx) { if(f.indexOf('~/') === 0) { source.resource[idx] = f = 'src//' + f.substr(2); } console.log((' - [' + idx + '] ' + f).italic); gulp.task('build:' + name + ':resource:' + idx, function() { var sourceConfig = getSourceConfig(f); return gulp.src(sourceConfig.src, {base: sourceConfig.base}) .pipe(gulp.dest(destPath)); }); taskList.push('build:' + name + ':resource:' + idx); }); } if(taskList.length || depTaskList.length) { var completeCallback = function() { console.log(('√ Build ' + name.bold + ' success! ').green); callback && callback(); }; if(taskList.length) { if(depTaskList.length) { runSequence(depTaskList, taskList, completeCallback); } else { runSequence(taskList, completeCallback); } } else { runSequence(depTaskList, completeCallback); } } else { console.log(('No source files for build: ' + name).red); callback && callback(); } } gulp.task('build', function(callback) { var name = process.argv[3] || 'dist'; if(name && name[0] === '-') name = name.substr(1); var type = process.argv.length > 4 ? process.argv[4] : false; if(type && type[0] === '-') type = type.substr(1); console.log(('>> Build ' + name.bold + ' BEGIN ').inverse); buildBundle(name, callback, type); }); ['dist', 'doc'].forEach(function(name) { gulp.task(name, function(callback) { console.log(('>> Build ' + name.bold + ' BEGIN ').inverse); buildBundle(name, callback); }); gulp.task('watch:' + name, function() { gulp.watch(["./src/less/**/*"], function(event) { buildBundle(name, function() { console.log((' √ WATCH ' + name.bold + ' COMPLETED!').yellow.inverse); }, 'less'); }); gulp.watch(["./src/js/**/*"], function(event) { buildBundle(name, function() { console.log((' √ WATCH ' + name.bold + ' COMPLETED!').yellow.inverse); }, 'js'); }); gulp.watch(["./src/fonts/**/*"], function(event) { buildBundle(name, function() { console.log((' √ WATCH ' + name.bold + ' COMPLETED!').yellow.inverse); }, 'resource'); }); }); }); gulp.task('default', function() { buildBundle('all'); });