Last active
July 17, 2018 07:59
-
-
Save vintharas/9999cf6098c66e81eb7736db7b779951 to your computer and use it in GitHub Desktop.
Sample gulpfile for a complete pipeline with ES6 and SASS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint strict: [2, "global"] */ | |
'use strict'; | |
/*** Main paths ***/ | |
var projectRoot = './', | |
root = './myProject.web/', // project root | |
index = root + 'Views/Shared/Layouts/', | |
src = root + 'Content/', // source code | |
temp = root + 'temp/', // temporary folder | |
dist = src + 'dist/', // generated code | |
templates = src + 'templates/', // html templates for angular | |
bower = { // third parties | |
directory: root + 'bower_components/', | |
json: './bower.json', | |
}, | |
packages = { | |
json: './package.json' | |
}; | |
/*** Subpaths for reuse ***/ | |
var bowerFontsSrc = [bower.directory + 'bootstrap-sass/assets/fonts/**/*.*', bower.directory + 'font-awesome/fonts/*.*']; | |
/* API */ | |
exports.config = getConfig(); | |
function getConfig() { | |
var config = { | |
projectRoot: projectRoot, | |
root: root, | |
src: src, | |
dist: dist, | |
temp: temp, | |
packages: [bower.json, packages.json], | |
/*** CSS ***/ | |
sass: root + 'Styles/styles.scss', | |
allSass: [root + 'Styles/**/*.scss'], | |
distCss: dist + 'css/', | |
distCssFiles: dist + 'css/**/*.css', | |
/*** JS ***/ | |
js: src + 'js/**/*.js', | |
tempJs: temp + '**/*.js', | |
jsConfigs: root + '../*.js', | |
specs: src + 'specs/**/*.spec.js', | |
distJs: dist + 'js/', | |
distJsFiles: dist + 'js/**/*.js', | |
/*** HTML ***/ | |
index: index, | |
indexOriginFile: index + '_RootChrome.orig.cshtml', | |
indexGeneratedFileRename: './Views/Shared/Layouts/_RootChrome.cshtml', | |
indexGeneratedFile: index + '_RootChrome.cshtml', | |
indexGeneratedFileName: './_RootChrome.cshtml', | |
htmlTemplates: templates + '**/*.html', | |
/*** Fonts ***/ | |
bowerFontsSrc: bowerFontsSrc, | |
allFontsSrc: bowerFontsSrc.concat([root + 'Content/fonts/*.*']), | |
fonts: root + 'Content/fonts/', | |
fontsDist: dist + 'fonts/', | |
/*** Resources ***/ | |
resources: root + 'Content/resources/locale-*.json', | |
resourcesDist: dist + 'resources/', | |
get allJs() { | |
return [this.js, this.jsConfigs, this.specs]; | |
}, | |
/*** wiredep ***/ | |
// wire dep needs to know about bower directories so that | |
// it can find the dependencies and inject them in our index.html file | |
getWiredepOptions: function (logger) { | |
return { | |
exclude: ['bower_components/jquery'], | |
bowerJson: require(bower.json), | |
directory: bower.directory, | |
ignorePath: '../../..', | |
onError: function (err) { | |
logger.log('error when running wiredep: ' + err + ' with code ' + err.code); | |
// If not overridden, an error will throw. | |
// err = Error object. | |
// err.code can be: | |
// - "PKG_NOT_INSTALLED" (a Bower package was not found) | |
// - "BOWER_COMPONENTS_MISSING" (cannot find the `bower_components` directory) | |
}, | |
onFileUpdated: function (filePath) { | |
// filePath = 'name-of-file-that-was-updated' | |
logger.log('file updated: ' + filePath); | |
}, | |
onPathInjected: function (fileObject) { | |
// fileObject.block = 'type-of-wiredep-block' ('js', 'css', etc) | |
// fileObject.file = 'name-of-file-that-was-updated' | |
// fileObject.path = 'path-to-file-that-was-injected' | |
logger.log('file injected: ' + fileObject.path); | |
}, | |
onMainNotFound: function (pkg) { | |
// pkg = 'name-of-bower-package-without-main' | |
logger.error('main not found for package: ' + pkg); | |
} | |
}; | |
}, | |
/*** inject ***/ | |
injectOptions: { | |
ignorePath: '/myProject.se.web' | |
}, | |
/*** rev ***/ | |
manifest: temp, | |
manifestFile: './rev-manifest.json', | |
manifestFileFullPath: temp + './rev-manifest.json' | |
}; | |
return config; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint strict: 0 */ | |
'use strict'; | |
var gulp = require('gulp'), | |
config = require('./gulp.config.js').config, | |
del = require('del'), | |
$ = require('gulp-load-plugins')({ lazy: true }), | |
path = require('path'), | |
exec = require('child_process').exec, | |
args = require('yargs').argv, | |
ngAnnotate = require('gulp-ng-annotate'); | |
/* Gulp tasks */ | |
gulp.task('help', $.taskListing); | |
gulp.task('js:clean', function(){ | |
log('Cleaning generated javascript files'); | |
var jsFilesInDist = path.join(config.distJs, '**/*.*'), | |
tempFiles = path.join(config.temp, '**/*.*'), | |
files = [jsFilesInDist, tempFiles]; | |
return cleanFiles(files); | |
}); | |
gulp.task('clean', function(){ | |
var filesInDist = path.join(config.dist, '**/*.*'), | |
tempFiles = path.join(config.temp, '**/*.*'), | |
files = [filesInDist, tempFiles]; | |
return cleanFiles(files); | |
}); | |
gulp.task('clean:temp', function(){ | |
return cleanFiles(path.join(config.temp, '**/*.*')); | |
}); | |
//gulp.task('default', function () { | |
// return gulp.src('Content/js') | |
// .pipe(ngAnnotate()) | |
// .pipe(gulp.dest('dist')); | |
//}); | |
gulp.task('fonts', function(){ | |
return copyFiles(config.bowerFontsSrc, config.fonts); | |
}); | |
gulp.task('fonts:dist', function(){ | |
return copyFiles(config.allFontsSrc, config.fontsDist); | |
}); | |
gulp.task('resources', function () { | |
return copyFiles(config.resources, config.resourcesDist); | |
}); | |
gulp.task('resources:watch', ['resources'], function (done) { | |
// use of gulp-watch plugin instead of gulp.watch | |
// because it supports watching new or deleted files | |
log('Watching on resources changes'); | |
$.watch(config.resources, function () { | |
gulp | |
.start('resources') | |
.on('end', done); | |
}); | |
}); | |
gulp.task('lint', function(){ | |
log('Linting all javascript files'); | |
return gulp.src(config.allJs) | |
.pipe($.print()) | |
.pipe($.eslint()) | |
.pipe($.eslint.format()); | |
}); | |
gulp.task('lint:watch', ['lint'], function(done){ | |
log('Watching changes on all javascript files and linting'); | |
// use of gulp-watch plugin instead of gulp.watch | |
// because it supports watching new or deleted files | |
$.watch(config.allJs, function () { | |
gulp | |
.start('lint') | |
.on('end', done); | |
}); | |
}); | |
gulp.task('test', function(done){ | |
log('Running JavaScript unit tests with Karma'); | |
startTests({singleRun: true, done: done}); | |
}); | |
gulp.task('test:watch', function(done) { | |
log('Running JavaScript unit tests with Karma and watch for changes'); | |
startTests({singleRun: false, done: done}); | |
}); | |
gulp.task('testlint:watch', ['test:watch', 'lint:watch'], function() {}); | |
function templateCache() { | |
var templatesFile = 'templates.js', | |
options = { | |
module: 'myapp', | |
standAlone: false, // add them to the existing myapp module (don't create a new module) | |
root: '/Content/templates/' // prefix for template urls | |
}; | |
log('Starting bundling and minification of templates in: ' + config.htmlTemplates); | |
return gulp.src(config.htmlTemplates) // clientApp + '**/*.html' | |
.pipe($.minifyHtml({empty: true})) // include empty HTML tags | |
.pipe($.angularTemplatecache(templatesFile, options)) | |
.pipe(gulp.dest(config.temp)); | |
} | |
gulp.task('templates', ['clean'], templateCache); | |
gulp.task('templates:noclean', templateCache); | |
function js() { | |
log('Compiling ES6 to vanilla JavaScript'); | |
log('Copying generated files into: ' + config.distJs); | |
return gulp.src([config.js, config.tempJs]) | |
.pipe($.sourcemaps.init()) | |
.pipe($.babel()) | |
.pipe(ngAnnotate({ single_quotes: true })) | |
.pipe($.concat('my-app.js')) | |
.pipe($.sourcemaps.write('.')) | |
.pipe(gulp.dest(config.distJs)); | |
} | |
gulp.task('js', ['templates'], js); | |
gulp.task('js:noclean', js); | |
gulp.task('js:watch', ['js:noclean'], function(done){ | |
// use of gulp-watch plugin instead of gulp.watch | |
// because it supports watching new or deleted files | |
log('Watching on js changes'); | |
$.watch(config.js, function () { | |
gulp | |
.start('js:noclean') | |
.on('end', done); | |
}); | |
}); | |
function sass() { | |
log('Starting sass compilation of: ' + config.sass); | |
return gulp.src(config.sass) | |
.pipe($.plumber()) | |
.pipe($.print()) | |
.pipe($.sourcemaps.init()) | |
.pipe($.sass().on('error', $.sass.logError)) | |
.pipe($.autoprefixer({ browsers: ['last 2 version', '> 5%'] })) | |
.pipe($.sourcemaps.write('.')) | |
.pipe(gulp.dest(config.distCss)); | |
} | |
gulp.task('sass', ['clean'], sass); | |
gulp.task('sass:noclean', sass); | |
gulp.task('sass:watch', ['sass:noclean'], function(done){ | |
// use of gulp-watch plugin instead of gulp.watch | |
// because it supports watching new or deleted files | |
log('Watching on sass styles changes'); | |
return $.watch(config.allSass, function(){ | |
gulp | |
.start('sass:noclean') | |
.on('end', done); | |
}); | |
}); | |
gulp.task('wiredep', ['js', 'sass', 'fonts:dist', 'resources'], function(){ | |
/* wire bower css/js dependencies in our app js */ | |
var wiredep = require('wiredep').stream, | |
wiredepOptions = config.getWiredepOptions(logger()); | |
log('Starting wiring of dependencies into root cshtml file: ' + config.index); | |
// log('Reading: ' + JSON.stringify(wiredepOptions.bowerJson)); // debug | |
log('Bower components in folder: ' + wiredepOptions.directory); | |
return gulp | |
.src(config.indexOriginFile) | |
.pipe($.plumber()) | |
.pipe($.rename(config.indexGeneratedFileName)) | |
.pipe(wiredep(wiredepOptions)) | |
.pipe($.inject(gulp.src(config.distJsFiles), config.injectOptions)) | |
.pipe($.inject(gulp.src(config.distCssFiles), config.injectOptions)) | |
.pipe(gulp.dest(config.index)); | |
}); | |
gulp.task('bundle', ['js', 'sass', 'fonts:dist', 'resources'], function () { | |
/* wire bower css/js dependencies in our app js */ | |
var wiredep = require('wiredep').stream, | |
wiredepOptions = config.getWiredepOptions(logger()); | |
log('Starting wiring of dependencies into root cshtml file: ' + config.indexOriginFile); | |
log('The generated file will be placed in: ' + config.indexGeneratedFileName); | |
//log('Reading: ' + JSON.stringify(wiredepOptions.bowerJson)); | |
log('Bower components in folder: ' + wiredepOptions.directory); | |
return gulp | |
.src(config.indexOriginFile) | |
.pipe($.plumber()) | |
.pipe($.rename(config.indexGeneratedFileName)) | |
.pipe(wiredep(wiredepOptions)) | |
.pipe($.inject(gulp.src(config.distJsFiles), config.injectOptions)) | |
.pipe($.inject(gulp.src(config.distCssFiles), config.injectOptions)) | |
.pipe($.useref({searchPath: config.root, base: config.root})) | |
.pipe(gulp.dest(config.index)); | |
}); | |
// This task must be run together with cache busting | |
// TODO: improve! | |
gulp.task('optimize', ['js', 'sass', 'fonts:dist', 'resources'], function () { | |
/* wire bower css/js dependencies in our app js */ | |
var wiredep = require('wiredep').stream, | |
wiredepOptions = config.getWiredepOptions(logger()); | |
log('Starting bundling and optimizing dependencies and bundling them into root cshtml file: ' + config.indexOriginFile); | |
log('The generated file will be placed in: ' + config.indexGeneratedFileName); | |
log('Bower components in folder: ' + wiredepOptions.directory); | |
return gulp | |
.src(config.indexOriginFile, {base: config.root}) | |
.pipe($.print()) | |
.pipe($.plumber()) | |
.pipe($.rename(config.indexGeneratedFileName)) | |
.pipe($.print()) | |
.pipe(wiredep(wiredepOptions)) | |
.pipe($.inject(gulp.src(config.distJsFiles), config.injectOptions)) | |
.pipe($.inject(gulp.src(config.distCssFiles), config.injectOptions)) | |
.pipe($.useref({searchPath: config.root, base: config.root})) | |
.pipe($.if('*.css', $.csso())) | |
.pipe($.if('*.js', $.uglify())) // TODO: Optimize this to grab the already minified versions of vendor libraries | |
.pipe($.if('*.css', $.rev())) | |
.pipe($.if('*.js', $.rev())) | |
.pipe($.if('*.css', gulp.dest(config.root))) | |
.pipe($.if('*.js', gulp.dest(config.root))) | |
.pipe($.print()) | |
.pipe($.if('*.cshtml', gulp.dest(config.index))) | |
.pipe($.rev.manifest(config.manifestFile)) | |
.pipe(gulp.dest(config.manifest)); | |
}); | |
gulp.task('cachebusting', ['optimize'], function(){ | |
log('Injected cache busting dependencies in: ' + config.indexGeneratedFile); | |
return gulp | |
.src(config.indexGeneratedFile) | |
.pipe($.print()) | |
.pipe($.revReplace({replaceInExtensions: ['.cshtml', '.js', '.css'], manifest: gulp.src(config.manifestFileFullPath)})) | |
.pipe($.print()) | |
.pipe(gulp.dest(config.index)); | |
}); | |
gulp.task('bump', function(){ | |
var options = { | |
type: args.type, | |
version: args.version | |
}; | |
return gulp | |
.src(config.packages) | |
.pipe($.bump(options)) | |
.pipe($.print()) | |
.pipe(gulp.dest(config.projectRoot)); | |
}); | |
/*** CI only tasks ***/ | |
gulp.task('bower', function (cb) { | |
exec('.\\tools\\CI\\bower.cmd install -f', function (err, stdout, stderr) { | |
console.log(stdout); | |
console.log(stderr); | |
cb(err); | |
}); | |
}); | |
// TODO: build more granular tasks for js and sass | |
// because the ones we have now are not wired | |
gulp.task('build', ['wiredep']); // => all separate dependencies | |
gulp.task('build:dev', ['wiredep']); | |
gulp.task('build:bundle', ['bundle']); // => all dependencies bundled | |
gulp.task('build:prod', ['cachebusting']); // => all dependencies optimized and with hash | |
gulp.task('watch', ['clean'], function() { | |
gulp.start(['lint:watch', 'js:watch', 'sass:watch', 'fonts:dist', 'resources:watch']); | |
}); | |
gulp.task('default', ['help']); | |
/* Gulpfile helpers */ | |
function log(message){ | |
$.util.log($.util.colors.blue(message)); | |
} | |
function error(message){ | |
$.util.log($.util.colors.red(message)); | |
} | |
function logger(){ | |
return { | |
log: log, | |
error: error | |
}; | |
} | |
function cleanFiles(files){ | |
log('Cleaning files: ' + files); | |
return del(files); | |
} | |
function startTests(options){ | |
var singleRun = options.singleRun, | |
done = options.done, | |
Server = require('karma').Server, | |
karmaOptions = { | |
configFile: path.join(__dirname, '/karma.conf.js'), | |
singleRun: singleRun | |
}, | |
server = new Server(karmaOptions, karmaCompleted); | |
server.start(); | |
function karmaCompleted(exitCode){ | |
if (exitCode !== 0) { | |
var errorMessage = 'Karma exited with error code: ' + exitCode; | |
error(errorMessage); | |
return process.exit(exitCode); | |
} | |
done(); | |
} | |
if (options.singleRun) { | |
gulp.src('karma_html/coverage-report/index.html') | |
.pipe($.open({ app: 'chrome' })); | |
gulp.src('karma_html/test-report/index.html') | |
.pipe($.open({ app: 'chrome' })); | |
} | |
} | |
function copyFiles(from, to) { | |
log('Copying files from ' + from + ' to folder: ' + to); | |
return gulp.src(from) | |
.pipe($.print()) | |
.pipe(gulp.dest(to)); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "myapp", | |
"version": "1.0.1", | |
"description": "my app", | |
"main": "index.js", | |
"scripts": { | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"repository": { | |
"type": "git", | |
"url": "https://myrepo.com" | |
}, | |
"engine": { | |
"node": "0.12.x", | |
"npm": "2.13.x" | |
}, | |
"author": "", | |
"license": "ISC", | |
"devDependencies": { | |
"babel-preset-es2015": "^6.1.18", | |
"bower": "^1.7.2", | |
"del": "^2.0.2", | |
"eslint-config-eslint": "^1.0.1", | |
"gulp": "^3.9.0", | |
"gulp-angular-templatecache": "^1.8.0", | |
"gulp-autoprefixer": "^2.3.1", | |
"gulp-babel": "^5.2.1", | |
"gulp-bump": "^1.0.0", | |
"gulp-concat": "^2.6.0", | |
"gulp-csso": "^1.0.1", | |
"gulp-eslint": "^1.1.1", | |
"gulp-if": "^2.0.0", | |
"gulp-inject": "^3.0.0", | |
"gulp-load-plugins": "^0.10.0", | |
"gulp-minify-html": "^1.0.5", | |
"gulp-plumber": "^1.0.1", | |
"gulp-print": "^1.1.0", | |
"gulp-rename": "^1.2.2", | |
"gulp-rev": "^6.0.1", | |
"gulp-rev-replace": "^0.4.3", | |
"gulp-sass": "^2.0.4", | |
"gulp-sourcemaps": "^1.5.2", | |
"gulp-task-listing": "^1.0.1", | |
"gulp-uglify": "^1.5.1", | |
"gulp-useref": "^3.0.5", | |
"gulp-util": "^3.0.6", | |
"gulp-watch": "^4.3.5", | |
"jasmine-core": "^2.3.4", | |
"karma": "^0.13.22", | |
"karma-babel-preprocessor": "^6.0.1", | |
"karma-chrome-launcher": "^0.2.0", | |
"karma-jasmine": "^0.3.6", | |
"karma-phantomjs-launcher": "^1.0.0", | |
"karma-sinon": "^1.0.4", | |
"sinon": "^1.17.1", | |
"wiredep": "^3.0.0", | |
"yargs": "^3.19.0", | |
"karma-html-reporter": "^0.2.7", | |
"karma-coverage": "^0.5.5", | |
"gulp-open": "^1.0.0", | |
"gulp-ng-annotate": "^2.0.0", | |
"phantomjs-prebuilt": "^2.1.7", | |
"karma-phantomjs2-launcher": "^0.5.0" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment