/* * Copyright (c) 2016 Martin Donath * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ /* ---------------------------------------------------------------------------- * Imports * ------------------------------------------------------------------------- */ var gulp = require('gulp'); var addsrc = require('gulp-add-src'); var args = require('yargs').argv; var autoprefix = require('autoprefixer'); var changed = require('gulp-changed'); var child = require('child_process'); var clean = require('del'); var compact = require('gulp-remove-empty-lines'); var concat = require('gulp-concat'); var ignore = require('gulp-ignore'); var gulpif = require('gulp-if'); var mincss = require('gulp-cssnano'); var minhtml = require('gulp-htmlmin'); var minsvg = require('gulp-svgmin'); var modernizr = require('gulp-modernizr'); var mqpacker = require('css-mqpacker'); var notifier = require('node-notifier'); var path = require('path'); var plumber = require('gulp-plumber'); var postcss = require('gulp-postcss'); var replace = require('gulp-replace'); var rev = require('gulp-rev'); var sass = require('gulp-sass'); var sasslint = require('gulp-sass-lint'); var sourcemaps = require('gulp-sourcemaps'); var stream = require('webpack-stream'); var uglify = require('gulp-uglify'); var util = require('gulp-util'); var vinyl = require('vinyl-paths'); var version = require('gulp-rev-replace'); var webpack = require('webpack'); /* ---------------------------------------------------------------------------- * Locals * ------------------------------------------------------------------------- */ /* MkDocs server */ var server = null; /* Watching context */ var watch = false; /* ---------------------------------------------------------------------------- * Overrides * ------------------------------------------------------------------------- */ /* * Override gulp.src() for nicer error handling. */ var src = gulp.src; gulp.src = function() { return src.apply(gulp, arguments) .pipe( plumber(function(error) { util.log(util.colors.red( 'Error (' + error.plugin + '): ' + error.message )); /* Extract file where error happened, if existent */ var file = error.relativePath ? error.relativePath.split('/').pop() : ''; /* Dispatch system-level notification */ notifier.notify({ title: 'Error (' + error.plugin + '): ' + file, message: error.messageOriginal }); this.emit('end'); })); }; /* ---------------------------------------------------------------------------- * Asset pipeline * ------------------------------------------------------------------------- */ /* * Clean stylesheets generated by build. */ gulp.task('assets:clean:stylesheets', function() { return gulp.src('material/assets/stylesheets/*') .pipe(vinyl(clean)); }); /* * Clean javascripts generated by build. */ gulp.task('assets:clean:javascripts', function() { return gulp.src('material/assets/javascripts/*') .pipe(vinyl(clean)); }); /* * Clean images generated by build. */ gulp.task('assets:clean:images', function() { return gulp.src('material/assets/images/*') .pipe(vinyl(clean)); }); /* * Clean files generated by build. */ gulp.task('assets:clean', [ 'assets:clean:stylesheets', 'assets:clean:javascripts', 'assets:clean:images' ]); /* * Build stylesheets from SASS source. */ gulp.task('assets:build:stylesheets', args.production ? [ 'assets:clean:stylesheets', 'assets:build:images', ] : [], function() { return gulp.src('src/assets/stylesheets/*.scss') .pipe(gulpif(args.sourcemaps, sourcemaps.init())) .pipe( sass({ includePaths: [ 'node_modules/modularscale-sass/stylesheets', 'node_modules/material-design-color', 'node_modules/material-shadows' ] })) .pipe( postcss([ autoprefix(), mqpacker ])) .pipe(gulpif(args.sourcemaps, sourcemaps.write())) .pipe(gulpif(args.production, mincss())) .pipe(gulpif(args.production, rev())) .pipe(gulpif(args.production, version({ manifest: gulp.src('manifest.json') }))) .pipe(gulp.dest('material/assets/stylesheets')) .pipe(gulpif(args.production, rev.manifest('manifest.json', { base: 'material/assets', merge: true }))) .pipe(gulpif(args.production, gulp.dest('material/assets'))); }); /* * Build javascripts by transpiling ES6 with babel. */ gulp.task('assets:build:javascripts', args.production ? [ 'assets:clean:javascripts' ] : [], function() { return gulp.src('src/assets/javascripts/**/*.js') .pipe( stream({ entry: 'application.js', output: { filename: 'application.js' }, module: { loaders: [{ loader: 'babel-loader', test: path.join(__dirname, 'src/assets/javascripts'), query: { presets: 'es2015' } }] }, plugins: [ new webpack.NoErrorsPlugin(), ].concat( args.production ? [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ] : []), stats: { colors: true }, resolve: { modulesDirectories: [ 'src/assets/javascripts', 'node_modules' ], extensions: [ '', '.js' ] }, devtool: args.sourcemaps ? 'source-map' : '' })) .pipe(gulpif(args.production, rev())) .pipe(gulp.dest('material/assets/javascripts')) .pipe(gulpif(args.production, rev.manifest('manifest.json', { base: 'material/assets', merge: true }))) .pipe(gulpif(args.production, gulp.dest('material/assets'))); }); /* * Create a customized modernizr build. */ gulp.task('assets:build:modernizr', [ 'assets:build:stylesheets', 'assets:build:javascripts' ], function() { return gulp.src([ 'material/assets/stylesheets/*.css', 'material/assets/javascripts/*.js' ]).pipe( modernizr({ options: [ 'addTest', /* Add custom tests */ 'fnBind', /* Use function.bind */ 'html5printshiv', /* HTML5 support for IE */ 'setClasses', /* Add CSS classes to root tag */ 'testProp' /* Test for properties */ ] })) .pipe(concat('modernizr.js')) .pipe(gulpif(args.production, uglify())) .pipe(gulpif(args.production, rev())) .pipe(gulp.dest('material/assets/javascripts')) .pipe(gulpif(args.production, rev.manifest('manifest.json', { base: 'material/assets', merge: true }))) .pipe(gulpif(args.production, gulp.dest('material/assets'))); }); /* * Copy and minify vector graphics. */ gulp.task('assets:build:images:svg', function() { return gulp.src('src/assets/images/**/*.svg') .pipe(gulpif(watch, changed('material/assets/images'))) .pipe(gulpif(args.production, minsvg())) .pipe(gulpif(args.production, rev())) .pipe(gulp.dest('material/assets/images')) .pipe(gulpif(args.production, rev.manifest('manifest.json', { base: 'material/assets', merge: true }))) .pipe(gulpif(args.production, gulp.dest('material/assets'))); }); /* * Copy favicon. */ gulp.task('assets:build:images:ico', function() { return gulp.src('src/assets/images/**/*.ico') .pipe(gulp.dest('material/assets/images')) }); /* * Copy images. */ gulp.task('assets:build:images', [ 'assets:clean:images' ], function() { return gulp.start([ 'assets:build:images:svg', 'assets:build:images:ico' ]); }); /* * Minify views. */ gulp.task('assets:build:views', args.production ? [ 'assets:build:stylesheets', 'assets:build:modernizr', 'assets:build:images' ] : [], function() { var metadata = require('./package.json'); return gulp.src('src/**/*.html') .pipe(gulpif(watch, changed('material'))) .pipe( minhtml({ collapseBooleanAttributes: true, removeComments: true, removeScriptTypeAttributes: true, removeStyleLinkTypeAttributes: true, customAttrCollapse: /(content)/ })) .pipe(replace('$theme-name$', metadata.name)) .pipe(replace('$theme-version$', metadata.version)) .pipe(compact()) .pipe(gulpif(args.production, version({ manifest: gulp.src('manifest.json') }))) .pipe(gulp.dest('material')); }); /* * Build assets. */ gulp.task('assets:build', [ 'assets:build:stylesheets', 'assets:build:javascripts', 'assets:build:modernizr', 'assets:build:images', 'assets:build:views' ]); /* * Watch assets for changes and rebuild on the fly. */ gulp.task('assets:watch', function() { watch = true; /* Rebuild stylesheets */ gulp.watch([ 'src/assets/stylesheets/**/*.scss' ], ['assets:build:stylesheets']); /* Rebuild javascripts */ gulp.watch([ 'src/assets/javascripts/**/*.js' ], ['assets:build:javascripts']); /* Copy images */ gulp.watch([ 'src/assets/images/**/*' ], ['assets:build:images']); /* Minify views */ gulp.watch([ 'src/**/*.html' ], ['assets:build:views']); }); /* ---------------------------------------------------------------------------- * Application server * ------------------------------------------------------------------------- */ /* * Build documentation. */ gulp.task('mkdocs:build', [ 'assets:build' ], function() { return child.spawnSync('mkdocs', ['build']); }); /* * Restart MkDocs server. */ gulp.task('mkdocs:serve', function() { if (server) server.kill(); /* Spawn MkDocs server */ server = child.spawn('mkdocs', ['serve', '-a', '0.0.0.0:8000']); /* Pretty print server log output */ server.stdout.on('data', function(data) { var lines = data.toString().split('\n') for (var l in lines) if (lines[l].length) util.log(lines[l]); }); /* Print errors to stdout */ server.stderr.on('data', function(data) { process.stdout.write(data.toString()); }); }); /* ---------------------------------------------------------------------------- * Interface * ------------------------------------------------------------------------- */ /* * Build assets and documentation. */ gulp.task('build', [ 'assets:clean', 'assets:build' ].concat(args.mkdocs ? 'mkdocs:build' : [])); /* * Start asset and MkDocs watchdogs. */ gulp.task('watch', [ 'assets:clean', 'assets:build' ], function() { return gulp.start([ 'assets:watch' ].concat(args.mkdocs ? 'mkdocs:serve' : [])); }); /* * Build assets by default. */ gulp.task('default', ['build']);