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.

Revisions

  1. subblue created this gist Mar 29, 2015.
    383 changes: 383 additions & 0 deletions gulpfile.coffee
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,383 @@
    # 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'