Skip to content

Instantly share code, notes, and snippets.

@subblue
Created March 29, 2015 13:56
Show Gist options
  • Save subblue/137274a98bca341c767e to your computer and use it in GitHub Desktop.
Save subblue/137274a98bca341c767e to your computer and use it in GitHub Desktop.
Gulp build file for the new subblue website
# node modules
fs = require 'fs'
path = require 'path'
url = require 'url'
browserSync = require 'browser-sync'
browserify = require 'browserify'
watchify = require 'watchify'
source = require 'vinyl-source-stream'
del = require 'del'
# gulp modules
gulp = require 'gulp'
autoprefix = require 'gulp-autoprefixer'
concat = require 'gulp-concat'
cssmin = require 'gulp-cssmin'
eco = require 'gulp-eco'
ect = require 'gulp-ect-simple'
filter = require 'gulp-filter'
newer = require 'gulp-newer'
notify = require 'gulp-notify'
rename = require 'gulp-rename'
sass = require 'gulp-sass'
sourcemaps = require 'gulp-sourcemaps'
uglify = require 'gulp-uglify'
gulpif = require 'gulp-if'
responsive = require 'gulp-responsive'
awspublish = require 'gulp-awspublish'
awsrouter = require 'gulp-awspublish-router'
minifyHTML = require 'gulp-minify-html'
reload = browserSync.reload
###############################################
config =
src : 'src' # main path for all source files
dest : 'dist' # output path for all deployable files
dist : 'dist' # output path for distribution builds
debug : true # include source maps
port : 3003 # dev server port
env : 'dev' # when not set to dev js and css will be compressed
index : 'home.html' # default file for rewrites
analytics: 'XXXX' # Google Analytics code
bucket : 'XXXX' # S3 bucket name
region : 'eu-west-1' # S3 region
config.scripts =
src: "./#{config.src}/scripts/main.coffee"
dest: "./#{config.dest}/scripts/" # output folder
filename: 'main.js' # output filename
config.styles =
src: "./#{config.src}/styles/main.scss"
dest: "./#{config.dest}/scripts/" # output folder
filename: 'main.css' # output filename
config.images =
src: "./#{config.src}/images/**"
dest: "./#{config.dest}/images/"
config.resize =
src: "./masters"
dest: "./#{config.src}/images"
config.minify =
quotes: true
loose: false
conditionals: true
spare: true
empty: true
cdata: true
###############################################
gulp.task 'default', ['watch']
gulp.task 'watch', ['setWatch', 'browserSync'], ->
gulp.watch("#{config.src}/**/*.scss", ['styles'])
gulp.watch("#{config.src}/**/*.ect", ['ect'])
gulp.watch("#{config.src}/data/*.html", ['data'])
gulp.task 'setWatch', ->
global.isWatching = true
gulp.task 'browserSync', ['dev'], ->
browserSync
files: [
"#{config.dest}/*.html"
]
server:
baseDir: [config.dest, config.src, '.']
middleware: [
(req, res, next) ->
return next() if /\.(scss|coffee|css|js|ico|jpg|gif|png|svg)/.test(req.url)
console.log 'Requesting:', req.url
# https://github.com/shakyShane/browser-sync/issues/204#issuecomment-51469264
fileName = url.parse(req.url)
fileName = fileName.href.split(fileName.search).join('')
fileName = fileName.replace(/\.html$/i, '')
folder = path.resolve(__dirname, config.dest)
fileExists = fs.existsSync(folder + fileName + '.html')
if !fileExists && fileName.indexOf("browser-sync-client") < 0 && fileName.indexOf("/data/") < 0
req.url = "/#{config.index}"
else
req.url = "#{fileName}.html"
console.log 'Serving:', req.url
next()
# gzip.gzip()
]
port: config.port
debugInfo: false
logLevel: "info"
open: false
debounce: 100
notify: false
ghostMode: false
online: false
ui: false
gulp.task 'dev', ['clean'], ->
gulp.start 'build'
gulp.task 'clean', (cb) ->
del([config.dest], cb)
gulp.task 'build', ['ect', 'images', 'browserify', 'styles']
gulp.task 'ect', ['data'], ->
pageData = require './src/scripts/site/config/page_data'
dataFn = (file) ->
key = '/' + file.relative.replace('.ect', '')
data =
pages: pageData.pages
page: pageData.index[key] || {title: 'sub.blue'}
analytics: config.analytics
data.className = "page hidden "
data.className += "style-#{data.page.mode} " if data.page.mode
data.className += (data.page.className || data.page.path || '').replace('/', '')
data
gulp
.src "#{config.src}/pages/*.ect"
.pipe ect(options: {root: 'src/pages', ext: '.ect', cache: false}, data: dataFn)
.pipe gulpif(config.env == 'production', minifyHTML(config.minify))
.pipe gulp.dest(config.dest)
.pipe reload(stream: true)
gulp.task 'data', ->
pageData = require './src/scripts/site/config/page_data'
gulp
.src "#{config.src}/pages/data/*.ect"
.pipe ect(options: {root: 'src/data', ext: '.ect', cache: false}, data: pageData)
.pipe gulpif(config.env == 'production', minifyHTML(config.minify))
.pipe gulp.dest("#{config.dest}/data")
gulp.task 'images', ->
gulp
.src config.images.src
.pipe newer(config.images.dest)
.pipe gulp.dest(config.images.dest)
gulp.task 'resize', ['resize:thumbnails', 'resize:backgrounds', 'resize:gallery'], ->
gulp.start 'images'
gulp.task 'resize:thumbnails', ->
gulp.src "./masters/thumbnails/*.jpg"
.pipe responsive
'*.jpg': [
{rename: {suffix: '-400'}, width: 400, quality: 80}
{rename: {suffix: '-800'}, width: 800, quality: 65}
]
{progressive: true, withMetadata: false, strictMatchConfig: false, strictMatchImages: false, errorOnEnlargement: false, max: true}
.pipe gulp.dest("#{config.resize.dest}/thumbnails")
gulp.task 'resize:articles', ->
gulp.src "./masters/articles/**/*.jpg"
.pipe responsive
'**/*.jpg': [
{rename: {suffix: '@1x'}, width: '50%', quality: 80}
{rename: {suffix: '@2x'}, width: '100%', quality: 75}
]
{progressive: true, withMetadata: false, strictMatchConfig: false, strictMatchImages: false, errorOnEnlargement: false, max: true}
.pipe gulp.dest("#{config.resize.dest}/articles")
gulp.task 'resize:backgrounds', ['resize:backgrounds:png'], ->
gulp.src "./masters/backgrounds/*.jpg"
.pipe responsive
'*.jpg': [
{rename: {suffix: '-480'}, width: 480, quality: 80}
{rename: {suffix: '-480@2x'}, width: 960, quality: 55}
{rename: {suffix: '-960'}, width: 960, quality: 80}
{rename: {suffix: '-960@2x'}, width: 1920, quality: 75}
{rename: {suffix: '-1024'}, width: 1024, quality: 80}
{rename: {suffix: '-1024@2x'}, width: 2048, quality: 75}
{rename: {suffix: '-1440'}, width: 1440, quality: 80}
{rename: {suffix: '-1440@2x'}, width: 2880, quality: 75}
]
{progressive: true, withMetadata: false, strictMatchConfig: false, strictMatchImages: false, errorOnEnlargement: false, max: true}
.pipe gulp.dest("#{config.resize.dest}/backgrounds")
gulp.task 'resize:backgrounds:png', ->
gulp.src "./masters/backgrounds/*.png"
.pipe gulp.dest("#{config.resize.dest}/backgrounds")
gulp.task 'resize:gallery', ->
gulp.src "./masters/gallery/**/*.jpg"
.pipe responsive
'**/*.jpg': [
{rename: {suffix: '-480'}, width: 480, height: 480, quality: 80}
{rename: {suffix: '-480@2x'}, width: 960, height: 960, quality: 55}
{rename: {suffix: '-960'}, width: 960, height: 960, quality: 80}
{rename: {suffix: '-960@2x'}, width: 1920, height: 1920, quality: 75}
{rename: {suffix: '-1024'}, width: 1024, height: 1024, quality: 80}
{rename: {suffix: '-1024@2x'}, width: 2048, height: 2048, quality: 75}
{rename: {suffix: '-1440'}, width: 1440, height: 1440, quality: 75}
{rename: {suffix: '-1440@2x'}, width: 2880, height: 2880, quality: 75}
{rename: {suffix: '-1920'}, width: 1920, height: 1920, quality: 75}
{rename: {suffix: '-1920@2x'}, width: 3840, height: 3840, quality: 75}
]
{progressive: true, withMetadata: true, strictMatchConfig: false, strictMatchImages: false, errorOnEnlargement: false, max: true}
.pipe gulp.dest("#{config.resize.dest}/gallery")
# browserify task based on: https://github.com/greypants/gulp-starter
gulp.task 'browserify', ->
opts =
# required watchify args
cache: {}
packageCache: {}
fullPaths: global.isWatching
# browserify options
entries: config.scripts.src
extensions: ['.coffee', '.hbs', '.js']
debug: config.debug
detectGlobals: false
bundler = browserify(opts)
.transform 'coffeeify'
if config.env != 'dev'
bundler = bundler.transform {global: true}, 'uglifyify'
bundle = ->
bundler
.bundle()
.on('error', (err) -> console.log(err.message))
# Use vinyl-source-stream to make the stream gulp compatible with output file name here
.pipe source(config.scripts.filename)
.pipe gulp.dest config.scripts.dest
.pipe reload(stream: true)
if global.isWatching
# Rebundle with watchify on changes.
bundler = watchify(bundler)
bundler.on('update', bundle)
bundle()
gulp.task 'styles', ->
dev = config.env == 'dev'
gulp.src config.styles.src
.pipe gulpif(dev, sourcemaps.init())
.pipe sass(errLogToConsole: true)
.pipe autoprefix(browsers: ['last 1 version', 'iOS 6'], cascade: false)
.pipe gulpif(dev, sourcemaps.write())
.pipe gulpif(!dev, cssmin())
.pipe gulp.dest config.styles.dest
.pipe filter('**/*.css') # Filtering stream to only css files
.pipe reload(stream: true)
gulp.task 'deploy', ['dist'], ->
gulp.start 'publish'
# See: https://github.com/jussi-kalliokoski/gulp-awspublish-router
gulp.task 'publish', ->
publisher = awspublish.create(bucket: config.bucket, region: config.region)
gulp.src '**/*', cwd: "./#{config.dist}/"
.pipe awsrouter
cache:
# cache for 5 minutes by default
cacheTime: 5 * 60
public: true
allowTransform: true
routes:
"^scripts/(?:.+)\\.(?:js|css)$":
# don't modify original key. this is the default
key: "$&"
# use gzip for assets that benefit from it
gzip: true
# cache static assets for 1 day
cacheTime: 24 * 3600
"^images/.+$":
# cache static assets for 1 year
cacheTime: 365 * 24 * 3600
# e.g. upload html files without html extension
"^([^/]+)\\.html":
key: "$1"
headers:
"Content-Type": "text/html"
"^data/(?:.+)\\.(?:html)$":
# don't modify original key. this is the default
key: "$&"
# use gzip for assets that benefit from it
gzip: true
# pass-through for anything that wasn't matched by routes above, to be uploaded with default options
"^.+$": "$&"
.pipe publisher.publish()
.pipe publisher.sync()
.pipe publisher.cache()
.pipe awspublish.reporter(states: ['create', 'update', 'delete'])
gulp.task 'dist', ->
config.debug = false
config.env = 'production'
gulp.start 'distbuild'
gulp.task 'distbuild', ['clean'], ->
gulp.start 'build'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment