feat(build): added build tasks

pull/3/head
Vladimir Lugovsky 2015-12-10 19:22:20 +03:00
parent 16b2388d24
commit 1935514ca8
10 changed files with 392 additions and 191 deletions

98
gulp/build.js Normal file
View File

@ -0,0 +1,98 @@
'use strict';
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var $ = require('gulp-load-plugins')({
pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del']
});
gulp.task('partials', function () {
return gulp.src([
path.join(conf.paths.src, '/app/**/*.html'),
path.join(conf.paths.tmp, '/serve/app/**/*.html')
])
.pipe($.minifyHtml({
empty: true,
spare: true,
quotes: true
}))
.pipe($.angularTemplatecache('templateCacheHtml.js', {
module: 'angularBestPractices',
root: 'app'
}))
.pipe(gulp.dest(conf.paths.tmp + '/partials/'));
});
gulp.task('html', ['inject', 'partials'], function () {
var partialsInjectFile = gulp.src(path.join(conf.paths.tmp, '/partials/templateCacheHtml.js'), { read: false });
var partialsInjectOptions = {
starttag: '<!-- inject:partials -->',
ignorePath: path.join(conf.paths.tmp, '/partials'),
addRootSlash: false
};
var htmlFilter = $.filter('*.html', { restore: true });
var jsFilter = $.filter('**/*.js', { restore: true });
var cssFilter = $.filter('**/*.css', { restore: true });
var assets;
return gulp.src(path.join(conf.paths.tmp, '/serve/*.html'))
.pipe($.inject(partialsInjectFile, partialsInjectOptions))
.pipe(assets = $.useref.assets())
.pipe($.rev())
.pipe(jsFilter)
.pipe($.sourcemaps.init())
.pipe($.ngAnnotate())
.pipe($.uglify({ preserveComments: $.uglifySaveLicense })).on('error', conf.errorHandler('Uglify'))
.pipe($.sourcemaps.write('maps'))
.pipe(jsFilter.restore)
.pipe(cssFilter)
.pipe($.sourcemaps.init())
.pipe($.replace('../../bower_components/bootstrap-sass/assets/fonts/bootstrap/', '../fonts/'))
.pipe($.minifyCss({ processImport: false }))
.pipe($.sourcemaps.write('maps'))
.pipe(cssFilter.restore)
.pipe(assets.restore())
.pipe($.useref())
.pipe($.revReplace())
.pipe(htmlFilter)
.pipe($.minifyHtml({
empty: true,
spare: true,
quotes: true,
conditionals: true
}))
.pipe(htmlFilter.restore)
.pipe(gulp.dest(path.join(conf.paths.dist, '/')))
.pipe($.size({ title: path.join(conf.paths.dist, '/'), showFiles: true }));
});
// Only applies for fonts from bower dependencies
// Custom fonts are handled by the "other" task
gulp.task('fonts', function () {
return gulp.src($.mainBowerFiles())
.pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}'))
.pipe($.flatten())
.pipe(gulp.dest(path.join(conf.paths.dist, '/fonts/')));
});
gulp.task('other', function () {
var fileFilter = $.filter(function (file) {
return file.stat.isFile();
});
return gulp.src([
path.join(conf.paths.src, '/**/*'),
path.join('!' + conf.paths.src, '/**/*.{html,css,js,scss}')
])
.pipe(fileFilter)
.pipe(gulp.dest(path.join(conf.paths.dist, '/')));
});
gulp.task('clean', function () {
return $.del([path.join(conf.paths.dist, '/'), path.join(conf.paths.tmp, '/')]);
});
gulp.task('build', ['html', 'fonts', 'other']);

41
gulp/conf.js Normal file
View File

@ -0,0 +1,41 @@
/**
* This file contains the variables used in other gulp files
* which defines tasks
* By design, we only put there very generic config values
* which are used in several places to keep good readability
* of the tasks
*/
var gutil = require('gulp-util');
/**
* The main paths of your project handle these with care
*/
exports.paths = {
src: 'src',
dist: 'release',
tmp: '.tmp',
e2e: 'e2e'
};
/**
* Wiredep is the lib which inject bower dependencies in your project
* Mainly used to inject script tags in the index.html but also used
* to inject css preprocessor deps and js files in karma
*/
exports.wiredep = {
exclude: [/jquery/, /\/bootstrap\.js$/, /\/bootstrap-sass\/.*\.js/, /\/bootstrap\.css/],
directory: 'bower_components'
};
/**
* Common implementation for an error handler of a Gulp plugin
*/
exports.errorHandler = function(title) {
'use strict';
return function(err) {
gutil.log(gutil.colors.red('[' + title + ']'), err.toString());
this.emit('end');
};
};

