Optimizing images using imagemin Grunt plugin

I have tried to use Prepros and one feature that I like is its image optimization. This feature reduces the byte size of of the image and this means faster web page loading. But Grunt is the workflow management I am using. Good thing is Grunt has this Imagemin plugin which can also optimize images (jpeg, png and gif). Lets take a look on how to setup and use this plugin to our workflow. My operating system is Windows. Therefore, the shell commands, output, etc. that will be shown here are for Windows.

File structure

We'll use this project folder structure:

Project folder structure

Where:

img_src = all image files (jpeg, png and gif) stored here will be the source of imagemin

img_dest = optimized image files processed by imagemin will be saved in this folder

Lets create two empty text files labeled as "package.json" and "gruntfile.js":

Setup files

Setup Imagemin

Populate "package.json" with these codes:


{
  "name": "sample_project",
  "description": "Sample imagemin project",
  "version": "0.0.1",
  "author": "Your name",
  "homepage": "http://www.webfoobar.com",
  "dependencies": {
    "grunt": "~0.4.5",
    "grunt-contrib-imagemin": "~1.0.0",
    "grunt-contrib-watch": "~0.6.1"
  }
}

At your command prompt, execute:


npm install

As output, you should see something like this (by the way, I am using Git's cygwin here):

Imagemin install output

We will going to use pngquant to optimize png image files, mozjpeg for jpeg and gifsicle for gif.

To install pngquant, execute the following command at your terminal:


npm install imagemin-pngquant

Terminal output:

imagemin-pngquant installation output

To install mozjpeg, execute the following command at your terminal:


npm install imagemin-mozjpeg

Terminal output:

imagemin-mozjpeg installation

And to install gifsicle, execute the following command at your terminal:


npm install imagemin-gifsicle

Terminal output:

imagemin-gifsicle installation

You may be asking, why we did not just add imagemin-pngquant, imagemin-mozjpeg and imagemin-gifsicle as dependencies at our "package.json" file and execute "npm install" to install all plugins in one command. I have already tried but I got this error:

Error

Note: if ever one or all the image tools software failed to install, temporarily disable the anti-virus and execute the commands again to re-install.

Grunt tasks

Open our "gruntfile.js" and populate it with these codes:


var pngquant = require('imagemin-pngquant');
var mozjpeg = require('imagemin-mozjpeg');
var gifsicle = require('imagemin-gifsicle');
module.exports = function (grunt) {
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-imagemin');
  grunt.initConfig({
    imagemin:{
    target: {
      options: {
        optimizationLevel: 3,
        progressive: true,
        use: [pngquant(), mozjpeg(), gifsicle()]
      }, // options
      files: [{
        expand: true,
        cwd: 'img_src/',
        src: ['**/*.{png,jpg,jpeg,gif}'],
        dest: 'img_dest/'
      }] // files
    } // target
    }, // imagemin
    watch: {
      imageopti: {
        files: ['img_src/*.*'],
        tasks: ['imagemin']
      } // imageopti
    } // watch
  }); // initConfig
  grunt.registerTask('default', 'watch');
} // exports

Execute the following command at your terminal:


grunt

You should see something like this at your terminal:

Grunt command executed

Grunt is now waiting for any changes (file edit or file add) in our "img_src" folder. If we add image files in this folder, we should see something like this at our terminal:

Image files added to img_src

Grunt will automatically optimize the image files (*.png, *.jpg, *.jpeg and *.gif) inside "img_src" and save the optimized image files at "img_dest" folder.

Comments

Thsi worked for me.....Appreciate the effort

Hi!

Thanks for this tutorial, and also for "Using SASS in Bootstrap Drupal theme".

I have setup imagemin following the steps above, but when I start grunt, the following error message is displayed:

/home/alien/www/www-gorj/sites/all/themes/gjtheme/node_modules/imagemin-pngquant/index.js:2
const execBuffer = require('exec-buffer');
^^^^^
Loading "gruntfile.js" tasks...ERROR
>> SyntaxError: Use of const in strict mode.
Warning: Task "default" not found. Use --force to continue.

Aborted due to warnings.

Can you help me with this?

Thank you!

Hi,

You're welcome!

That's new, I haven't encountered that error. I checked my "node_modules/imagemin-pngquant/index.js" line 1 to 5:

  
'use strict';
var spawn = require('child_process').spawn;
var isPng = require('is-png');
var pngquant = require('pngquant-bin');
var through = require('through2');
  

Your's different. My imagemin-pngquant version is 4.2.0. Please try installing that version:

  
npm install [email protected]
  

Hi!

Thank you! That solved my problem. I was using the latest versions of imagemin-pngquant, imagemin-mozjpeg & imagemin-gifsicle. Hence the error.

Starting from your fix, I tried other versions for those libraries and it turned out that the latest versions that work in this context are:

  
[email protected]
[email protected]
[email protected]
  

Also, I noticed that the script is running the imagemin task for all the images in the source folder everytime you add a new image. I solved this by installing grunt-newer

  
sudo npm install grunt-newer --save-dev
  

Based on your script, my new gruntfile.js looks like this:

  
var pngquant = require('imagemin-pngquant');
var mozjpeg = require('imagemin-mozjpeg');
var gifsicle = require('imagemin-gifsicle');
module.exports = function (grunt) {
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-imagemin');
  grunt.loadNpmTasks('grunt-newer');
  grunt.initConfig({
    uglify: {
      js_dev: {
        options: {
          preserveComments: 'all',
          beautify: {
            width: 80,
            beautify: true
          } // beautify
        }, // options
        files: {
          'js/scripts.js': [
            'bootstrap/javascripts/bootstrap/affix.js',
            'bootstrap/javascripts/bootstrap/alert.js',
            'bootstrap/javascripts/bootstrap/button.js',
            'bootstrap/javascripts/bootstrap/carousel.js',
            'bootstrap/javascripts/bootstrap/collapse.js',
            'bootstrap/javascripts/bootstrap/dropdown.js',
            'bootstrap/javascripts/bootstrap/modal.js',
            'bootstrap/javascripts/bootstrap/tooltip.js',
            'bootstrap/javascripts/bootstrap/popover.js',
            'bootstrap/javascripts/bootstrap/scrollspy.js',
            'bootstrap/javascripts/bootstrap/tab.js',
            'bootstrap/javascripts/bootstrap/transition.js',
            'assets/js/*.js'
          ]
        } // files
      }, // js_dev
      js_prod: {
        files: {
          'js/scripts.js': [
            'bootstrap/javascripts/bootstrap/affix.js',
            'bootstrap/javascripts/bootstrap/alert.js',
            'bootstrap/javascripts/bootstrap/button.js',
            'bootstrap/javascripts/bootstrap/carousel.js',
            'bootstrap/javascripts/bootstrap/collapse.js',
            'bootstrap/javascripts/bootstrap/dropdown.js',
            'bootstrap/javascripts/bootstrap/modal.js',
            'bootstrap/javascripts/bootstrap/tooltip.js',
            'bootstrap/javascripts/bootstrap/popover.js',
            'bootstrap/javascripts/bootstrap/scrollspy.js',
            'bootstrap/javascripts/bootstrap/tab.js',
            'bootstrap/javascripts/bootstrap/transition.js',
            'assets/js/*.js'
          ]
        } // files
      } // js_prod
    }, // uglify
    compass: {
      prod: {
        options: {
          config: 'config.rb',
          environment: 'production'
        } // options
      }, // prod
      dev: {
        options: {
          config: 'config.rb'
        } // options
      } // dev
    }, // compass
    imagemin: {
      target: {
        options: {    
          use: [pngquant(), mozjpeg(), gifsicle()],
        },
        files: [{
          expand: true,
          cwd: 'assets/images/',
          src: ['**/*.{png,jpg,jpeg,gif}'],
          dest: 'img/'
        }] // files
      } // target
    }, // imagemin
    watch: {
      sass: {
        files: ['assets/sass/*.scss'],
        tasks: ['compass:dev']
      }, // sass
      javascripts: {
        files: ['assets/js/*.js'], // We only need to watch the custom js
        tasks: ['uglify:js_dev']
      }, // javascripts
      imageopti: {
        files: ['assets/images/*.*'],
        tasks: ['newer:imagemin']
      } // imageopti
    } // watch
  }); // initConfig

  grunt.registerTask('default', 'watch');
  grunt.registerTask('prod', ['uglify:js_prod', 'compass:prod', 'imagemin']);
} // exports
  

I shared this in case you find it useful.

Thanks again for your tutorial! It is really helpfull!

The solution for "Fatal error: Cannot read property 'contents' of undefined" error is to update your grunt-contrib-imagemin to version 1.0.0. Open your package.json and have the following script:

  
{
  "name": "sample_project",
  "description": "Sample imagemin project",
  "version": "0.0.1",
  "author": "Your name",
  "homepage": "http://www.webfoobar.com",
  "dependencies": {
    "grunt": "~0.4.5",
    "grunt-contrib-imagemin": "~1.0.0",
    "grunt-contrib-watch": "~0.6.1"
  }
}
  

And run:

  
npm install
  

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.