Another Grunt task: installing Imagemin


I am continuing to add to my grunt task runner process that I started in this post, https://iphonedevlog.wordpress.com/2016/10/31/how-to-use-grunt-to-automate-repetitive-tasks/ (At a minimum, you need to do steps 1-6 on that page.)

In this new article, I’ll add one more processors that I had already listed in the previous article:

d. npm install grunt-contrib-imagemin –save-dev (minimize images to make them faster loading)

I am adding it to the Gruntfile.js file already created in that article. So if you are doing grunt for the first time, you should read that page first — it is an introductory guide for the first-time user.

Installing the grunt-contrib-imagemin plugin

imagemin will compress your images files, whether jpg, png, or gif.

1. Go to http://gruntjs.com/plugins to install plugins. Type imagemin in the Search box, then click on contrib-imagemin by the Grunt team to open it. That brings up page https://www.npmjs.com/package/grunt-contrib-imagemin (Note that Grunt is not the only task runner around. Gulp is also a popular task runner and you’ll see the gulp- prefix before plugins as well.(

2. What does the page tell us to do? It tells us how to install the package. So start the terminal, and from your /myApp folder and run:

npm install grunt-contrib-imagemin --save-dev

If you look in /node_modules, you’ll find a new folder called /imagemin.

3. Open Gruntfile.js and add this line under the similar loadNpmTasklines:

grunt.loadNpmTasks('grunt-contrib-imagemin');

4. Register the task in the appropriate line by adding a comma then ‘imagemin’ to the end:

grunt.registerTask('default', ['jshint','postcss','imagemin'] );

It is my guess that the tasks will be performed in the order listed in registerTask.

5. Again, Grunt is only a task runner — it doesn’t have the guts of the programs themselves. Grunt will open and run imagemin, but it can’t do that if imagemin isn’t installed on the system. So the page gives us the URL so we can install: https://github.com/imagemin/imagemin

6. Install imagemin from the terminal:

npm install --save imagemin

7. Now let’s see how to implement the task in Grunt. Return to https://www.npmjs.com/package/grunt-contrib-imagemin Scrolling down, we already see a sample script:

grunt.initConfig({
 imagemin: { // Task 
 static: { // Target 
 options: { // Target options 
 optimizationLevel: 3,
 svgoPlugins: [{ removeViewBox: false }],
 use: [mozjpeg()]
 },
 files: { // Dictionary of files 
 'dist/img.png': 'src/img.png', // 'destination': 'source' 
 'dist/img.jpg': 'src/img.jpg',
 'dist/img.gif': 'src/img.gif'
 }
 },
 dynamic: { // Another target 
 files: [{
 expand: true, // Enable dynamic expansion 
 cwd: 'src/', // Src matches are relative to this path 
 src: ['**/*.{png,jpg,gif}'], // Actual patterns to match 
 dest: 'dist/' // Destination path prefix 
 }]
 }
 }
});

Let’s take a closer look at these lines:

static{} section

a. Static has to do with specifying particular files and/or folders by name. Dynamic has to do with selecting a range of files by pattern matching. My current project has images in different folders, so I’ll choose static.

b. options. In this section we’ll put all the options we want Grunt to follow regarding the various program parameters. To find these parameters, we must look up each processor’s page and see what options are available. Each file type (jpg, gif, svg, png) has its own lingo, and the options will reflect this.

c. svgoPlugins: [{ removeViewBox: false }] If we choose to use an option specific to svgoPlugins, then we’ll format the entry as shown, with the key:value enclosed with braces as you see them here.

d. use: [mozjpeg()] Here are the options for using mozjpeg: https://github.com/imagemin/imagemin-mozjpeg

e. optimizationLevel: 3. In https://www.npmjs.com/package/grunt-contrib-imagemin we find out what the levels mean. Our options range from 0 through 7. I don’t know the lingo, but I’m going to go out on a limb here and assume that a higher level means more compression. This needs to be tested and images compared, though.

d. files: {}. This nested section within static: {} and is composed of lines divided into two key/value pairs: ‘dist/img.png’: ‘src/img.png’ This means that the img.png in src/ will be compressed and put in dist/ as img.png. If we have images scattered among different folders, then we’ll reproduce that folder structure in src/ and replace dist/ with the actual folder where the image belongs. So: ‘www/folder1/*.jpg’: ‘static/src/folder1/*.jpg’ would satisfy this. Grunt reproduce the folder structure when it puts images in the destination folder, so you’ll need to recreate them yourself. Go ahead and make sure all these folders exist in the project.

dynamic{} section

a. files: expand: true. This is required if we are going to use the dynamic setting.

d. files: cwd. cwd = “Current Working Directory.” For us, that would be myApp/.

e. files: src. **/*. src = “Source.” Source images are those which will be compressed. **/*. tells us to match up any folder in the app. So Grunt will search every folder to find images to compress.

f. {png,jpg,gif} This is the list of graphic image types we want to compress.

g. files: dest: ‘dist/’ This is the folder into which Grunt will insert the compressed images. I created my folder as myApp/dynamic_dest. But what do I do when my images are across several folders? I create matching myApp/dynamic_src/ and myApp/dynamic_dest/ folders for each folder. Grunt will not recreate the folder structure, so you need to make all folders you’ve listed in Gruntfile.js.

Why am I using both static and dynamic sections? I decided to use the static section to minimize the images that are scattered throughout the app. I’ll use dynamic to minimize the icons that will be generated by cordova and placed there, and I’ll put the screenshots there too that I’ll upload to the stores (faster upload, anyone?).

So myApp/ includes:

config.xml
dynamic_dest/
dynamic_src/
Gruntfile.js
hooks/
node_modulres
package.json
platforms/
plugins/
static_src/
www/

Inside static_src/ and www/ I include matching folders:

folder1/
folder2/
folder3/

So my final imagemin section in Gruntfile.js looks like:

,
 imagemin: { // Task 
 static: {
 options: { // Target options 
 optimizationLevel: 7,
 // svgoPlugins: [{ removeViewBox: false }], not using SVG format now
 use: [mozjpeg()]
 },
 files: { // Dictionary of files 
 'www/folder1/static1.gif': 'static_src/folder1/static1.gif' , // 'destination': 'source' 
 'www/folder2/static2.png': 'static_src/folder2/static2.png' ,
 'www/folder3/static3.jpg': 'static_src/folder3/static3.jpg' 
 }
 },
 dynamic: { // Another target 
 files: [{
 expand: true, // Enable dynamic expansion 
 cwd: 'dynamic_src/', // Source matches are relative to this path 
 src: ['**/*.{png,jpg,gif}'], // Actual patterns to match 
 dest: 'dynamic_dest/' // Destination path prefix 
 }]
 }

I grabbed these files from the web to test:

These go into myApp/static_src/ folders 1, 2, and 3, one picture in each:

These go in myApp/dynamic_src/ (cleverly named, huh?):

Results

Running "imagemin:static" (imagemin) task
Minified 3 images (saved 284.16 kB)

Running "imagemin:dynamic" (imagemin) task
Minified 3 images (saved 127.95 kB)

One thought on “Another Grunt task: installing Imagemin

  1. Pingback: How to use Grunt to automate repetitive tasks | iPhone Dev Log

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.