Skip to content

Instantly share code, notes, and snippets.

@pjsvis
Created November 20, 2016 15:11
Show Gist options
  • Save pjsvis/50814c48ae0c547e9ecd416b45cef523 to your computer and use it in GitHub Desktop.
Save pjsvis/50814c48ae0c547e9ecd416b45cef523 to your computer and use it in GitHub Desktop.
/*
Adapted from the utp gulp file
Currently using _LayoutEx.cshtml as master pages
Need to include bootstrap
*/
// Visual Studio has a binding of BeforeBuild: main
// This means that when you build the app the main task will run.
//
// References
// 1. [https://gist.github.com/spboyer/96339ce687b0c79b8258](https://gist.github.com/spboyer/96339ce687b0c79b8258)
// 1. [http://stackoverflow.com/questions/32824381/parse-main-bower-files-js-css-scss-images-to-distribution-via-gulp](http://stackoverflow.com/questions/32824381/parse-main-bower-files-js-css-scss-images-to-distribution-via-gulp)
'use strict';
// The following dependencies are installed by
// ```
// npm install gulp --save-dev
// ```
var gulp = require('gulp');
var bower = require('gulp-bower');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var cssnano = require('gulp-cssnano');
var sourcemaps = require('gulp-sourcemaps');
var mainBowerFiles = require('main-bower-files');
var del = require('del');
var ts = require('gulp-typescript');
var runSequence = require('run-sequence');
var htmlhint = require('gulp-htmlhint');
var eslint = require('gulp-eslint');
var less = require('gulp-less');
var typedoc = require("gulp-typedoc");
var docco = require("gulp-docco");
var clean = require('gulp-clean');
var shell = require('gulp-shell');
var npmRun = require('gulp-npm-run')(require('gulp'), {
exclude: 'test',
include: 'tsc-watch',
requireStrict: true,
npmRun: true
});
var rename = require('gulp-rename');
// Deprecated. Use explicit requires for clarity.
var $ = require('gulp-load-plugins')({
lazy: true
});
gulp.task('fis', function () {
return gulp.src('custom/fis-bootstrap.less')
.pipe(sourcemaps.init())
.pipe(less())
.pipe(rename('custom-bootstrap.css'))
.pipe(sourcemaps.write('/'))
.pipe(gulp.dest('./css'));
});
// Clean out the app-docs folder
gulp.task('clean-docs', function () {
return gulp
.src(['app-docs'], {
read: false
})
.pipe(clean());
});
// Typedoc creates documentation for our Typescript files in ```app-docs/typedoc```
// We use [Typewriter](https://github.com/frhagn/Typewriter) to generate
// Typescript interfaces for our WebAPI endpoints and our database models.
// We don't need to document angular controllers or componentsas they don't have any interfaces
gulp.task("typedoc", function () {
return gulp
.src(["app/**/*.ts", "!app/**/*.controller.ts", "!app/**/*.component.ts", "!app/globals.ts"])
.pipe(typedoc({
module: "system",
target: "es5",
out: "app-docs/typedoc",
name: "Certification Management Portal",
includeDeclarations: true
}))
;
});
// Used to document gulpfile.js
//
// We document our ```scripts/app/**/*.js``` files using docco-toc which is run from a shell
// ```
// docco-toc -o app-docs/docco-toc *.js
// ```
gulp.task('docco', function () {
var options = {
layout: 'parallel',
output: 'app-docs/docco',
template: null,
css: null,
extension: null,
languages: {},
marked: null
};
return gulp.src("gulpfile.js")
.pipe(docco(options))
.pipe(gulp.dest('./app-docs/docco'));
});
// Some variables used in the config object.
// Only used by the templatecache and inject-app tasks
// Could be trimmed down
// TODO: Try and exclude scratch.tpl.html
var client = '';
var clientApp = 'app/';
var layoutSource = 'Views/Shared/';
// bower main files will be stored here
var targetDir = 'build/lib';
var config = {
client: client,
layoutSource: layoutSource,
// script/style tags will be injected here
index: layoutSource + '_LayoutEx.cshtml',
css: [
// Get all css files in all folders
targetDir + '/**/*.css'
],
js: [
// Get all js files in all folders
targetDir + '/**/*.js'
],
htmltemplates: [clientApp + '**/*.html'],
templateCache: {
file: 'templates.js',
options: {
module: 'templates',
root: 'app/',
standAlone: true
}
},
temp: './.tmp/'
};
// Clean the ```build/lib``` folder.
// Required to get rid of any deprecated files
gulp.task('clean-build-lib', function () {
log('Cleaning ./build/lib');
log('NOTE: This is the bower-preinstall task');
return del('./build/lib/');
});
gulp.task('clean-lib', function () {
log('Cleaning ./lib');
return del('./lib/');
});
// Copy the main bower files to the ```build/lib``` folder
gulp.task('main-bower-files', ['clean-build-lib'], function () {
log('Copying main bower files to ./lib/');
return gulp.src(mainBowerFiles({ debugging: true }), { base: 'lib' })
.pipe(gulp.dest('./build/lib'));
});
// Lint the app html
gulp.task('htmlhint', function () {
return gulp.src("./app/**/*.html")
.pipe(htmlhint("htmlhintrc.json"))
//.pipe(htmlhint())
.pipe(htmlhint.reporter("htmlhint-stylish"))
.pipe(htmlhint.failReporter({ suppress: true }));
});
// Compile font awesome from the Less sources
gulp.task('less-fa', function () {
return gulp.src('lib/font-awesome/less/font-awesome.less')
.pipe(sourcemaps.init())
.pipe(less())
.pipe(sourcemaps.write('/'))
.pipe(gulp.dest('css'));
});
// Copy the bootstrap and font-awesome fonts to the ```fonts``` folder
gulp.task('copyfonts', function () {
gulp.src('./lib/font-awesome/fonts/**/*.{ttf,woff,eof,svg,woff2}')
.pipe(gulp.dest('./fonts'));
});
// Copy the tree-control images to images folder.
// This is required for the release build.
// <br>TODO: See if any other components need assets relocated for release
gulp.task('copy-tree-images', function () {
gulp.src('build/lib/angular-tree-control/images/*.png')
.pipe(gulp.dest('images'));
});
// Ensure that the vendor script refs are in the correct order in ```_Layout.cshtml```
var vendorSrc = [
'build/lib/console-shim/**/*.js',
'build/lib/jquery/**/*.js',
'build/lib/signalr/**/*.js',
'build/lib/moment/**/*.js',
'build/lib/lodash/**/*.js',
'build/lib/api-check/dist/api-check.js',
'build/lib/codemirror/lib/**/*.js',
'build/lib/codemirror/mode/**/*.js',
'build/lib/ag-grid/dist/ag-grid.js',
'build/lib/angular/**/*.js',
'build/lib/angular-formly/dist/*.js',
'build/lib/angular-formly-templates-bootstrap/dist/*.js',
'build/lib/angular-gantt/assets/angular-gantt.js',
'build/lib/angular-gantt/assets/angular-gantt-plugins.js',
'build/lib/angular*/**/*.js',
'build/lib/**/*.js'
];
var vendorCss = 'build/lib/**/*.css';
// Inject our vendor ```*.js``` and ```*.css``` files into ```_Layout.cshtml```
gulp.task('inject-bower', [], function () {
log('Injecting bower *.css and *.js files into _layout.cshtml');
var timestamp = getTimestamp();
var params = ['?v=', timestamp].join('');
return gulp
.src(config.index)
.pipe($.inject(gulp.src(vendorCss), {
starttag: '<!-- inject:bower:css -->',
transform: function (filepath) {
return ['<link href="~', filepath, params, '" rel="stylesheet" />'].join('');
}
}))
.pipe($.inject(gulp.src(vendorSrc, { read: false }), {
starttag: '<!-- inject:bower:js -->',
transform: function (filepath) {
return ['<script src="~', filepath, params, '"></script>'].join('');
}
}))
.pipe(gulp.dest(config.layoutSource));
});
// Update our bower files
gulp.task('bower-update', function () {
log('Updating bower files');
return bower({ cmd: 'update' }); // Run gulp update
});
// Do not use these hooks as Visual Studio forces an update on project open
//
// Before we do a bower install we clean ```build/lib```
gulp.task('bower-preinstall', ['clean-build-lib']);
// After we do a bower install we wire up the dependencies
gulp.task('bower-postinstall', ['inject-bower', 'copy-tree-images']);
// Create an angular module called templates to hold the minified app html.
// The templates module gets injected in to the app module
// TODO: Have a look at just https://github.com/laxa1986/gulp-angular-embed-templates
// This will include the templates inline
// Ref: https://www.npmjs.com/package/gulp-angular-templatecache
gulp.task('templatecache', function () {
log('Creating an AngularJS $templateCache');
return gulp
.src(['app/**/*.html'])
.pipe($.minifyHtml({ empty: true }))
.pipe($.angularTemplatecache(
config.templateCache.file,
config.templateCache.options
))
.pipe(gulp.dest('./app/'));
});
// Define excludes and loading order for the app scripts.
// The models/*.ts files are interrfaces that compile down to empty *.js files
var appSrc = [
'!app/ts-gen/models/*.js',
'app/app.js',
'app/app.routes.js',
'app/templates.js',
'app/*module*.js',
'app/directives/angular-affix/**/*.js',
'app/**/*.js'
];
// Define the loading order for the app style sheets.
// Exclude ```brand.css``` as it is injected after the other app styles so that it always overrides them
var appCss = [
'!css/brand.css',
'css/custom-bootstrap.css',
'css/custom-bootstrap-overrides.css',
'css/Site.css',
'css/app-modals.css',
'css/**/*.css'];
// Inject our app and brand css files and then our app js files
gulp.task('inject-app', function () {
log('Injecting app *.css and *.js files into _layoutEx.cshtml');
log('NOTE: All html files will be minified and injected into the cache via ./scripts/app/templates.js');
log('DEPRECATE: *.route.js files should be referenced in their parent MVC views');
log(appCss);
var timestamp = getTimestamp();
var params = ['?v=', timestamp].join('');
return gulp
.src('Views/Shared/_LayoutEx.cshtml')
.pipe($.inject(gulp.src(appCss, { read: false }), {
starttag: '<!-- inject:app:css -->',
transform: function (filepath) {
return ['<link href="~', filepath, params, '" rel="stylesheet" />'].join('');
}
}))
.pipe($.inject(gulp.src('css/brand.css', { read: false }), {
starttag: '<!-- inject:brand:css -->',
transform: function (filepath) {
return ['<link href="~', filepath, params, '" rel="stylesheet" />'].join('');
}
}))
.pipe($.inject(gulp.src(appSrc, { read: false }), {
starttag: '<!-- inject:app:js -->',
transform: function (filepath) {
return ['<script src="~', filepath, params, '"></script>'].join('');
}
}))
.pipe(gulp.dest(config.layoutSource));
});
gulp.task('inject-release', function () {
log('Injecting dist/[app.min, app.css, vendor.min.js, vendor.min.css] into _layoutEx.cshtml');
log(appCss);
var timestamp = getTimestamp();
var params = ['?v=', timestamp].join('');
return gulp
.src('Views/Shared/_LayoutEx.cshtml')
.pipe($.inject(gulp.src('dist/vendor.min.css', { read: false }), {
starttag: '<!-- inject:vendor-dist:css -->',
transform: function (filepath) {
return ['<link href="~', filepath, params, '" rel="stylesheet" />'].join('');
}
}))
.pipe($.inject(gulp.src('dist/app.min.css', { read: false }), {
starttag: '<!-- inject:app-dist:css -->',
transform: function (filepath) {
return ['<link href="~', filepath, params, '" rel="stylesheet" />'].join('');
}
}))
.pipe($.inject(gulp.src('css/brand.css', { read: false }), {
starttag: '<!-- inject:brand-dist:css -->',
transform: function (filepath) {
return ['<link href="~', filepath, params, '" rel="stylesheet" />'].join('');
}
}))
.pipe($.inject(gulp.src('dist/vendor.min.js', { read: false }), {
starttag: '<!-- inject:vendor-dist:js -->',
transform: function (filepath) {
return ['<script src="~', filepath, params, '"></script>'].join('');
}
}))
.pipe($.inject(gulp.src('dist/app.min.js', { read: false }), {
starttag: '<!-- inject:app-dist:js -->',
transform: function (filepath) {
return ['<script src="~', filepath, params, '"></script>'].join('');
}
}))
.pipe(gulp.dest(config.layoutSource));
});
// Declare placeholder for brandName and default it to fis
var brandName = 'fis';
// Brand the app for a specific brand name
gulp.task('brandCss', function () {
var glob = ['branding/', brandName, '/**/*.{css,map}'].join('');
return gulp.src(glob).pipe(gulp.dest('./css'));
});
// Brand the app images for a specific brand name
gulp.task('brandImages', function () {
var glob = ['branding/', brandName, '/**/*.{png,ico}'].join('');
return gulp.src(glob).pipe(gulp.dest('./images'));
});
// FIS branding
gulp.task('brand-fis', function () {
brandName = 'fis';
log(brandName);
runSequence('brandImages', 'brandCss');
});
// Concatenate and minify vendor scripts with mangle=false, preserve comments and licenses.
// Then copy the output to the ```./dist``` folder
// ```_Layout.cshtml``` has a debug flag. When set to false the minified sources will be used.
gulp.task('uglify-vendor', function () {
log('Concat and minify vendor files to ./dist/vendor.min.js with mangle=false and license=true');
return gulp.src(vendorSrc)
.pipe(sourcemaps.init())
.pipe(concat('vendor.min.js'))
.pipe(uglify({ mangle: false, preserveComments: true, license: true }))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('./dist'));
});
// Minify the vendor css
gulp.task('cssnano-vendor', function () {
return gulp.src(vendorCss)
.pipe(sourcemaps.init())
.pipe(concat('vendor.min.css'))
.pipe(cssnano())
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('./dist'));
});
// Minify the app scripts
gulp.task('uglify-app', function () {
return gulp.src(appSrc)
.pipe(sourcemaps.init())
.pipe(concat('app.min.js'))
.pipe(uglify({ mangle: false, preserveComments: true, license: true }))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('./dist'));
});
// Minify the app css
gulp.task('cssnano-app', function () {
return gulp.src(appCss)
.pipe(sourcemaps.init())
.pipe(concat('app.min.css'))
.pipe(cssnano())
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('./dist'));
});
// Lint the javascript files
gulp.task('eslint', function () {
return gulp.src([
'scripts/app/**/*.js',
'!node_modules/**',
'!lib/**',
'!build/**',
'!scripts/app/templates.js'
])
.pipe(eslint())
.pipe(eslint.format());
});
// Compile font-awesome
gulp.task('less-fa', function () {
return gulp.src('lib/font-awesome/less/font-awesome.less')
.pipe(sourcemaps.init())
.pipe(less())
.pipe(sourcemaps.write('/'))
.pipe(gulp.dest('css'));
});
// Copy font awesome fonts to the fonts folder
gulp.task('copyfonts', function () {
gulp.src('./lib/font-awesome/fonts/**/*.{ttf,woff,eof,svg,woff2}')
.pipe(gulp.dest('./fonts'));
});
gulp.task('copy-bootstrap-fonts', function () {
gulp.src('./lib/bootstrap/fonts/**/*.{eot,svg,ttf,woff,woff2}')
.pipe(gulp.dest('./fonts'));
});
// Create a timestamp for cache busting purposes
function getTimestamp() {
var dt = new Date();
var yy = dt.getFullYear();
var mo = dt.getMonth();
var dd = dt.getDate();
var hh = dt.getHours();
var mm = dt.getMinutes();
var ss = dt.getSeconds();
var ms = dt.getMilliseconds();
return [yy, mo, dd, hh, mm, ss, ms].join('');
}
// Log a message or series of messages using chalk's blue color.
// Can pass in a string, object or array.
function log(msg) {
if (typeof (msg) === 'object') {
for (var item in msg) {
if (msg.hasOwnProperty(item)) {
$.util.log($.util.colors.blue(msg[item]));
}
}
} else {
$.util.log($.util.colors.blue(msg));
}
}
// Compile app typescript files. Not currently used.
// TODO: Figure out why it does not compile the ts files
// Currently we use a command line ```tsc --watch```
gulp.task('tsc', function () {
var tsProject = ts.createProject('tsconfig.json', { sortOutput: true });
tsProject.src() // instead of gulp.src(...)
.pipe(ts(tsProject));
//var tsResult = tsProject.src() // instead of gulp.src(...)
// .pipe(ts(tsProject));
//return tsResult.js.pipe(gulp.dest('release'));
});
gulp.task('tsc-watch', function () {
return gulp.src('./app/**/*.ts')
.pipe(shell(['npm run tsc-watch']));
});
// The watch task is launched from Visual Studio Task Explorer.
// This will watch for changes in the app files and run the templatecache and inject-app tasks
gulp.task('app-watch', function () {
gulp.watch([
//'app/**/*.ts',
'app/**/*.js',
'config/*.json',
'app/**/*.html',
'css/*.css'
], function () {
runSequence('templatecache', 'inject-app');
});
});
// The main task is bound to the beforeBuild event is Visual Studio task explorer.
gulp.task('main', function () {
runSequence('templatecache', 'inject-app');
});
// Complete font awesome workflow
gulp.task('font-awesome', ['less-fa', 'copyfonts']);
// Build the app (duplicate of main)
// TODO: Add a tsc task
gulp.task('build-app', function () {
runSequence('templatecache', 'inject-app');
});
// Create the release files. (Not currently used.)
gulp.task('release-app', ['uglify-vendor', 'cssnano-vendor', 'uglify-app', 'cssnano-app', 'inject-release']);
// Expermimental watch-all method to compile *.ts, templatecache, inject-app
gulp.task('watch', ['app-watch', 'tsc-watch']);
gulp.task('default', ['watch']);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment