Left file: appwork-v1_3_1/src/gulpfile.js  
Right file: appwork-v1_4_0/src/gulpfile.js  
const path = require('path') = const path = require('path')
     
// -------------------------------------------------------------------------------   // -------------------------------------------------------------------------------
// Config   // Config
     
const env = require('gulp-environment')   const env = require('gulp-environment')
     
process.env.NODE_ENV = env.current.name   process.env.NODE_ENV = env.current.name
     
const conf = (() => {   const conf = (() => {
  const _conf = require('./build-config')     const _conf = require('./build-config')
  return require('deepmerge').all([{}, _conf.base || {}, _conf[process.env.NODE_ENV] || {}])     return require('deepmerge').all([{}, _conf.base || {}, _conf[process.env.NODE_ENV] || {}])
})()   })()
     
conf.buildPath = path.resolve(__dirname, conf.buildPath).replace(/\\/g, '/')   conf.buildPath = path.resolve(__dirname, conf.buildPath).replace(/\\/g, '/')
     
// -------------------------------------------------------------------------------   // -------------------------------------------------------------------------------
// Modules   // Modules
     
const { src, dest, parallel, series, watch } = require('gulp')   const { src, dest, parallel, series, watch } = require('gulp')
const webpack = require('webpack')   const webpack = require('webpack')
const sass = require('gulp-sass')   const sass = require('gulp-sass')
const autoprefixer = require('gulp-autoprefixer')   const autoprefixer = require('gulp-autoprefixer')
const rename = require('gulp-rename')   const rename = require('gulp-rename')
const replace = require('gulp-replace')   const replace = require('gulp-replace')
const gulpIf = require('gulp-if')   const gulpIf = require('gulp-if')
const sourcemaps = require('gulp-sourcemaps')   const sourcemaps = require('gulp-sourcemaps')
const del = require('del')   const del = require('del')
const colors = require('ansi-colors')   const colors = require('ansi-colors')
const log = require('fancy-log')   const log = require('fancy-log')
     
colors.enabled = require('color-support').hasBasic   colors.enabled = require('color-support').hasBasic
     
// -------------------------------------------------------------------------------   // -------------------------------------------------------------------------------
// Utilities   // Utilities
     
function normalize(p) {   function normalize(p) {
  return p.replace(/\\/g, '/')     return p.replace(/\\/g, '/')
}   }
     
function root(p) {   function root(p) {
  return p.startsWith('!') ?     return p.startsWith('!') ?
    normalize(`!${path.join(__dirname, p.slice(1))}`) :       normalize(`!${path.join(__dirname, p.slice(1))}`) :
    normalize(path.join(__dirname, p))       normalize(path.join(__dirname, p))
}   }
     
function getSrc(...src) {   function getSrc(...src) {
  return src.map(p => root(p)).concat(conf.exclude.map(d => `!${root(d)}/**/*`))     return src.map(p => root(p)).concat(conf.exclude.map(d => `!${root(d)}/**/*`))
}   }
     
// -------------------------------------------------------------------------------   // -------------------------------------------------------------------------------
// Clean build directory   // Clean build directory
     
const cleanTask = function () {   const cleanTask = function () {
  return del([conf.buildPath], {     return del([conf.buildPath], {
    force: true       force: true
  })     })
}   }
     
// -------------------------------------------------------------------------------   // -------------------------------------------------------------------------------
// Build css   // Build css
     
const buildCssTask = function () {   const buildCssTask = function () {
  return src(getSrc('**/*.scss', '!**/_*.scss'), { base: root('.') })     return src(getSrc('**/*.scss', '!**/_*.scss'), { base: root('.') })
     
    .pipe(gulpIf(conf.sourcemaps, sourcemaps.init()))       .pipe(gulpIf(conf.sourcemaps, sourcemaps.init()))
    .pipe(sass({       .pipe(sass({
      outputStyle: conf.minify ? 'compressed' : 'nested'         outputStyle: conf.minify ? 'compressed' : 'nested'
    }).on('error', sass.logError))       }).on('error', sass.logError))
    .pipe(gulpIf(conf.sourcemaps, sourcemaps.write()))       .pipe(gulpIf(conf.sourcemaps, sourcemaps.write()))
     
    .pipe(gulpIf(conf.sourcemaps, sourcemaps.init({       .pipe(gulpIf(conf.sourcemaps, sourcemaps.init({
      loadMaps: true         loadMaps: true
    })))       })))
    .pipe(autoprefixer({       .pipe(autoprefixer({
      browsers: [ <>       overrideBrowserslist: [
        '>= 1%', =         '>= 1%',
        'last 2 versions',           'last 2 versions',
        'not dead',           'not dead',
        'Chrome >= 45',           'Chrome >= 45',
        'Firefox >= 38',           'Firefox >= 38',
        'Edge >= 12',           'Edge >= 12',
        'Explorer >= 10',           'Explorer >= 10',
        'iOS >= 9',           'iOS >= 9',
        'Safari >= 9',           'Safari >= 9',
        'Android >= 4.4',           'Android >= 4.4',
        'Opera >= 30'           'Opera >= 30'
      ]         ]
    }))       }))
    .pipe(gulpIf(conf.sourcemaps, sourcemaps.write()))       .pipe(gulpIf(conf.sourcemaps, sourcemaps.write()))
     
    .pipe(dest(conf.buildPath))       .pipe(dest(conf.buildPath))
}   }
     
