'use strict'; // Directory name inside the patterns repo var site = 'codesignd'; //////////////////////////////////////////////////////////////////////////////// // Node dependencies var fs = require('fs'); var path = require('path'); // gulp and gulp plugins var gulp = require('gulp'); var autoprefixer = require('gulp-autoprefixer'); var cleanCSS = require('gulp-clean-css'); var concat = require('gulp-concat'); var header = require('gulp-header'); var include = require('gulp-include'); var preservetime = require('gulp-preservetime'); var refresh = require('gulp-refresh'); var rename = require('gulp-rename'); var gulpSass = require('gulp-sass'); var sass = gulpSass.compiler; var uglify = require('gulp-uglify'); // Other npm modules var del = require('del'); // Load package.json of the patterns repo var packageData = require('./site/patterns/package.json'); //////////////////////////////////////////////////////////////////////////////// var helpers = {}; /** * Returns a banner for asset files * * @param {string} type File type of the generated file * @return {object} */ helpers.banner = function(type) { var banner = [ '/*!', ' * <%= pkg.description %>', ' * @link <%= pkg.homepage %>', ' * @copyright <%= pkg.copyright %>', ' * @license <%= pkg.license' + type + ' || pkg.license %>', ' */', '' ].join('\n'); return header(banner, {pkg: packageData}); }; /** * Builds the CSS of the specified site * * @param {string} site Site name, defaults to "shared" if not given * @param {boolean} minify Whether to minify using clean-css * @return {stream} */ helpers.buildCSS = function(site, minify) { if(!site) site = 'shared'; if(!minify) minify = false; var sassOptions = { functions: { '-cdd-cachebuster($filepath)': function(filepath, done) { var pathString = filepath.getValue(); fs.stat(__dirname + pathString, function(err, stats) { if(err) throw err; var mtime = Math.round(Date.parse(stats.mtime) / 1000); var parsed = path.parse(pathString); var filepath = parsed.dir + '/' + parsed.name + '.' + mtime + parsed.ext; done(sass.types.String(filepath)); }); } }, outputStyle: 'expanded' }; // Compile the SCSS file var stream = gulp.src('site/patterns/' + site + '/' + site + '.scss') .pipe(gulpSass(sassOptions).on('error', gulpSass.logError)) .pipe(autoprefixer({browsers: ['> 1%']})) .pipe(rename('index.css')) .pipe(helpers.banner('CSS')) .pipe(gulp.dest('assets/css')); // Minify CSS if required if(minify) { stream = stream.pipe(rename('index.min.css')) .pipe(cleanCSS()) .pipe(gulp.dest('assets/css')); } // Trigger LiveReload return stream.pipe(refresh()); }; /** * Builds the JS of the specified site * * @param {string} site Site name, defaults to "shared" if not given * @param {boolean} minify Whether to minify using UglifyJS * @return {stream} */ helpers.buildJS = function(site, minify) { if(!site) site = 'shared'; if(!minify) minify = false; var src = ['site/patterns/shared/**/*.js', '!site/patterns/shared/polyfills.js']; if(site !== 'shared') { src.push('site/patterns/' + site + '/**/*.js'); src.push('!site/patterns/' + site + '/polyfills.js'); } // Concat the JS files var stream = gulp.src(src) .pipe(concat('index.js')) .pipe(include({includePaths: __dirname + '/node_modules'})) .pipe(helpers.banner('JS')) .pipe(gulp.dest('assets/js')); // Minify JS if required if(minify) { stream = stream.pipe(rename('index.min.js')) .pipe(uglify({output: {comments: 'some'}})) .pipe(gulp.dest('assets/js')); } // Trigger LiveReload return stream.pipe(refresh()); }; /** * Builds the polyfills JS of the specified site * * @param {string} site Site name, defaults to "shared" if not given * @param {boolean} minify Whether to minify using UglifyJS * @return {stream} */ helpers.buildPolyfillsJS = function(site, minify) { if(!site) site = 'shared'; if(!minify) minify = false; var src = ['site/patterns/shared/polyfills.js']; if(site !== 'shared') src.push('site/patterns/' + site + '/polyfills.js'); // Concat the JS files var stream = gulp.src(src, {allowEmpty: true}) .pipe(concat('polyfills.js')) .pipe(include({includePaths: __dirname + '/node_modules'})) .pipe(helpers.banner('JS')) .pipe(gulp.dest('assets/js')); // Minify JS if required if(minify) { stream = stream.pipe(rename('polyfills.min.js')) .pipe(uglify({output: {comments: 'some'}})) .pipe(gulp.dest('assets/js')); } // Trigger LiveReload return stream.pipe(refresh()); }; /** * Copies all files matching a specified pattern to the assets dir * Removes folder hierarchies so make sure that each file has a unique name! * * @param {string} site Site name, defaults to "shared" if not given * @param {string} pattern Something like "*.{jpg,svg}" * @param {string} dest Either "fonts" or "img" * @return {stream} */ helpers.copyFiles = function(site, pattern, dest) { if(!site) site = 'shared'; var src = ['site/patterns/shared/**/' + pattern]; if(site !== 'shared') src.push('site/patterns/' + site + '/**/' + pattern); return gulp.src(src, {since: gulp.lastRun(dest)}) .pipe(rename({dirname: ''})) // Flat hierarchy .pipe(gulp.dest('assets/' + dest)) .pipe(preservetime()) .pipe(refresh()); }; //////////////////////////////////////////////////////////////////////////////// /** * Compiles the CSS file of the current site */ gulp.task('css', function() { return helpers.buildCSS(site); }); /** * Compiles and minifies the CSS file of the current site */ gulp.task('css.min', function() { return helpers.buildCSS(site, true); }); /** * Combines the JS files of the current site */ gulp.task('js', function() { return helpers.buildJS(site); }); /** * Combines and minifies the JS files of the current site */ gulp.task('js.min', function() { return helpers.buildJS(site, true); }); /** * Combines the polyfills JS files of the current site */ gulp.task('polyfills', function() { return helpers.buildPolyfillsJS(site); }); /** * Combines and minifies the polyfills JS files of the current site */ gulp.task('polyfills.min', function() { return helpers.buildPolyfillsJS(site, true); }); /** * Copies all webfonts to assets/fonts */ gulp.task('fonts', function() { return helpers.copyFiles(site, '*.{woff,woff2,eot}', 'fonts'); }); /** * Copies all images to assets/img */ gulp.task('img', function() { return helpers.copyFiles(site, '*.{jpg,png,svg,ico}', 'img'); }); /** * Copies prism.js components to assets/js/prism */ gulp.task('prismjs', function() { return gulp.src('node_modules/prismjs/components/*') .pipe(gulp.dest('assets/js/prism')); }); /** * Builds everything except the minified files for local development */ gulp.task('default', gulp.series(gulp.parallel('fonts', 'img'), gulp.parallel('css', 'js', 'polyfills', 'prismjs'))); /** * Watches for changes */ function watchwait() { refresh.listen(); gulp.watch('site/patterns/**/*.scss', gulp.series('css')); gulp.watch('site/patterns/**/*.js', gulp.series('js')); gulp.watch('site/patterns/*/polyfills.js', gulp.series('polyfills')); gulp.watch('site/patterns/**/*.{woff,woff2,eot}', gulp.series('fonts')); gulp.watch('site/patterns/**/*.{jpg,png,svg,ico}', gulp.series('img')); gulp.watch(['content/**/*.txt', 'site/**/*.{php,yml}']).on('change', refresh.changed); } gulp.task('watch', gulp.series('default', watchwait)); /** * Cleans built files */ gulp.task('clean', function() { return del('assets/*/*'); }); /** * Builds everything for production * WARNING: Deletes some source files, only run this after committing your files */ function prodclean() { return del(['node_modules', 'gulpfile.js', 'site/patterns/*/', '!site/patterns/{shared,' + site + '}']); } gulp.task('prod', gulp.series('clean', gulp.parallel('fonts', 'img'), gulp.parallel('css.min', 'js.min', 'polyfills.min', 'prismjs'), prodclean));