/* * Copyright (c) 2016-2017 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. */ import gulp from "gulp" import notifier from "node-notifier" import plumber from "gulp-plumber" import util from "gulp-util" import yargs from "yargs" /* ---------------------------------------------------------------------------- * Configuration and arguments * ------------------------------------------------------------------------- */ const config = { assets: { src: "src/assets", /* Source directory for assets */ build: "material/assets" /* Target directory for assets */ }, lib: "lib", /* Libraries and tasks */ tests: { visual: "tests/visual" /* Base directory for visual tests */ }, views: { src: "src", /* Source directory for views */ build: "material" /* Target directory for views */ } } let args = yargs .default("clean", false) /* Clean before build */ .default("karma", true) /* Karma watchdog */ .default("lint", true) /* Lint sources */ .default("mkdocs", true) /* MkDocs watchdog */ .default("optimize", false) /* Optimize sources */ .default("revision", false) /* Revision assets */ .default("sourcemaps", false) /* Create sourcemaps */ .argv /* Only use the last seen value if boolean, so overrides are possible */ args = Object.keys(args).reduce((result, arg) => { result[arg] = Array.isArray(args[arg]) && typeof args[arg][0] === "boolean" ? [].concat(args[arg]).pop() : args[arg] return result }, {}) /* ---------------------------------------------------------------------------- * Overrides and helpers * ------------------------------------------------------------------------- */ /* * Override gulp.src() for nicer error handling. */ const src = gulp.src gulp.src = (...glob) => { return src.apply(gulp, glob) .pipe( plumber(function(error) { util.log(util.colors.red( `Error (${error.plugin}): ${error.message}` )) /* Extract file where error happened, if existent */ const file = error.relativePath ? error.relativePath.split("/").pop() : "" /* Dispatch system-level notification */ notifier.notify({ title: `Error (${error.plugin}): ${file}`, message: error.messageOriginal }) // eslint-disable-next-line no-invalid-this this.emit("end") /* Throw error and abort, if not in watch mode */ if (args._[0] !== "watch") throw error })) } /* * Helper function to load a task * * This function returns a callback that will require the task with the given * name and execute the function that is returned by this task. It omits the * need to load all tasks upfront, speeding up the build a gazillion times. */ const load = task => { return done => { return require(`./${config.lib}/tasks/${task}`) .call(gulp, gulp, config, args)(done) } } /* ---------------------------------------------------------------------------- * Images * ------------------------------------------------------------------------- */ /* * Copy favicon */ gulp.task("assets:images:build:ico", [ args.clean ? "assets:images:clean" : false ].filter(t => t), load("assets/images/build/ico")) /* * Copy and minify vector graphics */ gulp.task("assets:images:build:svg", [ args.clean ? "assets:images:clean" : false ].filter(t => t), load("assets/images/build/svg")) /* * Copy images */ gulp.task("assets:images:build", [ "assets:images:build:ico", "assets:images:build:svg" ]) /* * Clean images generated by build */ gulp.task("assets:images:clean", load("assets/images/clean")) /* ---------------------------------------------------------------------------- * JavaScript * ------------------------------------------------------------------------- */ /* * Build application logic * * When revisioning assets, the build must be serialized due to possible race * conditions when two tasks try to write manifest.json simultaneously */ gulp.task("assets:javascripts:build:application", [ args.clean ? "assets:javascripts:clean" : false, args.lint ? "assets:javascripts:lint" : false, args.revision ? "assets:stylesheets:build" : false ].filter(t => t), load("assets/javascripts/build/application")) /* * Build custom modernizr * * When revisioning assets, the build must be serialized due to possible race * conditions when two tasks try to write manifest.json simultaneously */ gulp.task("assets:javascripts:build:modernizr", [ "assets:stylesheets:build", args.clean ? "assets:javascripts:clean" : false, args.lint ? "assets:javascripts:lint" : false, args.revision ? "assets:javascripts:build:application" : false ].filter(t => t), load("assets/javascripts/build/modernizr")) /* * Build application logic and Modernizr */ gulp.task("assets:javascripts:build", [ "assets:javascripts:build:application", "assets:javascripts:build:modernizr" ]) /* * Clean JavaScript generated by build */ gulp.task("assets:javascripts:clean", load("assets/javascripts/clean")) /* * Annotate JavaScript */ gulp.task("assets:javascripts:annotate", load("assets/javascripts/annotate")) /* * Lint JavaScript */ gulp.task("assets:javascripts:lint", load("assets/javascripts/lint")) /* ---------------------------------------------------------------------------- * Stylesheets * ------------------------------------------------------------------------- */ /* * Build stylesheets from SASS source */ gulp.task("assets:stylesheets:build", [ args.clean ? "assets:stylesheets:clean" : false, args.lint ? "assets:stylesheets:lint" : false ].filter(t => t), load("assets/stylesheets/build")) /* * Clean stylesheets generated by build */ gulp.task("assets:stylesheets:clean", load("assets/stylesheets/clean")) /* * Lint SASS sources */ gulp.task("assets:stylesheets:lint", load("assets/stylesheets/lint")) /* ---------------------------------------------------------------------------- * Assets * ------------------------------------------------------------------------- */ /* * Build assets */ gulp.task("assets:build", [ "assets:images:build", "assets:javascripts:build", "assets:stylesheets:build" ]) /* * Clean files generated by build */ gulp.task("assets:clean", [ "assets:images:clean", "assets:javascripts:clean", "assets:stylesheets:clean" ]) /* ---------------------------------------------------------------------------- * Views * ------------------------------------------------------------------------- */ /* * Minify views */ gulp.task("views:build", [ args.clean ? "views:clean" : false, args.revision ? "assets:images:build" : false, args.revision ? "assets:stylesheets:build" : false, args.revision ? "assets:javascripts:build" : false ].filter(t => t), load("views/build")) /* * Clean views */ gulp.task("views:clean", load("views/clean")) /* ---------------------------------------------------------------------------- * MkDocs * ------------------------------------------------------------------------- */ /* * Build documentation */ gulp.task("mkdocs:build", [ "assets:build", "views:build", "mkdocs:clean" ], load("mkdocs/build")) /* * Clean documentation build */ gulp.task("mkdocs:clean", load("mkdocs/clean")) /* * Restart MkDocs server */ gulp.task("mkdocs:serve", load("mkdocs/serve")) /* ---------------------------------------------------------------------------- * Visual tests * ------------------------------------------------------------------------- */ /* * Generate visual tests */ gulp.task("tests:visual:generate", [ args.clean ? "tests:visual:clean" : false, args.clean ? "assets:build" : false, args.clean ? "views:build" : false ].filter(t => t), load("tests/visual/generate")) /* * Run visual tests */ gulp.task("tests:visual:run", [ "tests:visual:generate" ], load("tests/visual/run")) /* * Update reference images for visual tests */ gulp.task("tests:visual:update", load("tests/visual/update")) /* * Clean files generated by visual tests */ gulp.task("tests:visual:clean", load("tests/visual/clean")) /* * Open a SauceConnect session for manual testing */ gulp.task("tests:visual:session", [ "tests:visual:generate" ], load("tests/visual/session")) /* ---------------------------------------------------------------------------- * Interface * ------------------------------------------------------------------------- */ /* * Build assets and documentation */ gulp.task("build", [ "assets:build", "views:build", args.mkdocs ? "mkdocs:build" : false ].filter(f => f)) /* * Clean assets and documentation */ gulp.task("clean", [ "assets:clean", "views:clean", "mkdocs:clean" ]) /* * Watch for changes and rebuild assets on the fly */ gulp.task("watch", [ "assets:build", "views:build" ], () => { process.env.WATCH = true /* Start MkDocs server */ if (args.mkdocs) gulp.start("mkdocs:serve") /* Rebuild stylesheets */ gulp.watch([ `${config.assets.src}/stylesheets/**/*.scss` ], ["assets:stylesheets:build"]) /* Rebuild JavaScript */ gulp.watch([ `${config.assets.src}/javascripts/**/*.{js,jsx}` ], ["assets:javascripts:build:application"]) /* Copy images */ gulp.watch([ `${config.assets.src}/images/**/*` ], ["assets:images:build"]) /* Minify views */ gulp.watch([ `${config.views.src}/**/*.html` ], ["views:build"]) }) /* * Build assets by default */ gulp.task("default", ["build"])