2017-08-24 11:39:07 +02:00
/* eslint-disable no-console */
2017-08-09 17:12:21 +02:00
2017-08-24 11:39:07 +02:00
import fs from 'fs'
2017-08-09 17:12:21 +02:00
import { src , dest , watch , parallel , series } from 'gulp'
2017-08-24 11:39:07 +02:00
import del from 'del'
import parallelize from 'concurrent-transform'
import browser from 'browser-sync'
import critical from 'critical'
import yaml from 'js-yaml'
import request from 'request'
2017-08-09 17:12:21 +02:00
// required to get our mix of old and ES6+ js to work with ugify-js 3
2017-08-24 11:39:07 +02:00
import uglifyjs from 'uglify-es'
import composer from 'gulp-uglify/composer'
2017-08-09 17:12:21 +02:00
// get all the configs: `pkg` and `site`
import pkg from './package.json'
2017-08-24 11:39:07 +02:00
// load plugins
const spawn = require ( 'child_process' ) . spawn
const $ = require ( 'gulp-load-plugins' ) ( )
const minify = composer ( uglifyjs , console )
2017-08-09 17:12:21 +02:00
const site = yaml . safeLoad ( fs . readFileSync ( './_config.yml' ) )
// handle errors
const onError = ( error ) => {
2017-08-24 11:39:07 +02:00
console . log ( $ . util . colors . red ( '\nYou fucked up:' , error . message , 'on line' , error . lineNumber , '\n' ) )
2017-08-09 17:12:21 +02:00
this . emit ( 'end' )
}
// 'development' is just default, production overrides are triggered
// by adding the production flag to the gulp command e.g. `gulp build --production`
2017-08-24 11:39:07 +02:00
const isProduction = ( $ . util . env . production === true )
const isStaging = ( $ . util . env . staging === true )
2017-08-09 17:12:21 +02:00
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Config
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Port to use for the development server
const PORT = 1337
// paths
2017-08-24 11:39:07 +02:00
const SRC = ` ${ site . source } / `
const DIST = ` ${ site . destination } / `
2017-08-09 17:12:21 +02:00
// deployment
2017-08-24 11:39:07 +02:00
const S3BUCKET = 'beta.ipdb.io'
const S3REGION = 'eu-central-1'
const S3BUCKET _BETA = 'beta.ipdb.io'
const S3REGION _BETA = 'eu-central-1'
2017-08-09 17:12:21 +02:00
// SVG sprite
const SPRITECONFIG = {
2017-08-24 11:39:07 +02:00
dest : ` ${ DIST } assets/img/ ` ,
mode : {
symbol : {
dest : './' ,
sprite : 'sprite.svg'
}
}
2017-08-09 17:12:21 +02:00
}
// code banner
const BANNER = [
2017-08-24 11:39:07 +02:00
'/**' ,
' ** <%= pkg.name %>' ,
' ** <%= pkg.description %>' ,
' ** <%= pkg.homepage %>' ,
' **' ,
' ** <%= pkg.author.name %> <<%= pkg.author.email %>>' ,
' **/' ,
''
2017-08-09 17:12:21 +02:00
] . join ( '\n' )
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Tasks
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
// Delete build artifacts
//
export const clean = ( ) =>
del ( [
2017-08-24 11:39:07 +02:00
` ${ DIST } **/* ` ,
` ${ DIST } .* ` // delete all hidden files
2017-08-09 17:12:21 +02:00
] )
//
// Jekyll
//
export const jekyll = ( done ) => {
browser . notify ( 'Compiling Jekyll' )
2017-08-24 11:39:07 +02:00
let jekyllOptions
2017-08-09 17:12:21 +02:00
if ( isProduction ) {
process . env . JEKYLL _ENV = 'production'
2017-08-24 11:39:07 +02:00
jekyllOptions = 'jekyll build'
2017-08-09 17:12:21 +02:00
} else if ( isStaging ) {
process . env . JEKYLL _ENV = 'staging'
2017-08-24 11:39:07 +02:00
jekyllOptions = 'jekyll build'
2017-08-09 17:12:21 +02:00
} else {
process . env . JEKYLL _ENV = 'development'
2017-08-24 11:39:07 +02:00
jekyllOptions = 'jekyll build --incremental --drafts --future'
2017-08-09 17:12:21 +02:00
}
2017-08-24 11:39:07 +02:00
const jekyllInstance = spawn ( 'bundle' , [ 'exec' , jekyllOptions ] , { stdio : 'inherit' } )
2017-08-09 17:12:21 +02:00
2017-08-24 11:39:07 +02:00
jekyllInstance . on ( 'error' , ( error ) => onError ( error ) ) . on ( 'close' , done )
2017-08-09 17:12:21 +02:00
}
//
// HTML
//
2017-08-24 11:39:07 +02:00
export const html = ( ) => src ( ` ${ DIST } **/*.html ` )
2017-08-09 17:12:21 +02:00
. pipe ( $ . if ( isProduction || isStaging , $ . htmlmin ( {
collapseWhitespace : true ,
conservativeCollapse : true ,
removeComments : true ,
useShortDoctype : true ,
collapseBooleanAttributes : true ,
removeRedundantAttributes : true ,
removeEmptyAttributes : true ,
minifyJS : true ,
minifyCSS : true
} ) ) )
. pipe ( dest ( DIST ) )
//
// Styles
//
export const css = ( ) => src ( [
2017-08-24 11:39:07 +02:00
` ${ SRC } _assets/scss/ipdb.scss ` ,
` ${ SRC } _assets/scss/page-*.scss `
] )
2017-08-09 17:12:21 +02:00
. pipe ( $ . if ( ! ( isProduction || isStaging ) , $ . sourcemaps . init ( ) ) )
. pipe ( $ . sass ( {
includePaths : [ 'node_modules' ]
} ) . on ( 'error' , $ . sass . logError ) )
. pipe ( $ . autoprefixer ( ) )
. pipe ( $ . if ( isProduction || isStaging , $ . cleanCss ( ) ) )
. pipe ( $ . if ( ! ( isProduction || isStaging ) , $ . sourcemaps . write ( ) ) )
2017-08-24 11:39:07 +02:00
. pipe ( $ . if ( isProduction || isStaging , $ . header ( BANNER , { pkg } ) ) )
2017-08-09 17:12:21 +02:00
. pipe ( $ . rename ( { suffix : '.min' } ) )
2017-08-24 11:39:07 +02:00
. pipe ( dest ( ` ${ DIST } assets/css/ ` ) )
2017-08-09 17:12:21 +02:00
. pipe ( browser . stream ( ) )
// inline critical-path CSS
export const criticalCss = ( done ) => {
if ( isProduction || isStaging ) {
critical . generate ( {
base : DIST ,
src : 'index.html' ,
dest : 'index.html' ,
inline : true ,
minify : true ,
dimensions : [ {
height : 320 ,
width : 640
} , {
height : 600 ,
width : 800
} , {
height : 900 ,
width : 1360
} ]
} )
}
done ( )
}
//
// JavaScript
//
export const js = ( ) =>
src ( [
2017-08-24 11:39:07 +02:00
` ${ SRC } _assets/js/ipdb.js ` ,
` ${ SRC } _assets/js/page-*.js `
2017-08-09 17:12:21 +02:00
] )
2017-08-24 11:39:07 +02:00
. pipe ( $ . if ( ! ( isProduction || isStaging ) , $ . sourcemaps . init ( ) ) )
. pipe ( $ . include ( {
includePaths : [ 'node_modules' , ` ${ SRC } _assets/js ` ]
} ) ) . on ( 'error' , onError )
. pipe ( $ . if ( isProduction || isStaging , minify ( ) ) )
. on ( 'error' , onError )
. pipe ( $ . if ( ! ( isProduction || isStaging ) , $ . sourcemaps . write ( ) ) )
. pipe ( $ . if ( isProduction || isStaging , $ . header ( BANNER , { pkg } ) ) )
. pipe ( $ . rename ( { suffix : '.min' } ) )
. pipe ( dest ( ` ${ DIST } assets/js/ ` ) )
2017-08-09 17:12:21 +02:00
//
// SVG sprite
//
2017-08-24 11:39:07 +02:00
export const svg = ( ) => src ( ` ${ SRC } _assets/img/*.svg ` )
2017-08-09 17:12:21 +02:00
. pipe ( $ . if ( isProduction || isStaging , $ . imagemin ( {
svgoPlugins : [ { removeRasterImages : true } ]
} ) ) )
. pipe ( $ . svgSprite ( SPRITECONFIG ) )
2017-08-24 11:39:07 +02:00
. pipe ( dest ( ` ${ DIST } assets/img/ ` ) )
2017-08-09 17:12:21 +02:00
//
// Copy Images
//
2017-08-24 11:39:07 +02:00
export const images = ( ) => src ( ` ${ SRC } _assets/img/**/* ` )
2017-08-09 17:12:21 +02:00
. pipe ( $ . if ( isProduction || isStaging , $ . imagemin ( [
2017-08-24 11:39:07 +02:00
$ . imagemin . gifsicle ( { interlaced : true } ) ,
$ . imagemin . jpegtran ( { progressive : true } ) ,
$ . imagemin . optipng ( { optimizationLevel : 5 } ) ,
$ . imagemin . svgo ( { plugins : [ { removeViewBox : true } ] } )
2017-08-09 17:12:21 +02:00
] ) ) )
2017-08-24 11:39:07 +02:00
. pipe ( dest ( ` ${ DIST } assets/img/ ` ) )
2017-08-09 17:12:21 +02:00
//
// Revision static assets
//
export const rev = ( done ) => {
// globbing is slow so do everything conditionally for faster dev build
if ( isProduction || isStaging ) {
2017-08-24 11:39:07 +02:00
return src ( ` ${ DIST } assets/**/*.{css,js,png,jpg,jpeg,svg,eot,ttf,woff,woff2} ` )
2017-08-09 17:12:21 +02:00
. pipe ( $ . rev ( ) )
2017-08-24 11:39:07 +02:00
. pipe ( dest ( ` ${ DIST } assets/ ` ) )
2017-08-09 17:12:21 +02:00
// output rev manifest for next replace task
. pipe ( $ . rev . manifest ( ) )
2017-08-24 11:39:07 +02:00
. pipe ( dest ( ` ${ DIST } assets/ ` ) )
2017-08-09 17:12:21 +02:00
}
done ( )
}
//
// Replace all links to assets in files
// from a manifest file
//
export const revReplace = ( done ) => {
// globbing is slow so do everything conditionally for faster dev build
if ( isProduction || isStaging ) {
2017-08-24 11:39:07 +02:00
const manifest = src ( ` ${ DIST } assets/rev-manifest.json ` )
2017-08-09 17:12:21 +02:00
2017-08-24 11:39:07 +02:00
return src ( ` ${ DIST } **/*.{html,css,js} ` )
. pipe ( $ . revReplace ( { manifest } ) )
2017-08-09 17:12:21 +02:00
. pipe ( dest ( DIST ) )
}
done ( )
}
//
// Dev Server
//
export const server = ( done ) => {
browser . init ( {
server : DIST ,
port : PORT ,
reloadDebounce : 2000
} )
done ( )
}
//
// Watch for file changes
//
export const watchSrc = ( ) => {
2017-08-24 11:39:07 +02:00
watch ( ` ${ SRC } _assets/scss/**/*.scss ` ) . 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 ( svg , browser . reload ) )
watch ( [
` ${ SRC } **/*.{html,xml,json,txt,md,yml} ` ,
'./*.yml' ,
` ${ SRC } _includes/svg/* `
] ) . on ( 'all' , series ( 'build' , browser . reload ) )
2017-08-09 17:12:21 +02:00
}
//
// Build banner
//
2017-08-24 11:39:07 +02:00
/* eslint-disable max-len */
2017-08-09 17:12:21 +02:00
const buildBanner = ( done ) => {
2017-08-24 11:39:07 +02:00
let buildEnvironment
if ( $ . util . env . production ) {
buildEnvironment = 'production'
} else if ( $ . util . env . staging ) {
buildEnvironment = 'staging'
} else {
buildEnvironment = 'dev'
}
console . log ( $ . util . colors . gray ( ' ------------------------------------------' ) )
console . log ( $ . util . colors . green ( ` Building ${ buildEnvironment } version... ` ) )
console . log ( $ . util . colors . gray ( ' ------------------------------------------' ) )
2017-08-09 17:12:21 +02:00
done ( )
}
//
// Deploy banner
//
const deployBanner = ( done ) => {
2017-08-24 11:39:07 +02:00
let deployTarget
2017-08-24 15:21:12 +02:00
if ( $ . util . env . live ) {
2017-08-24 11:39:07 +02:00
deployTarget = 'Live'
2017-08-24 15:21:12 +02:00
} else if ( $ . util . env . beta ) {
2017-08-24 11:39:07 +02:00
deployTarget = 'Beta'
} else {
deployTarget = 'Gamma'
}
if ( ( $ . util . env . live || $ . util . env . beta || $ . util . env . gamma ) === true ) {
console . log ( $ . util . colors . gray ( ' ------------------------------------------' ) )
console . log ( $ . util . colors . green ( ` Deploying to ${ deployTarget } ... ` ) )
console . log ( $ . util . colors . gray ( ' ------------------------------------------' ) )
2017-08-09 17:12:21 +02:00
} else {
console . log ( $ . util . colors . red ( '\nHold your horses! You need to specify a deployment target like so: gulp deploy --beta. Possible targets are: --live, --beta, --gamma\n' ) )
}
done ( )
}
2017-08-24 11:39:07 +02:00
/* eslint-enable max-len */
2017-08-09 17:12:21 +02:00
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Collection tasks
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
// Full build
//
// `gulp build` is the development build
// `gulp build --production` is the production build
//
2017-08-24 11:39:07 +02:00
export const build = series (
buildBanner , clean , jekyll ,
parallel ( html , css , js , images , svg ) ,
rev , revReplace , criticalCss
)
2017-08-09 17:12:21 +02:00
//
// Build site, run server, and watch for file changes
//
// `gulp dev`
//
2017-08-24 11:39:07 +02:00
export const dev = series (
build , server , watchSrc
)
2017-08-09 17:12:21 +02:00
// Set `gulp dev` as default: `gulp`
export default dev
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Deployment
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
// gulp deploy --live
// gulp deploy --beta
// gulp deploy --gamma
//
export const s3 = ( ) => {
// create publisher, define config
2017-08-24 11:39:07 +02:00
let publisher
2017-08-09 17:12:21 +02:00
if ( $ . util . env . live === true ) {
2017-08-24 11:39:07 +02:00
publisher = $ . awspublish . create ( {
'params' : { 'Bucket' : S3BUCKET } ,
2017-08-09 17:12:21 +02:00
'accessKeyId' : process . env . AWS _ACCESS _KEY ,
'secretAccessKey' : process . env . AWS _SECRET _KEY ,
'region' : S3REGION
} )
} else if ( $ . util . env . beta === true ) {
2017-08-24 11:39:07 +02:00
publisher = $ . awspublish . create ( {
'params' : { 'Bucket' : S3BUCKET _BETA } ,
2017-08-09 17:12:21 +02:00
'accessKeyId' : process . env . AWS _BETA _ACCESS _KEY ,
'secretAccessKey' : process . env . AWS _BETA _SECRET _KEY ,
'region' : S3REGION _BETA
} )
} else {
return
}
2017-08-24 11:39:07 +02:00
src ( ` ${ DIST } **/* ` )
2017-08-09 17:12:21 +02:00
. 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/.+$' : {
2017-08-24 11:39:07 +02:00
cacheTime : 2592000 // cache for 1 month
2017-08-09 17:12:21 +02:00
} ,
// all html files, not cached & gzipped
'^.+\\.html' : {
cacheTime : 0 ,
gzip : true
} ,
// all pdf files, not cached
'^.+\\.pdf' : {
cacheTime : 0
} ,
// font mime types
2017-08-24 11:39:07 +02:00
'.ttf$' : {
2017-08-09 17:12:21 +02:00
key : '$&' ,
headers : { 'Content-Type' : 'application/x-font-ttf' }
} ,
2017-08-24 11:39:07 +02:00
'.woff$' : {
2017-08-09 17:12:21 +02:00
key : '$&' ,
headers : { 'Content-Type' : 'application/x-font-woff' }
} ,
2017-08-24 11:39:07 +02:00
'.woff2$' : {
2017-08-09 17:12:21 +02:00
key : '$&' ,
headers : { 'Content-Type' : 'application/x-font-woff2' }
} ,
2017-08-24 11:39:07 +02:00
// pass-through for anything that wasn't matched by routes above,
// to be uploaded with default options
'^.+$' : '$&'
2017-08-09 17:12:21 +02:00
}
} ) )
. pipe ( parallelize ( publisher . publish ( ) , 100 ) ) . on ( 'error' , onError )
. pipe ( publisher . sync ( ) ) // delete files in bucket that are not in local folder
. pipe ( $ . awspublish . reporter ( {
states : [ 'create' , 'update' , 'delete' ]
} ) )
}
//
// Ping search engines on live deployment
//
export const seo = ( done ) => {
2017-08-24 11:39:07 +02:00
const googleUrl = 'http://www.google.com/webmasters/tools/ping?sitemap='
const bingUrl = 'http://www.bing.com/webmaster/ping.aspx?siteMap='
2017-08-09 17:12:21 +02:00
2017-08-24 11:39:07 +02:00
const showResponse = ( error , response ) => {
2017-08-09 17:12:21 +02:00
if ( error ) {
$ . util . log ( $ . util . colors . red ( error ) )
} else {
$ . util . log ( $ . util . colors . gray ( 'Status:' , response && response . statusCode ) )
if ( response . statusCode === 200 ) {
$ . util . log ( $ . util . colors . green ( 'Successfully notified' ) )
}
}
}
2017-08-24 11:39:07 +02:00
if ( $ . util . env . live === true ) {
request ( ` ${ googleUrl + site . url } /sitemap.xml ` , showResponse )
request ( ` ${ bingUrl + site . url } /sitemap.xml ` , showResponse )
}
2017-08-09 17:12:21 +02:00
done ( )
}
//
// `gulp deploy`
//
export const deploy = series ( deployBanner , s3 , seo )