36
gulp/inject.js Normal file
View File

@ -0,0 +1,36 @@
'use strict';
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var $ = require('gulp-load-plugins')();
var wiredep = require('wiredep').stream;
var _ = require('lodash');
gulp.task('inject', ['scripts', 'styles'], function () {
var injectStyles = gulp.src([
path.join(conf.paths.tmp, '/serve/app/**/*.css'),
path.join('!' + conf.paths.tmp, '/serve/app/vendor.css')
], { read: false });
var injectScripts = gulp.src([
path.join(conf.paths.src, '/app/**/*.module.js'),
path.join(conf.paths.src, '/app/**/*.js'),
path.join('!' + conf.paths.src, '/app/**/*.spec.js'),
path.join('!' + conf.paths.src, '/app/**/*.mock.js'),
])
.pipe($.angularFilesort()).on('error', conf.errorHandler('AngularFilesort'));
var injectOptions = {
ignorePath: [conf.paths.src, path.join(conf.paths.tmp, '/serve')],
addRootSlash: false
};
return gulp.src(path.join(conf.paths.src, '/*.html'))
.pipe($.inject(injectStyles, injectOptions))
.pipe($.inject(injectScripts, injectOptions))
.pipe(wiredep(_.extend({}, conf.wiredep)))
.pipe(gulp.dest(path.join(conf.paths.tmp, '/serve')));
});

17
gulp/scripts.js Normal file
View File

@ -0,0 +1,17 @@
'use strict';
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var browserSync = require('browser-sync');
var $ = require('gulp-load-plugins')();
gulp.task('scripts', function () {
return gulp.src(path.join(conf.paths.src, '/app/**/*.js'))
.pipe($.eslint())
.pipe($.eslint.format())
.pipe(browserSync.reload({ stream: true }))
.pipe($.size())
});

55
gulp/server.js Normal file
View File

@ -0,0 +1,55 @@
'use strict';
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var browserSync = require('browser-sync');
var browserSyncSpa = require('browser-sync-spa');
var util = require('util');
var proxyMiddleware = require('http-proxy-middleware');
function browserSyncInit(baseDir, browser) {
browser = browser === undefined ? 'default' : browser;
var routes = null;
if(baseDir === conf.paths.src || (util.isArray(baseDir) && baseDir.indexOf(conf.paths.src) !== -1)) {
routes = {
'/bower_components': 'bower_components'
};
}
var server = {
baseDir: baseDir,
routes: routes
};
/*
* You can add a proxy to your backend by uncommenting the line below.
* You just have to configure a context which will we redirected and the target url.
* Example: $http.get('/users') requests will be automatically proxified.
*
* For more details and option, https://github.com/chimurai/http-proxy-middleware/blob/v0.0.5/README.md
*/
// server.middleware = proxyMiddleware('/users', {target: 'http://jsonplaceholder.typicode.com', proxyHost: 'jsonplaceholder.typicode.com'});
browserSync.instance = browserSync.init({
startPath: '/',
server: server,
browser: browser
});
}
browserSync.use(browserSyncSpa({
selector: '[ng-app]'// Only needed for angular apps
}));
gulp.task('serve', ['watch'], function () {
browserSyncInit([path.join(conf.paths.tmp, '/serve'), conf.paths.src]);
});
gulp.task('serve:dist', ['build'], function () {
browserSyncInit(conf.paths.dist);
});

46
gulp/styles.js Normal file
View File

@ -0,0 +1,46 @@
'use strict';
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var browserSync = require('browser-sync');
var $ = require('gulp-load-plugins')();
var wiredep = require('wiredep').stream;
var _ = require('lodash');
gulp.task('styles', function () {
var sassOptions = {
style: 'expanded'
};
var injectFiles = gulp.src([
path.join(conf.paths.src, '/app/**/*.scss'),
path.join('!' + conf.paths.src, '/app/index.scss')
], { read: false });
var injectOptions = {
transform: function(filePath) {
filePath = filePath.replace(conf.paths.src + '/app/', '');
return '@import "' + filePath + '";';
},
starttag: '// injector',
endtag: '// endinjector',
addRootSlash: false
};
return gulp.src([
path.join(conf.paths.src, '/app/index.scss')
])
.pipe($.inject(injectFiles, injectOptions))
.pipe(wiredep(_.extend({}, conf.wiredep)))
.pipe($.sourcemaps.init())
.pipe($.sass(sassOptions)).on('error', conf.errorHandler('Sass'))
.pipe($.autoprefixer()).on('error', conf.errorHandler('Autoprefixer'))
.pipe($.sourcemaps.write())
.pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/app/')))
.pipe(browserSync.reload({ stream: true }));
});

