Caching image optimization tasks in gulp

I am trying to write a gulpfile.js that will follow modern optimization best practices and one of them is using an element picture

. So I optimize, resize and add webp

images, but all these processing tasks take quite a long time, so I want to cache them.

'use strict';

var gulp            = require('gulp'),
    plumber         = require('gulp-plumber'),
    gutil           = require('gulp-util'),
    notify          = require('gulp-notify'),
    size            = require('gulp-size'),
    rename          = require('gulp-rename'),
    sass            = require('gulp-sass'),
    autoprefixer    = require('gulp-autoprefixer'),
    cmq             = require('gulp-combine-media-queries'),
    minifyCSS       = require('gulp-minify-css'),
    jshint          = require('gulp-jshint'),
    concat          = require('gulp-concat'),
    uglify          = require('gulp-uglify'),
    psi             = require('psi'),
    ngrok           = require('ngrok'),
    cp              = require('child_process'),
    browserSync     = require('browser-sync'),
    imageMin        = require('gulp-imagemin'),
    cwebp           = require('gulp-cwebp'),
    imageResize     = require('gulp-image-resize'),
    cache           = require('gulp-cache'),
    cached          = require('gulp-cached'),
    changed         = require('gulp-changed'),
    newer           = require('gulp-newer'),
    parallel        = require('concurrent-transform'),
    os              = require('os-utils'),
    minifyHTML      = require('gulp-minify-html'),
    clean           = require('gulp-clean'),
    url             = 'http://1ec934f4.ngrok.com/',
    reload          = browserSync.reload;

var onError         = function(err) {
    gutil.beep();
    gutil.log(gutil.colors.green(err + '\n'));
};

var messages = {
    jekyllBuild: '<span style="color: grey">Running:</span> $ jekyll build'
};

/*==========  Paths  ==========*/

var paths = {
    styles: {
        src:            'assets/sass/main.scss',
        dest:           'build/css',
        destProd:       'html/build/css',
        watch:          'assets/sass/**/*.scss',
        style:          'build/css/main.css',
        styleProd:      'html/build/css/main.css',
        styleMin:       'build/css/main.min.css',
        styleMinProd:   'html/build/css/main.min.css'
    },
    scripts: {
        src:            'assets/js/**/*.js',
        dest:           'build/js',
        destProd:       'html/build/js',
        destVen:        'assets/js/vendor',
        script:         'build/js/main.js',
        scriptProd:     'html/build/js/main.js',
        scriptMin:      'build/js/main.min.js',
        scriptMinProd:  'html/build/js/main.min.js',
        bundleMain:     'build/js/main.bundle.js',
        bundleMainMin:  'build/js/main.bundle.min.js',
        watch:          ['assets/js/**/*.js', '!/assets/js/vendor/**/*.js']
    },
    jshint: {
        src: [
                        'assets/js/**/*.js',
                        '!assets/js/vendor/**/*.js'
        ]
    },
    bundles: {
        main: [
                        'assets/js/main.js',
                        'assets/js/vendor/**/*.js',
                        '!assets/js/vendor/bootstrap-sprockets.js',
                        '!assets/js/vendor/bootstrap.js',
        ]
    },
    images: {
        src:            'assets/img/**/*.{jpg, png, svg, gif, webp}',
        dest:           'build/img',
        destOpt:        'build/img/opt',
        destProd:       'html/build/img',
        watch:          'assets/img/**/*.{jpg, png, svg, gif, webp}',
        watchOpt:       'build/img/opt/*.{jpg, png, svg, gif, webp}',
        watchDest:      'build/img/*.{jpg, png, svg, gif, webp}',
        watchProd:      'html/build/img/**/*.{jpg, png, svg, gif, webp}'
    },
    html: {
        dest:           'html',
        watch:          ['index.html', '_layouts/*.html', '_includes/**/*', '_posts/**/*'],
        watchProd:      'html/**/*.html'
    },
    copy: {
        styles:         'bower_components/bootstrap-sass-official/assets/stylesheets/**/*.scss',
        scripts:        'bower_components/bootstrap-sass-official/assets/javascripts/**/*.js'
    },
    clean: {
        img:            'build/img',
        imgProd:        'html/build/img',
        styles:         'build/css',
        stylesProd:     'html/build/css',
        scripts:        'build/js',
        scriptsProd:    'html/build/js',
        build:          'build',
        buildProd:      'html/build',
        prod:           'html'
    }
};



/*==================================
=            Gulp Tasks            =
==================================*/



gulp.task('browser-sync', function() {
    browserSync({server: {baseDir: paths.html.dest}});
});