// -------------------------------------------------------------------------------   // -------------------------------------------------------------------------------
// Build js   // Build js
     
const buildJsTask = function (cb) {   const buildJsTask = function (cb) {
  setTimeout(function () {     setTimeout(function () {
    webpack(require('./webpack.config'), (err, stats) => {       webpack(require('./webpack.config'), (err, stats) => {
      if (err) {         if (err) {
        log(colors.gray('Webpack error:'), colors.red(err.stack || err))           log(colors.gray('Webpack error:'), colors.red(err.stack || err))
        if (err.details) log(colors.gray('Webpack error details:'), err.details)           if (err.details) log(colors.gray('Webpack error details:'), err.details)
        return cb()           return cb()
      }         }
     
      const info = stats.toJson()         const info = stats.toJson()
     
      if (stats.hasErrors()) {         if (stats.hasErrors()) {
        info.errors.forEach(e => log(colors.gray('Webpack compilation error:'), colors.red(e)))           info.errors.forEach(e => log(colors.gray('Webpack compilation error:'), colors.red(e)))
      }         }
     
      if (stats.hasWarnings()) {         if (stats.hasWarnings()) {
        info.warnings.forEach(w => log(colors.gray('Webpack compilation warning:'), colors.yellow(w)))           info.warnings.forEach(w => log(colors.gray('Webpack compilation warning:'), colors.yellow(w)))
      }         }
     
      // Print log         // Print log
      log(stats.toString({         log(stats.toString({
        colors: colors.enabled,           colors: colors.enabled,
        hash: false,           hash: false,
        timings: false,           timings: false,
        chunks: false,           chunks: false,
        chunkModules: false,           chunkModules: false,
        modules: false,           modules: false,
        children: true,           children: true,
        version: true,           version: true,
        cached: false,           cached: false,
        cachedAssets: false,           cachedAssets: false,
        reasons: false,           reasons: false,
        source: false,           source: false,
        errorDetails: false           errorDetails: false
      }))         }))
     
      cb()         cb()
    })       })
  }, 1)     }, 1)
}   }
     
// -------------------------------------------------------------------------------   // -------------------------------------------------------------------------------
// Build fonts   // Build fonts
     
const FONT_TASKS = [{   const FONT_TASKS = [{
    name: 'fontawesome',       name: 'fontawesome',
    path: 'node_modules/@fortawesome/fontawesome-free/webfonts/*'       path: 'node_modules/@fortawesome/fontawesome-free/webfonts/*'
  },     },
  {     {
    name: 'linearicons',       name: 'linearicons',
    path: 'node_modules/linearicons/dist/web-font/fonts/*'       path: 'node_modules/linearicons/dist/web-font/fonts/*'
  },     },
  {     {
    name: 'pe-icon-7-stroke',       name: 'pe-icon-7-stroke',
    path: 'node_modules/pixeden-stroke-7-icon/pe-icon-7-stroke/fonts/*'       path: 'node_modules/pixeden-stroke-7-icon/pe-icon-7-stroke/fonts/*'
  },     },
  {     {
    name: 'open-iconic',       name: 'open-iconic',
    path: 'node_modules/open-iconic/font/fonts/*'       path: 'node_modules/open-iconic/font/fonts/*'
  },     },
  {     {
    name: 'ionicons',       name: 'ionicons',
    path: 'node_modules/ionicons/dist/fonts/*'       path: 'node_modules/ionicons/dist/fonts/*'
  }     }
].reduce(function (tasks, font) {   ].reduce(function (tasks, font) {
  const functionName = `buildFonts${font.name.replace(/^./, m => m.toUpperCase())}Task`     const functionName = `buildFonts${font.name.replace(/^./, m => m.toUpperCase())}Task`
  const taskFunction = function () {     const taskFunction = function () {
    return src(root(font.path))       return src(root(font.path))
      .pipe(dest(normalize(path.join(conf.buildPath, 'fonts', font.name))))         .pipe(dest(normalize(path.join(conf.buildPath, 'fonts', font.name))))
  }     }
     
  Object.defineProperty(taskFunction, 'name', {     Object.defineProperty(taskFunction, 'name', {
    value: functionName       value: functionName
  });     });
     
  return tasks.concat([taskFunction])     return tasks.concat([taskFunction])
}, [])   }, [])
     
