UNPKG

generator-gulp-of-drano

Version:

Yeoman generator for an angular.js site. CoffeeScript, stylus, jade, gulp.js. Bootstrap, angular-strap, nib, angular-ui-router. Heroku + s3 deployment tasks included.

506 lines (411 loc) 12.3 kB
gulp = require('gulp') sprite = require('css-sprite').stream es = require('event-stream') seq = require('run-sequence') lazypipe = require('lazypipe') bowerFiles = require('main-bower-files') pXor = require('protractor-ci') del = require('del') path = require('path') pngcrush = require('imagemin-pngcrush') LIVERELOAD_PORT = 35729 paths = development: '.tmp' production: 'dist-production' # Load plugins $ = require('gulp-load-plugins')() # TODO: break out into modules $.injectAppFiles = require('./lib/gulp-inject-assets') $.userefStream = require('./lib/gulp-useref-stream') $.dumbSass = require('./lib/gulp-dumb-sass') # global refs config = null sassFilter = null jsFilter = null jsTmplFilter = null coffeeFilter = null spriteFilter = null imgFilter = null indexFilter = null indexHTMLFilter = null cssFilter = null fontFilter = null xdFilter = null publisher = null isCompiled = '**/*.{js,css,html,jpg,png,gif,eot,svg,ttf,woff}' textFileFilter = null initEnv = (envName) -> # ensure that env name set process.env.NODE_ENV ?= envName || 'development' # set dist dir process.env.DIST_DIR = paths[process.env.NODE_ENV] # set tag for release process.env.TAG = process.env.NODE_ENV + '-' + new Date().getTime() # load config after env has been determined config = require('config') # re-init filters for each task initFilters = -> sassFilter = $.filter('styles/**/{,_}*.{sass,scss}') jsFilter = $.filter('scripts/**/*.js') jsTmplFilter = $.filter('views/**/*.jade') coffeeFilter = $.filter('scripts/**/*.coffee') spriteFilter = $.filter('images/sprites/**/*.png') imgFilter = $.filter('images/**/*') indexFilter = $.filter('index.jade') indexHTMLFilter = $.filter('index.html') cssFilter = $.filter('styles/**/*.css') textFileFilter = $.filter('**/*.{js,css,html,txt,json}') fontFilter = $.filter('**/*.{eot,svg,ttf,woff}') xdFilter = $.filter('**/cross-domain/respond*.*') # app-sass processSass = lazypipe() .pipe(-> sassFilter) .pipe(-> $.sass({ includePaths: [ 'app/bower_components/font-awesome/scss' 'app/bower_components/bootstrap-sass-official/assets/stylesheets' ] })) .pipe(-> $.autoprefixer('last 1 version')) .pipe(-> sassFilter.restore()) # app-js processAppJs = lazypipe() .pipe(-> jsFilter) .pipe(-> $.cached('js')) .pipe(-> $.jshint('.jshintrc')) .pipe(-> $.jshint.reporter('default')) .pipe(-> $.remember('js')) .pipe(-> jsFilter.restore()) postProcessJS = lazypipe() .pipe(-> $.ngAnnotate({ add: true, single_quotes: true })) .pipe(-> $.uglify()) # app-coffee processAppCoffee = lazypipe() .pipe(-> coffeeFilter) .pipe(-> $.cached('coffee')) .pipe(-> $.coffee({bare: true})) .pipe(-> $.remember('coffee')) .pipe(-> coffeeFilter.restore()) # sprites processSprites = lazypipe() .pipe(-> spriteFilter) .pipe(-> $.cached('sprites')) .pipe(-> sprite({ cssPath: '/images', processor: 'scss', style: '_sprite.scss' name: 'sprite' retina: true })) .pipe(-> $.if('*.png', gulp.dest('app/images/'), gulp.dest('app/styles/include/'))) # js templates processJSTemplates = lazypipe() .pipe(-> jsTmplFilter) .pipe(-> $.cached('js-tmpl')) .pipe(-> $.jade()) .pipe(-> $.ngHtml2js({ moduleName: '<%= _.camelize(projectName.toLowerCase()) %>dbxUiPartials' })) .pipe(-> $.remember('js-tmpl')) .pipe(-> jsTmplFilter.restore()) # flatten fonts into /fonts dir processFonts = lazypipe() .pipe(-> fontFilter) .pipe(-> $.cached('fonts')) .pipe(-> $.rename({ dirname: 'fonts' })) .pipe(-> $.remember('fonts')) .pipe(-> fontFilter.restore()) # flatten xd files into /cross-domain dir processXDProxy = lazypipe() .pipe(-> xdFilter) .pipe(-> $.cached('xd-proxy')) .pipe(-> $.rename({ dirname: 'cross-domain' })) .pipe(-> $.remember('xd-proxy')) .pipe(-> xdFilter.restore()) # inject ie8 deps injectLegacyDeps = lazypipe() .pipe($.inject, gulp.src(bowerFiles()).pipe($.filter((f) -> /legacy/.test(f.path) ), {read: false}), { ignorePath: ['app'], starttag: '<!bower-legacy:{{ext}}>', endtag: '<!endbower-legacy>' }) # inject >ie8 deps injectModernDeps = lazypipe() .pipe($.inject, gulp.src(bowerFiles()).pipe($.filter((f) -> /modern/.test(f.path) ), {read: false}), { ignorePath: ['app'], starttag: '<!-- bower-modern:{{ext}}-->', endtag: '<!-- endbower-modern-->' }) # inject universal deps injectOtherDeps = lazypipe() .pipe($.inject, gulp.src(bowerFiles()).pipe($.filter((f) -> /^((?!(legacy|modern|\/jquery\/|\/angular\/)).)*$/.test(f.path) ), {read: false}), { ignorePath: ['app'], starttag: '<!-- bower-all:{{ext}}-->', endtag: '<!-- endbower-all-->' }) # compile, inject deps into index file processSPAIndex = lazypipe() .pipe(-> indexFilter) .pipe(-> $.cached('spa-index-ext-deps')) .pipe(-> $.jade({ pretty: true })) .pipe(-> injectLegacyDeps()) .pipe(-> injectModernDeps()) .pipe(-> injectOtherDeps()) .pipe(-> $.remember('spa-index-ext-deps')) .pipe(-> indexFilter.restore()) generateSprites = lazypipe() .pipe(-> processSprites()) # optimize images optimizeImages = lazypipe() .pipe(-> imgFilter) .pipe(-> $.cached('imagemin')) .pipe(-> $.imagemin({ progressive: true #use: [pngcrush()] })) .pipe(-> $.remember('imagemin')) .pipe(-> imgFilter.restore()) # build all sources into html, js, css transpile = lazypipe() .pipe(-> optimizeImages()) .pipe(-> processAppJs()) .pipe(-> $.sourcemaps.init()) .pipe(-> processSass()) .pipe(-> processAppCoffee()) .pipe(-> processJSTemplates()) .pipe(-> $.sourcemaps.write()) .pipe(-> processSPAIndex()) .pipe(-> processFonts()) .pipe(-> processXDProxy()) # minimize, cache-bust, cdnize compiled code optimize = lazypipe() .pipe(-> $.userefStream()) .pipe(-> $.if('**/*.css', $.minifyCss())) .pipe(-> $.if('**/*.js', postProcessJS())) .pipe(-> $.buffer()) .pipe(-> $.if(['/**/!(index.html)*'], $.rev())) .pipe(-> $.revReplaceStream()) .pipe(-> textFileFilter) .pipe(-> $.cdnizer({ defaultCDNBase: config.STATIC_URL allowRev: true allowMin: true files: ['/**/!(respond.proxy)*'] })) .pipe(-> textFileFilter.restore()) # sync optimized code with s3 s3 = lazypipe() .pipe(-> $.awspublish.gzip()) .pipe(-> publisher.publish({ 'Cache-Control': 'max-age=315360000, no-transform, public' })) #.pipe(-> publisher.sync()) .pipe(-> $.awspublish.reporter()) # generate spritemaps. outputs into app dir for sass deps gulp.task 'sprites', -> initFilters() gulp.src('app/**/*', {base: 'app'}) .pipe(generateSprites()) # clean directory, build all files gulp.task 'init', ['sprites'], -> initEnv('development') # start fresh del(process.env.DIST_DIR) initFilters() gulp.src(['app/**/*'], {base: 'app'}) .pipe(transpile()) .pipe($.injectAppFiles()) .pipe($.if([isCompiled], gulp.dest(process.env.DIST_DIR))) .pipe($.size()) # compile, start dev server, update files on change gulp.task 'default', ['init'], -> tinylr = require('tiny-lr')() # start node server $.nodemon({ script: 'app.js', ext: 'html js', ignore: ['**/*'], env: { 'NODE_ENV': process.env.NODE_ENV 'DIST_DIR': process.env.DIST_DIR } watch: [] }) .on('restart', -> console.log('restarted')) # start live reload server tinylr.listen(LIVERELOAD_PORT) # watch sprites for changes, compile into app dir gulp.watch('app/images/sprites/**/*.png', ['sprites']) # watch app dir for changes, build + pipe to browser gulp.watch('app/**/*').on 'change', (ev) -> initFilters() if /^(added|deleted)$/.test(ev.type) gulp.src(['app/**/*'], {base: 'app'}) .pipe(transpile()) .on('error', (e) -> $.util.log(e.toString()) this.emit('end') ) .pipe($.injectAppFiles()) .pipe($.filter(isCompiled)) .pipe($.changed(process.env.DIST_DIR)) .pipe(gulp.dest(process.env.DIST_DIR)) .pipe($.livereload(tinylr)) .pipe($.size()) else if ev.type == 'changed' gulp.src(ev.path, {base: 'app'}) .pipe($.dumbSass()) .pipe(transpile()) .on('error', (e) -> $.util.log(e.toString()) this.emit('end') ) .pipe($.filter(isCompiled)) .pipe($.changed(process.env.DIST_DIR)) .pipe(gulp.dest(process.env.DIST_DIR)) .pipe($.livereload(tinylr)) .pipe($.size()) # clean, compile, optimize, sync with s3 gulp.task 'build-for-deploy', -> # start fresh del(process.env.DIST_DIR) initFilters() console.log 'config', config # set aws creds publisher = $.awspublish.create({ key: config.AWS_KEY secret: config.AWS_SECRET bucket: config.AWS_BUCKET }) gulp.src(['app/**/*'], {base: 'app'}) # transpile .pipe(transpile()) # inject app js + css .pipe($.injectAppFiles()) # optimize .pipe(optimize()) # output to dist .pipe($.if([isCompiled], gulp.dest(process.env.DIST_DIR))) .pipe($.size()) # push to s3 .pipe($.if([isCompiled], s3())) # Push to heroku gulp.task 'push', -> $.shell.task([ "heroku config:set NODE_ENV=#{process.env.NODE_ENV}" "git checkout -b #{process.env.TAG}" 'git add -u .' 'git add .' "git commit -am 'commit for #{process.env.TAG} push'" "git push -f #{process.env.NODE_ENV} #{process.env.TAG}:master" 'git checkout master' "git branch -D #{process.env.TAG}" "rm -rf #{process.env.DIST_DIR}" ])() gulp.task 'release', -> initEnv('production') seq('build-for-deploy', 'push') # Mocha unit tests gulp.task 'test:unit:once', -> gulp.src([ 'test/unit/common.coffee' 'test/unit/spec/**/*.coffee' ]) .pipe($.mocha({ reporter: 'nyan' ui: 'tdd' })) gulp.task 'test:unit:watch', ['test:unit:once'], -> gulp.watch('test/unit/**/*').on 'change', (ev) -> if /^(added|deleted|changed)$/.test(ev.type) gulp.src(['test/unit/common.coffee', ev.path]) .pipe($.mocha({ reporter: 'nyan' ui: 'tdd' })) # E2E Protractor tests gulp.task 'start-sauce-connect', (cb) -> pXor.e2e.startSauceConnect() gulp.task 'test:e2e:once', -> pXor.e2e.testE2E({ nodeHost: 'localhost' nodePort: 5555 mockFile: 'mocks/nock-mocks.json' specs: ['test/e2e/**/*.coffee'] }) gulp.task 'test:e2e:watch', ['test:e2e:once'], -> gulp.watch('test/e2e/**/*').on 'change', (ev) -> if /^(added|deleted|changed)$/.test(ev.type) testPath = ev.path.replace(process.cwd(), '') console.log '@-->ev path', testPath pXor.e2e.testE2E({ nodeHost: 'localhost' nodePort: 5555 mockFile: 'mocks/nock-mocks.json' specs: ['test/e2e/common.coffee', testPath] }) gulp.task 'test:e2e:record', ['init'], -> pXor.e2e.testE2E({ nodeApp: 'app.js' nodeHost: 'localhost' nodePort: 4444 record: true mockFile: 'mocks/nock-mocks.json' specs: ['test/e2e/**/*.coffee'] }) gulp.task 'test:e2e:playback', ['init'], -> pXor.e2e.testE2E({ nodeApp: 'app.js' nodeHost: 'localhost' nodePort: 4444 playback: true mockFile: 'mocks/nock-mocks.json' specs: ['test/e2e/**/*.coffee'] }) gulp.task 'test:e2e:ci', ['init'], -> browsers = [ browserName: 'chrome' , browserName: 'firefox' , browserName: 'safari' , browserName: 'internet explorer' version: 11 , browserName: 'internet explorer' version: 10 , browserName: 'internet explorer' version: 9 , browserName: 'internet explorer' version: 8 ].map (item) -> item['build'] = process.env.TRAVIS_BUILD_NUMBER item['tunnel-identifier'] = process.env.TRAVIS_JOB_NUMBER item pXor.e2e.testE2E({ nodeApp: 'app.js' nodeHost: 'localhost' nodePort: 4444 playback: true mockFile: 'mocks/nock-mocks.json' specs: ['test/e2e/**/*.coffee'] browsers: browsers })