39
gulp/watch.js Normal file
View File

@ -0,0 +1,39 @@
'use strict';
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var browserSync = require('browser-sync');
function isOnlyChange(event) {
return event.type === 'changed';
}
gulp.task('watch', ['inject'], function () {
gulp.watch([path.join(conf.paths.src, '/*.html'), 'bower.json'], ['inject']);
gulp.watch([
path.join(conf.paths.src, '/app/**/*.css'),
path.join(conf.paths.src, '/app/**/*.scss')
], function(event) {
if(isOnlyChange(event)) {
gulp.start('styles');
} else {
gulp.start('inject');
}
});
gulp.watch(path.join(conf.paths.src, '/app/**/*.js'), function(event) {
if(isOnlyChange(event)) {
gulp.start('scripts');
} else {
gulp.start('inject');
}
});
gulp.watch(path.join(conf.paths.src, '/app/**/*.html'), function(event) {
browserSync.reload(event.path);
});
});

View File

@ -1,192 +1,23 @@
'use strict';
var gulp = require('gulp');
var wrench = require('wrench');
var sass = require('gulp-sass');
var autoprefix = require('gulp-autoprefixer');
var minifyCSS = require('gulp-minify-css');
var concat = require('gulp-concat');
var changed = require('gulp-changed');
var imagemin = require('gulp-imagemin');
var stripDebug = require('gulp-strip-debug');
var uglify = require('gulp-uglify');
var eventStream = require('event-stream');
var templateCache = require('gulp-angular-templatecache');
var minifyHTML = require('gulp-minify-html');
var zip = require('gulp-zip');
var prompt = require('gulp-prompt');
var rename = require('gulp-rename');
var bootstrapCssSrc = 'bower_components/bootstrap/dist/css/bootstrap.min.css';
gulp.task('minify-404-css', function () {
var vendorFiles = gulp.src(bootstrapCssSrc);
var appFiles = gulp.src('src/assets/css/404.scss').pipe(sass({ style: 'compressed' }).on('error', sass.logError));
return eventStream.concat(vendorFiles, appFiles)
.pipe(concat('404.min.css'))
.pipe(autoprefix('last 4 version'))
.pipe(minifyCSS())
.pipe(gulp.dest('release/css/'));
/**
* This will load all js or coffee files in the gulp directory
* in order to load all gulp tasks
*/
wrench.readdirSyncRecursive('./gulp').filter(function(file) {
return (/\.(js|coffee)$/i).test(file);
}).map(function(file) {
require('./gulp/' + file);
});
gulp.task('minify-auth-css', function () {
var vendorFiles = gulp.src(bootstrapCssSrc);
var appFiles = gulp.src('src/assets/css/auth.scss').pipe(sass({ style: 'compressed' }).on('error', sass.logError));
return eventStream.concat(vendorFiles, appFiles)
.pipe(concat('auth.min.css'))
.pipe(autoprefix('last 4 versions'))
.pipe(minifyCSS())
.pipe(gulp.dest('release/css/'))
/**
* Default task clean temporaries directories and launch the
* main optimization build task
*/
gulp.task('default', ['clean'], function () {
gulp.start('build');
});
gulp.task('minify-css', ['minify-404-css', 'minify-auth-css'], function () {
var vendorFiles = gulp.src([
bootstrapCssSrc,
'bower_components/bootstrap-select/dist/css/bootstrap-select.min.css',
'bower_components/bootstrap-switch/dist/css/bootstrap3/bootstrap-switch.min.css',
'bower_components/bootstrap-tagsinput/dist/bootstrap-tagsinput.css',
'bower_components/Ionicons/css/ionicons.min.css',
'bower_components/font-awesome/css/font-awesome.min.css',
'bower_components/animate.css/animate.min.css',
'bower_components/angular-progress-button-styles/dist/angular-progress-button-styles.min.css'
]);
var appFiles = gulp.src('src/assets/css/main.scss').pipe(sass({ style: 'compressed' }).on('error', sass.logError));
return eventStream.concat(vendorFiles, appFiles)
.pipe(concat('index.min.css'))
.pipe(autoprefix('last 2 versions'))
.pipe(minifyCSS())
.pipe(gulp.dest('release/css/'))
});
var imgSrc = [
'src/assets/img/*',
'src/assets/pictures/*',
'src/app/tplSkin/thumbs/*',
'src/app/pages/dashboard/widgets/timeline/img/*',
'src/app/pages/profile/img/*',
'src/app/pages/icons/widgets/kameleon-img/*',
'bower_components/amcharts/dist/amcharts/images/*',
'bower_components/ammap/dist/ammap/images/*',
'bower_components/leaflet/dist/images/*'
];
gulp.task('imagemin', function () {
var imgDst = 'release/img/';
return gulp
.src(imgSrc)
.pipe(changed(imgDst))
.pipe(imagemin())
.pipe(gulp.dest(imgDst));
});
gulp.task('js-lib', function(){
var libSrc = [
'bower_components/jquery/dist/jquery.min.js',
'bower_components/angular/angular.min.js',
'bower_components/angular-route/angular-route.min.js',
'bower_components/angular-touch/angular-touch.min.js',
'bower_components/jquery-ui/jquery-ui.min.js',
'bower_components/bootstrap/dist/js/bootstrap.min.js',
'bower_components/highlight/src/highlight.js',
'bower_components/bootstrap-switch/dist/js/bootstrap-switch.min.js',
'bower_components/bootstrap-select/dist/js/bootstrap-select.min.js',
'bower_components/bootstrap-tagsinput/dist/bootstrap-tagsinput.min.js',
'bower_components/moment/min/moment.min.js',
'bower_components/amcharts/dist/amcharts/amcharts.js',
'bower_components/amcharts/dist/amcharts/plugins/responsive/responsive.min.js',
'bower_components/amcharts/dist/amcharts/serial.js',
'bower_components/amcharts/dist/amcharts/funnel.js',
'bower_components/amcharts/dist/amcharts/pie.js',
'bower_components/amcharts-stock/dist/amcharts/amstock.js',
'bower_components/ammap/dist/ammap/ammap.js',
'bower_components/ammap/dist/ammap/maps/js/worldLow.js',
'bower_components/jquery.easing/js/jquery.easing.min.js',
'bower_components/angular-ui-sortable/sortable.js',
'bower_components/jquery.easy-pie-chart/dist/jquery.easypiechart.min.js',
'bower_components/fullcalendar/dist/fullcalendar.min.js',
'bower_components/Chart.js/Chart.min.js',
'bower_components/leaflet/dist/leaflet.js',
'bower_components/angular-toastr/dist/angular-toastr.tpls.min.js',
'bower_components/angular-smart-table/dist/smart-table.min.js',
'bower_components/slimScroll/jquery.slimscroll.min.js',
'bower_components/angular-slimscroll/angular-slimscroll.js',
'bower_components/hammerjs/hammer.min.js',
'bower_components/AngularHammer/angular.hammer.min.js',
'bower_components/angular-progress-button-styles/dist/angular-progress-button-styles.min.js',
'src/app/components/backTop/lib/jquery.backTop.min.js'
];
return gulp.src(libSrc)
.pipe(concat('lib.min.js'))
.pipe(stripDebug())
.pipe(uglify())
.pipe(gulp.dest('release/js/'));
});
gulp.task('js', function () {
var src = [
'src/assets/js/global-variables.js',
'src/assets/js/amcharts-blur-theme.js',
'src/app/**/*.js',
'!src/app/**/lib/**/*.js'
];
gulp.src(src).pipe(concat('bundle.min.js')).pipe(uglify()).pipe(gulp.dest('release/js/'));
});
gulp.task('font', function () {
var fontSrc = [
'src/assets/css/fonts/*',
'bower_components/bootstrap/fonts/*',
'bower_components/font-awesome/fonts/*',
'bower_components/Ionicons/fonts/*',
];
var fontDst = 'release/fonts/';
gulp.src(fontSrc).pipe(gulp.dest(fontDst));
});
gulp.task('templateCache', function () {
return gulp.src('src/app/**/*.html')
.pipe(minifyHTML({ conditionals: true, spare: true, empty: true }))
.pipe(templateCache({ root: 'app/', module: 'BlurAdmin' }))
.pipe(gulp.dest('release/js'));
});
gulp.task('html', function () {
return gulp.src('src/*.html')
.pipe(minifyHTML({ conditionals: true, spare: true, empty: true }))
.pipe(gulp.dest('release/'));
});
gulp.task('watch', function () {
gulp.watch(['src/app/**/*.css', 'src/assets/**/*.css', './**/*.scss '], ['minify-css']);
gulp.watch(imgSrc, ['imagemin']);
gulp.watch(['src/app/**/*.js', 'src/assets/**/*.js'], ['js']);
gulp.watch(['src/app/**/*.html'], ['templateCache']);
gulp.watch(['src/*.html'], ['html']);
});
gulp.task('init', ['minify-css', 'imagemin', 'js-lib', 'js', 'font', 'templateCache', 'html']);
gulp.task('marketplace-release', ['init'], function() {
return gulp.src('')
.pipe(prompt.prompt({
type: 'input',
name: 'version',
message: 'Please enter release version (x.x.x)'
}, function(res){
var nameAndVersion = 'blur-admin-' + res.version;
return gulp
.src(['src/**', 'release/**', 'bower.json', 'package.json', 'README.md', '.gitignore'], { base : "." })
.pipe(rename(function (path) {
path.dirname = nameAndVersion + '/' + path.dirname;
}))
.pipe(zip(nameAndVersion + '.zip'))
.pipe(gulp.dest('.'));
}));
});
gulp.task('default', ['init']);

View File

@ -3,21 +3,37 @@
"version": "0.0.1",
"devDependencies": {
"bower": "^1.5.2",
"browser-sync": "^2.10.0",
"browser-sync-spa": "^1.0.3",
"event-stream": "^3.3.1",
"gulp": "^3.9.0",
"gulp-angular-filesort": "^1.1.1",
"gulp-angular-templatecache": "^1.7.0",
"gulp-autoprefixer": "^2.3.1",
"gulp-changed": "^1.3.0",
"gulp-concat": "^2.6.0",
"gulp-eslint": "^1.1.1",
"gulp-filter": "^3.0.1",
"gulp-flatten": "^0.2.0",
"gulp-imagemin": "^2.3.0",
"gulp-inject": "^3.0.0",
"gulp-load-plugins": "^1.1.0",
"gulp-minify-css": "^1.2.1",
"gulp-minify-html": "^1.0.4",
"gulp-prompt": "^0.1.2",
"gulp-rename": "^1.2.2",
"gulp-sass": "^2.0.4",
"gulp-size": "^2.0.0",
"gulp-sourcemaps": "^1.6.0",
"gulp-strip-debug": "^1.0.2",
"gulp-uglify": "^1.4.0",
"gulp-zip": "^3.0.2"
"gulp-useref": "^3.0.3",
"gulp-zip": "^3.0.2",
"http-proxy-middleware": "^0.9.0",
"lodash": "^3.10.1",
"main-bower-files": "^2.9.0",
"wiredep": "^2.2.2",
"wrench": "^1.5.8"
},
"scripts": {
"postinstall": "bower install"

View File

@ -12,7 +12,17 @@
<link rel="icon" type="image/png" sizes="96x96" href="img/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png">
<link rel="stylesheet" href="css/index.min.css">
<!-- build:css({.tmp/serve,src}) styles/vendor.css -->
<!-- bower:css -->
<!-- run `gulp inject` to automatically populate bower styles dependencies -->
<!-- endbower -->
<!-- endbuild -->
<!-- build:css({.tmp/serve,src}) styles/app.css -->
<!-- inject:css -->
<!-- css files will be automatically insert here -->
<!-- endinject -->
<!-- endbuild -->
</head>
<body ng-controller="mainCtrl">
@ -48,10 +58,22 @@
<div></div>
</div>
<script src="js/lib.min.js"></script>
<!-- build:js(src) scripts/vendor.js -->
<!-- bower:js -->
<!-- run `gulp inject` to automatically populate bower script dependencies -->
<!-- endbower -->
<!-- endbuild -->
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script src="js/bundle.min.js"></script>
<script src="js/templates.js"></script>
<!-- build:js({.tmp/serve,.tmp/partials,src}) scripts/app.js -->
<!-- inject:js -->
<!-- js files will be automatically insert here -->
<!-- endinject -->
<!-- inject:partials -->
<!-- angular templates will be automatically converted in js and inserted here -->
<!-- endinject -->
<!-- endbuild -->
</body>
</html>