gulp.task('sass', function () {
    return gulp.src(paths.styles.watch)
        .pipe(plumber({errorHandler: onError}))
        .pipe(sass({outputStyles: 'nested'}))
        .pipe(autoprefixer(['last 15 versions', '> 1%', 'ie 8', 'ie 7'], {cascade: true}))
        .pipe(gulp.dest(paths.styles.dest))
        .pipe(gulp.dest(paths.styles.destProd))
        .pipe(size({showFiles: true}))
        .pipe(notify('sass is done.\n'));
});

gulp.task('sass-min', ['sass'], function () {
    return gulp.src(paths.styles.style)
        .pipe(plumber({errorHandler: onError}))
        .pipe(cmq({log: true}))
        .pipe(minifyCSS())
        // .pipe(zopfli())
        // .pipe(zip('main.css.zip'))
        .pipe(rename({suffix: '.min'}))
        .pipe(gulp.dest(paths.styles.dest))
        .pipe(gulp.dest(paths.styles.destProd))
        .pipe(size({showFiles: true}))
        .pipe(notify('Sass-min is done.\n'));
});

gulp.task('sass-reload', ['sass-min'], function () {
    return gulp.src(paths.styles.styleMin)
        .pipe(reload({stream: true}));
});

gulp.task('jshint-gulp', function () {
    return gulp.src('gulpfile.js')
        .pipe(cache(jshint('.jshintrc')))
        .pipe(jshint.reporter('jshint-stylish'))
        .pipe(notify('jshint-gulp is done.\n'));
});

gulp.task('jshint', ['jshint-gulp'], function () {
    return gulp.src(paths.scripts.script)
        .pipe(cache(jshint('.jshintrc')))
        .pipe(jshint.reporter('jshint-stylish'))
        .pipe(notify('jshint-gulp is done.\n'));
});

gulp.task('concat', ['jshint'], function () {
    return gulp.src(paths.bundles.main)
        .pipe(concat('main.bundle.js'))
        .pipe(gulp.dest(paths.scripts.dest))
        .pipe(gulp.dest(paths.scripts.destProd))
        .pipe(size({showFiles: true}));
});

gulp.task('js', ['concat'], function () {
    return gulp.src(paths.scripts.bundleMain)
        .pipe(uglify())
        .pipe(rename({suffix: '.min'}))
        .pipe(gulp.dest(paths.scripts.dest))
        .pipe(gulp.dest(paths.scripts.destProd))
        .pipe(notify('js is done.\n'));
});

gulp.task('js-reload', ['js'], function () {
    return gulp.src(paths.scripts.bundleMainMin)
        .pipe(plumber({errorHandler: onError}))
        .pipe(reload({stream:true}));
});

gulp.task('image-min', function () {
    return gulp.src(paths.images.src)
        .pipe(plumber({errorHandler: onError}))
        .pipe(cached(imageMin({optimizationLevel: 3, progressive: true, interlaced: true})))
        .pipe(gulp.dest(paths.images.destOpt))
        .pipe(size({showFiles: true}))
        .pipe(notify('image-min is done.\n'));
});

gulp.task('image-resize-sm', ['image-min'], function () {
    return  gulp.src(paths.images.watchOpt)
        .pipe(plumber({errorHandler: onError}))
        .pipe(changed(paths.images.dest))
        .pipe(parallel(imageResize({
            width   : 400,
            height  : 300,
            crop    : true,
            upscale : false
        }), os.cpuUsage(function(v) { console.log( 'CPU Usage (%): ' + v ); })))
        .pipe(rename({suffix: '-sm'}))
        .pipe(gulp.dest(paths.images.dest))
        .pipe(size({showFiles: true}))
        .pipe(gulp.dest(paths.images.destProd));
    });

gulp.task('image-resize-md', ['image-resize-sm'], function () {
    return  gulp.src(paths.images.watchOpt)
        .pipe(plumber({errorHandler: onError}))
        .pipe(changed(paths.images.dest))
        .pipe(parallel(imageResize({
            width : 800,
            height : 600,
            crop : true,
            upscale : false
        }), os.cpuUsage(function(v) { console.log( 'CPU Usage (%): ' + v ); })))
        .pipe(rename({suffix: '-md'}))
        .pipe(gulp.dest(paths.images.dest))
        .pipe(size({showFiles: true}))
        .pipe(gulp.dest(paths.images.destProd));
});

