diff --git a/gulpfile.babel.js b/gulpfile.babel.js index 9bf571e4..040b42ff 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -4,7 +4,7 @@ const $ = require('gulp-load-plugins')() // manually import modules that won't get picked up by gulp-load-plugins -import gulp from 'gulp' +import { src, dest, watch, parallel, series } from 'gulp' import del from 'del' import pkg from './package.json' import parallelize from 'concurrent-transform' @@ -106,59 +106,24 @@ const BANNER = [ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// gulp tasks -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -// -// Full build -// -// `gulp build` is the development build -// `gulp build --production` is the production build -// -gulp.task('build', gulp.series( - buildBanner, clean, jekyll, - gulp.parallel(html, css, js, images, icons, fonts, media), - rev, revReplace -)) - -function buildBanner(done) { - console.log($.util.colors.gray(" ------------------------------------------")) - console.log($.util.colors.green(' Building ' + ($.util.env.production ? 'production' : 'dev') + ' version...')) - console.log($.util.colors.gray(" ------------------------------------------")) - - done() -} - - -// -// Build site, run server, and watch for file changes -// -gulp.task('default', gulp.series('build', server, watch)) - - - -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// Functions +// Tasks // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // // Delete build artifacts // -function clean(done) { - return del([ +export const clean = () => + del([ DIST + '**/*', DIST + '.*', // delete all hidden files '!' + DIST + '/media/**' ]) - done() -} - // // Jekyll // -function jekyll(done) { +export const jekyll = (done) => { browser.notify('Compiling Jekyll') @@ -169,58 +134,53 @@ function jekyll(done) { var jekyll_options = 'jekyll build --config _config.yml,_config.dev.yml --incremental --drafts --future' } - var spawn = require('child_process').spawn, + let spawn = require('child_process').spawn, jekyll = spawn('bundle', ['exec', jekyll_options], { stdio: 'inherit' }) - return jekyll - .on('error', (error) => onError() ) - .on('close', done) + jekyll.on('error', (error) => onError() ).on('close', done) } - // // HTML // -function html() { - return gulp.src(DIST + '/**/*.html') - .pipe($.if(isProduction, $.htmlmin({ - collapseWhitespace: true, - conservativeCollapse: true, - removeComments: true, - useShortDoctype: true, - collapseBooleanAttributes: true, - removeRedundantAttributes: true, - removeEmptyAttributes: true, - minifyJS: true, - minifyCSS: true - }))) - .pipe(gulp.dest(DIST)) -} +export const html = () => src(DIST + '/**/*.html') + .pipe($.if(isProduction, $.htmlmin({ + collapseWhitespace: true, + conservativeCollapse: true, + removeComments: true, + useShortDoctype: true, + collapseBooleanAttributes: true, + removeRedundantAttributes: true, + removeEmptyAttributes: true, + minifyJS: true, + minifyCSS: true + }))) + .pipe(dest(DIST)) // // Styles // -function css() { - - var processors = [ - autoprefixer({ browsers: COMPATIBILITY }), - cssnano() - ] - - return gulp.src([ - SRC + '/_assets/styl/kremalicious3.styl', - SRC + '/_assets/styl/post-*.styl' - ]) - .pipe($.if(!isProduction, $.sourcemaps.init())) - .pipe($.stylus({ 'include css': true })).on('error', onError) - .pipe($.postcss(processors)).on('error', onError) - .pipe($.if(!isProduction, $.sourcemaps.write())) - .pipe($.if(isProduction, $.header(BANNER, { pkg: pkg }))) - .pipe($.rename({ suffix: '.min' })) - .pipe(gulp.dest(DIST + '/assets/css/')) - .pipe(browser.stream()) -} +const processors = [ + autoprefixer({ browsers: COMPATIBILITY }), + cssnano() +] +export const css = () => + src([ + SRC + '/_assets/styl/kremalicious3.styl', + SRC + '/_assets/styl/post-*.styl' + ]) + .pipe($.if(!isProduction, $.sourcemaps.init())) + .pipe($.stylus({ 'include css': true })).on('error', onError) + .pipe($.postcss(processors)).on('error', onError) + .pipe($.if(!isProduction, $.sourcemaps.write())) + .pipe($.if(isProduction, $.header(BANNER, { pkg: pkg }))) + .pipe($.rename({ suffix: '.min' })) + .pipe($.if(isProduction, $.rev())) + .pipe(dest(DIST + '/assets/css/')) + .pipe($.if(isProduction, $.rev.manifest())) + .pipe($.if(isProduction, dest(DIST + '/assets/css/'))) + .pipe(browser.stream()) // @@ -228,63 +188,56 @@ function css() { // // Libraries -function jsLibraries() { - return gulp.src([ - 'node_modules/picturefill/dist/picturefill.js' - ]) - .pipe($.if(isProduction, $.uglify())).on('error', onError) - .pipe($.rename({ suffix: '.min'})) - .pipe(gulp.dest(DIST + '/assets/js/')) -} +const jsLibraries = () => src('node_modules/picturefill/dist/picturefill.js') + .pipe($.if(isProduction, $.uglify())).on('error', onError) + .pipe($.rename({ suffix: '.min'})) + .pipe($.if(isProduction, $.rev())) + .pipe(dest(DIST + '/assets/js/')) + .pipe($.if(isProduction, $.rev.manifest())) + .pipe($.if(isProduction, dest(DIST + '/assets/js/'))) // Project js -function jsProject() { - return gulp.src(SRC + '/_assets/js/kremalicious3.js') - .pipe($.sourcemaps.init()) - .pipe($.include()).on('error', onError) - .pipe($.if(isProduction, $.uglify())).on('error', onError) - .pipe($.if(!isProduction, $.sourcemaps.write())) - .pipe($.if(isProduction, $.header(BANNER, { pkg: pkg }))) - .pipe($.rename({suffix: '.min'})) - .pipe(gulp.dest(DIST + '/assets/js/')) -} +const jsProject = () => src(SRC + '/_assets/js/kremalicious3.js') + .pipe($.sourcemaps.init()) + .pipe($.include()).on('error', onError) + .pipe($.if(isProduction, $.uglify())).on('error', onError) + .pipe($.if(!isProduction, $.sourcemaps.write())) + .pipe($.if(isProduction, $.header(BANNER, { pkg: pkg }))) + .pipe($.rename({suffix: '.min'})) + .pipe($.if(isProduction, $.rev())) + .pipe(dest(DIST + '/assets/js/')) + .pipe($.if(isProduction, $.rev.manifest())) + .pipe($.if(isProduction, dest(DIST + '/assets/js/'))) // Service Worker js -function jsSW() { - return gulp.src(DIST + '/service-worker.js') - .pipe($.if(isProduction, $.uglify({ - compress: { - drop_console: true - } - }))).on('error', onError) - .pipe(gulp.dest(DIST + '/')) -} +const jsSW = () => src(DIST + '/service-worker.js') + .pipe($.if(isProduction, $.uglify({ compress: { drop_console: true } }))).on('error', onError) + .pipe(dest(DIST + '/')) // Collect all script tasks -function js() { - return jsLibraries(), jsProject(), jsSW() -} +export const js = series(jsLibraries, jsProject, jsSW) // // Icons // -function icons() { - return gulp.src(iconset.icons) - .pipe($.rename({ prefix: iconset.prefix })) - .pipe(gulp.dest(iconset.dist)) - .pipe($.filter('**/*.svg')) - .pipe($.if(isProduction, $.imagemin({ svgoPlugins: [{ removeViewBox: false }] }))) - .pipe($.svgSprite(SPRITE)) - .pipe(gulp.dest(iconset.dist)) -} +export const icons = () => src(iconset.icons) + .pipe($.rename({ prefix: iconset.prefix })) + .pipe(dest(iconset.dist)) + .pipe($.filter('**/*.svg')) + .pipe($.if(isProduction, $.imagemin({ svgoPlugins: [{ removeViewBox: false }] }))) + .pipe($.svgSprite(SPRITE)) + .pipe($.if(isProduction, $.rev())) + .pipe(dest(iconset.dist)) + .pipe($.if(isProduction, $.rev.manifest())) + .pipe($.if(isProduction, dest(iconset.dist))) // // Copy images // -function images() { - return gulp.src([ +export const images = () => + src([ SRC + '/_assets/img/**/*', '!' + SRC + '/_assets/img/entypo/**/*' ]) @@ -295,56 +248,41 @@ function images() { multipass: true, // svg svgoPlugins: [{ removeViewBox: false }] }))) - .pipe(gulp.dest(DIST + '/assets/img/')) -} + .pipe($.if(isProduction, $.rev())) + .pipe(dest(DIST + '/assets/img/')) + .pipe($.if(isProduction, $.rev.manifest())) + .pipe($.if(isProduction, dest(DIST + '/assets/img/'))) // // Copy fonts // -function fonts() { - return gulp.src(SRC + '/_assets/fonts/**/*') - .pipe(gulp.dest(DIST + '/assets/fonts/')) -} +export const fonts = () => src(SRC + '/_assets/fonts/**/*') + .pipe($.if(isProduction, $.rev())) + .pipe(dest(DIST + '/assets/fonts/')) + .pipe($.if(isProduction, $.rev.manifest())) + .pipe($.if(isProduction, dest(DIST + '/assets/fonts/'))) // // Copy media // -function media() { - return gulp.src(SRC + '/_media/**/*') - .pipe(gulp.dest(DIST + '/media/')) -} - - -// -// Revision static assets -// -function rev(done) { - // globbing is slow so do everything conditionally for faster dev build - if (isProduction) { - return gulp.src(DIST + '/assets/**/*.{css,js,png,jpg,jpeg,svg,eot,ttf,woff,woff2}') - .pipe($.if(isProduction, $.rev())) - .pipe(gulp.dest(DIST + '/assets/')) - // output rev manifest for next replace task - .pipe($.if(isProduction, $.rev.manifest())) - .pipe(gulp.dest(DIST + '/assets/')) - } - done() -} +export const media = () => src(SRC + '/_media/**/*') + .pipe(dest(DIST + '/assets/media/')) // // Replace all links to assets in files // from a manifest file // -function revReplace(done) { +export const revReplace = (done) => { + let manifest = src(DIST + '/**/rev-manifest.json') + // globbing is slow so do everything conditionally for faster dev build if (isProduction) { - var manifest = gulp.src(DIST + '/assets/rev-manifest.json') - return gulp.src(DIST + '/**/*.{html,xml,txt,json,css,js,png,jpg,jpeg,svg,eot,ttf,woff}') - .pipe($.if(isProduction, $.revReplace({ manifest: manifest }))) - .pipe(gulp.dest(DIST)) + return src(DIST + '/**/*.{html,css,js}') + .pipe($.revReplace({ manifest: manifest })) + .pipe(dest(DIST)) } done() } @@ -353,13 +291,12 @@ function revReplace(done) { // // Dev Server // -function server(done) { +export const server = (done) => { browser.init({ server: DIST, port: PORT, reloadDebounce: 2000 }) - done() } @@ -367,81 +304,116 @@ function server(done) { // // Watch for file changes // -function watch() { - gulp.watch(SRC + '_assets/styl/**/*.styl').on('all', gulp.series(css)) - gulp.watch(SRC + '_assets/js/**/*.js').on('all', gulp.series(js, browser.reload)) - gulp.watch(SRC + '_assets/img/**/*.{png,jpg,jpeg,gif,webp}').on('all', gulp.series(images, browser.reload)) - gulp.watch(SRC + '_assets/img/**/*.{svg}').on('all', gulp.series(icons, browser.reload)) - gulp.watch(SRC + '_media/**/*').on('all', gulp.series(media, browser.reload)) - gulp.watch([SRC + '/**/*.{html,xml,json,txt,md,yml}', './*.yml', SRC + '_includes/svg/*']).on('all', gulp.series('build', browser.reload)) +export const watchSrc = () => { + watch(SRC + '_assets/styl/**/*.styl').on('all', series(css)) + watch(SRC + '_assets/js/**/*.js').on('all', series(js, browser.reload)) + watch(SRC + '_assets/img/**/*.{png,jpg,jpeg,gif,webp}').on('all', series(images, browser.reload)) + watch(SRC + '_assets/img/**/*.{svg}').on('all', series(icons, browser.reload)) + watch(SRC + '_media/**/*').on('all', series(media, browser.reload)) + watch([SRC + '/**/*.{html,xml,json,txt,md,yml}', './*.yml', SRC + '_includes/svg/*']).on('all', series('build', browser.reload)) } +// +// Build banner +// +export const buildBanner = (done) => { + console.log($.util.colors.gray(" ------------------------------------------")) + console.log($.util.colors.green(' Building ' + ($.util.env.production ? 'production' : 'dev') + ' version...')) + console.log($.util.colors.gray(" ------------------------------------------")) + + done() +} + + +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// Collection tasks +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +// +// Full build +// +// `gulp build` is the development build +// `gulp build --production` is the production build +// +export const build = series(buildBanner, clean, jekyll, parallel(html, css, js, images, icons, fonts, media), revReplace) + +// +// Build site, run server, and watch for file changes +// +// `gulp dev` +// +export const dev = series(build, server, watchSrc) + +// Set `gulp dev` as default: `gulp` +export default dev + + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // Deployment // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -gulp.task('deploy', (done) => { - - // create publisher, define config - var publisher = $.awspublish.create({ - params: { - 'Bucket': S3BUCKET - }, - 'accessKeyId': process.env.AWS_ACCESS_KEY, - 'secretAccessKey': process.env.AWS_SECRET_KEY, - 'region': S3REGION - }) - - return gulp.src(DIST + '/**/*') - .pipe($.awspublishRouter({ - cache: { - // cache for 5 minutes by default - cacheTime: 300 - }, - routes: { - // all static assets, cached & gzipped - '^assets/(?:.+)\\.(?:js|css|png|jpg|jpeg|gif|ico|svg|ttf|eot|woff|woff2)$': { - cacheTime: 2592000, // cache for 1 month - gzip: true - }, - - // every other asset, cached - '^assets/.+$': { - cacheTime: 2592000 // cache for 1 month - }, - - // all html files, not cached & gzipped - '^.+\\.html': { - cacheTime: 0, - gzip: true - }, - - // font mime types - '\.ttf$': { - key: '$&', - headers: { 'Content-Type': 'application/x-font-ttf' } - }, - '\.woff$': { - key: '$&', - headers: { 'Content-Type': 'application/x-font-woff' } - }, - '\.woff2$': { - key: '$&', - headers: { 'Content-Type': 'application/x-font-woff2' } - }, - - // pass-through for anything that wasn't matched by routes above, to be uploaded with default options - "^.+$": "$&" - } - })) - // make sure everything goes to the root '/' - .pipe($.rename(function (path) { - path.dirname = S3PATH + path.dirname - })) - .pipe(parallelize(publisher.publish(), 100)) - .pipe(publisher.sync()) // delete files in bucket that are not in local folder - .pipe($.awspublish.reporter({ - states: ['create', 'update', 'delete'] - })) +// create publisher, define config +const publisher = $.awspublish.create({ + params: { + 'Bucket': S3BUCKET + }, + 'accessKeyId': process.env.AWS_ACCESS_KEY, + 'secretAccessKey': process.env.AWS_SECRET_KEY, + 'region': S3REGION }) + +export const s3 = () => src(DIST + '/**/*') + .pipe($.awspublishRouter({ + cache: { + // cache for 5 minutes by default + cacheTime: 300 + }, + routes: { + // all static assets, cached & gzipped + '^assets/(?:.+)\\.(?:js|css|png|jpg|jpeg|gif|ico|svg|ttf|eot|woff|woff2)$': { + cacheTime: 2592000, // cache for 1 month + gzip: true + }, + + // every other asset, cached + '^assets/.+$': { + cacheTime: 2592000 // cache for 1 month + }, + + // all html files, not cached & gzipped + '^.+\\.html': { + cacheTime: 0, + gzip: true + }, + + // font mime types + '\.ttf$': { + key: '$&', + headers: { 'Content-Type': 'application/x-font-ttf' } + }, + '\.woff$': { + key: '$&', + headers: { 'Content-Type': 'application/x-font-woff' } + }, + '\.woff2$': { + key: '$&', + headers: { 'Content-Type': 'application/x-font-woff2' } + }, + + // pass-through for anything that wasn't matched by routes above, to be uploaded with default options + "^.+$": "$&" + } + })) + // make sure everything goes to the root '/' + .pipe($.rename(function (path) { + path.dirname = S3PATH + path.dirname + })) + .pipe(parallelize(publisher.publish(), 100)) + .pipe(publisher.sync()) // delete files in bucket that are not in local folder + .pipe($.awspublish.reporter({ + states: ['create', 'update', 'delete'] + })) + +// `gulp deploy` +export const deploy = series(s3)