// Copy linearicons' style.css   // Copy linearicons' style.css
FONT_TASKS.push(function buildFontsLinearicons () {   FONT_TASKS.push(function buildFontsLinearicons () {
  return src(root('node_modules/linearicons/dist/web-font/style.css'))     return src(root('node_modules/linearicons/dist/web-font/style.css'))
    .pipe(replace(/'fonts\//g, '\'linearicons/'))       .pipe(replace(/'fonts\//g, '\'linearicons/'))
    .pipe(rename({       .pipe(rename({
      basename: 'linearicons'         basename: 'linearicons'
    }))       }))
    .pipe(dest(normalize(path.join(conf.buildPath, 'fonts'))))       .pipe(dest(normalize(path.join(conf.buildPath, 'fonts'))))
})   })
     
const buildFontsTask = parallel(FONT_TASKS)   const buildFontsTask = parallel(FONT_TASKS)
     
// -------------------------------------------------------------------------------   // -------------------------------------------------------------------------------
// Copy   // Copy
     
const buildCopyTask = function () {   const buildCopyTask = function () {
  return src(getSrc('**/*.png', '**/*.gif', '**/*.jpg', '**/*.jpeg', '**/*.svg', '**/*.swf', '**/*.eot', '**/*.ttf', '**/*.woff', '**/*.woff2'), {     return src(getSrc('**/*.png', '**/*.gif', '**/*.jpg', '**/*.jpeg', '**/*.svg', '**/*.swf', '**/*.eot', '**/*.ttf', '**/*.woff', '**/*.woff2'), {
    base: root('.')       base: root('.')
  })     })
  .pipe(dest(conf.buildPath))     .pipe(dest(conf.buildPath))
}   }
     
// -------------------------------------------------------------------------------   // -------------------------------------------------------------------------------
// Watch   // Watch
     
const watchTask = function () {   const watchTask = function () {
  watch(getSrc('**/*.scss', '!fonts/**/*.scss'), buildCssTask)     watch(getSrc('**/*.scss', '!fonts/**/*.scss'), buildCssTask)
  watch(getSrc('fonts/**/*.scss'), parallel(buildCssTask, buildFontsTask))     watch(getSrc('fonts/**/*.scss'), parallel(buildCssTask, buildFontsTask))
  watch(getSrc('**/*.@(js|es6)', '!*.js'), buildJsTask)     watch(getSrc('**/*.@(js|es6)', '!*.js'), buildJsTask)
  watch(getSrc('**/*.png', '**/*.gif', '**/*.jpg', '**/*.jpeg', '**/*.svg', '**/*.swf'), buildCopyTask)     watch(getSrc('**/*.png', '**/*.gif', '**/*.jpg', '**/*.jpeg', '**/*.svg', '**/*.swf'), buildCopyTask)
}   }
     
// -------------------------------------------------------------------------------   // -------------------------------------------------------------------------------
// Build   // Build
     
const buildTasks = [   const buildTasks = [
  buildCssTask,     buildCssTask,
  buildJsTask,     buildJsTask,
  buildFontsTask,     buildFontsTask,
  buildCopyTask     buildCopyTask
]   ]
     
const buildTask = conf.cleanBuild ?   const buildTask = conf.cleanBuild ?
  series(cleanTask, parallel(buildTasks)) :     series(cleanTask, parallel(buildTasks)) :
  parallel(buildTasks)     parallel(buildTasks)
     
// -------------------------------------------------------------------------------   // -------------------------------------------------------------------------------
// Exports   // Exports
     
module.exports = {   module.exports = {
  default: buildTask,     default: buildTask,
  build: buildTask,     build: buildTask,
  'build:js': buildJsTask,     'build:js': buildJsTask,
  'build:css': buildCssTask,     'build:css': buildCssTask,
  'build:fonts': buildFontsTask,     'build:fonts': buildFontsTask,
  'build:copy': buildCopyTask,     'build:copy': buildCopyTask,
  watch: watchTask     watch: watchTask
}   }