gulp.task('image-resize-lg', ['image-resize-md'], function () {
    return  gulp.src(paths.images.watchOpt)
        .pipe(plumber({errorHandler: onError}))
        .pipe(changed(paths.images.dest))
        .pipe(parallel(imageResize({
            width : 1200,
            height : 900,
            crop : true,
            upscale : false
        }), os.cpuUsage(function(v) { console.log( 'CPU Usage (%): ' + v ); })))
        .pipe(rename({suffix: '-lg'}))
        .pipe(size({showFiles: true}))
        .pipe(gulp.dest(paths.images.dest))
        .pipe(gulp.dest(paths.images.destProd));
});

gulp.task('cwebp', ['image-resize-lg'], function () {
    return gulp.src(paths.images.watchProd)
        .pipe(plumber({errorHandler: onError}))
        // .pipe(changed(paths.images.watchDest))
        // .pipe(cwebp())
        .pipe(changed(paths.images.watchDest))
        .pipe(parallel(cwebp()), os.cpuUsage(function(v) { console.log( 'CPU Usage (%): ' + v ); }))
        .pipe(gulp.dest(paths.images.dest))
        .pipe(gulp.dest(paths.images.destProd))
        .pipe(notify('cwebp is done.\n'));
});

gulp.task('img-reload', ['cwebp'], function () {
    return gulp.src(paths.images.destProd)
        .pipe(plumber({errorHandler: onError}))
        .pipe(reload({stream:true}))
        .pipe(notify('img-reload is done.\n'));
});

gulp.task('jekyll-build', function (done) {
    browserSync.notify(messages.jekyllBuild);
    return cp.spawn('jekyll', ['build'], {stdio: 'inherit'})
        .on('close', done);
});

gulp.task('jekyll', ['jekyll-build'], function() {
    return gulp.src(paths.html.watchProd)
        .pipe(minifyHTML())
        .pipe(gulp.dest(paths.html.dest));
});

gulp.task('jekyll-rebuild', ['jekyll'], function () {
    reload();
});

gulp.task('copy-css', function() {
    return gulp.src(paths.copy.styles)
        .pipe(gulp.dest('assets/scss/vendor'));
});

gulp.task('copy-js', function() {
    return gulp.src(paths.copy.scripts)
        .pipe(gulp.dest(paths.scripts.destVen));
});

gulp.task('clear-cache', function(done) {
    return cache(cache.caches = {});
});

gulp.task('clean', ['clear-cache'], function() {
  return gulp.src(paths.html.dest, {read: false})
    .pipe(clean());
});

gulp.task('ngrok', function () {
    ngrok.connect({
        authtoken: 'aGJcNEqh838HDfvyheIe', //2BUMGp1fJDzPal7FvxN2
        //httpauth: 'login:password',
        port: 3000
      }, function(err, url) {
        if (err !== null) {
          console.log( err );
        }
    });
});

gulp.task('pagespeed', ['ngrok'], function () {
    return psi({
        nokey: 'true', // or use key: ‘YOUR_API_KEY’
        url: url,
        strategy: 'mobile'
    });
});

gulp.task('watch', ['sass-min', 'js', 'browser-sync'], function () {
    gulp.watch(paths.styles.watch, ['sass-reload']);
    gulp.watch(paths.scripts.watch, ['js-reload']);
    gulp.watch(paths.images.watch, ['img-reload']);
    gulp.watch(paths.html.watch, ['jekyll-rebuild']);
});

      

Questions

  • How to properly use os-utils to output cpu and memory in% used for one task?
  • Does the onError function work well? I am confused about how to use beep and gutil?
  • How to cache (or change

    , remember

    , cached

    or any other caching plugins) for image problems gulp-resize

    and gulp-cwebp

    ?

Check out the Github repository

I ran a few tests and the processing times suggest that gulp-cached

both parallel

are working fine but gulp-changed

not working. I also tried using plugins gulp-cache

and gulp-cached

instead gulp-changed

, but that didn't work either.

I did the task gulp-reload

for these tests with all the image analyzes from this repo. The task gulp-reload

includes plugins gulp-imagemin

, gulp-image-resize

and gulp-cwebp

.

If you want to run these tests on your local machine, I suggest using a task gulp clear-cache

to clear the cache for a task gulp image-min

.

Test 1

  • image-min [cached]
  • resize image []
  • cwebp []

TIME +/- 64 sec.

Test 2

  • image-min [cached]
  • resizing image [resized]
  • cwebp []

TIME +/- 63 sec

Test 3

  • image-min [cached]
  • resizing image [resized]
  • cwebp [modified]

TIME +/- 64 sec.

Test 4

  • image-min [cached]
  • resizing image [resized, parallel]
  • cwebp [modified]

Time +/- 22 sec

Test 5

  • image-min []
  • resizing image [resized, parallel]
  • cwebp [modified]

Time +/- 32sec

Any suggestions for the code are also welcome!

+3


source to share





All Articles