PROFILE

GruntJS SASS Javascript

Letting GruntJS run the show

Letting GruntJS run the show

Today I'm going to show you how to create a basic gruntjs setup. If you don't know what grunt is, I'd recommend you head over to the GruntJS site to catch up. In a nutshell, grunt is a task runner for javascript, this means that it can take any repetitive task the we do as developers, and automates it. We can compile SASS/LESS/Stylus or any css preprocessor language we use, minify HTML/JS/CSS, create sprites, optimize images, run tests...(u get the point).

First of all, be sure to have a package.json. If you don't have it yet, you can create it with npm init, which will walk you through in creating it, we need it for grunt to run. Our app/website directory structure, for this example, is simple and will look like:

assets/  
  ├─ js/
  ├─ img/
  └─ sass/
dist/ <-- this is where grunt will output our assets  
Gruntfile.js  
index.html  
package.json  

Now, we are going to need a couple of things to get this going. There are some dependencies we need for grunt, which are the following:

  • grunt
  • grunt-contrib-sass
  • grunt-contrib-uglify
  • grunt-contrib-imagemin

We need to add those NPMs to our project, lets install and save them in our package.json. Since we know all the modules we need, we will install them in one line: npm install grunt grunt-contrib-sass grunt-contrib-uglify grunt-contrib-imagemin --save-dev

Ok, so now we have our dependencies, what now? Gruntfile.js! Grunt uses this file to setup all its configurations. Go ahead and create it, yeah... we need to do this one manually. Put Gruntfile.js at the same level as package.json

Gruntfile.js will contain three parts:

  • Grunt wrapper function
  • Project configurations
  • Loading tasks

It has 1 more, which is 'Custom tasks' for running tasks that we create. We are not going to use it here.

The first part, is a simple function wrapper with 'grunt' as a parameter, and will contain almost everything needed. So the file will look kinda like:

// Grunt Wrapper Function ======================/
var grunt_wrap = function (grunt) {  
    // Configurations ==========================/

    // Load Dependent Plugins ==================/

    // Tasks ===================================/
}

module.exports = grunt_wrap  

For the configurations part, it will contain our three tasks and will look like:

// Configurations ==========================/
grunt.initConfig({  
    sass: {
        dist: {
            expand: true,                   // Dynamic expansion
            cwd: 'assets/sass/',            // current working directory (cwd)
            src:[                           // Files to watch and ignore
                    '**/*.scss',
                    '!**/_*.scss'
                ],  
            dest: 'dist/css',               // Where the output will go
            ext: '.css',                    // Extension of the output
            options: {
                style: "compressed"         // Minify CSS
            }
        }
    },
    uglify: {
        build: {
            files: [{
                expand: true,               // Dynamix expansion
                cwd: 'assets/js',           // current working directory (cwd)
                src: '**/*.js',             // Files to watch and ignore
                dest: 'dist/js/',           // Where the output will go
                ext: '.js'                  // Extension of the output
            }]
        }
    },
    imagemin: {
        png: {
            options: {
                optimizationLevel: 3
            },
            files: [
                {
                    expand: true,           // Dynamix expansion
                    cwd: 'assets/img/',     // current working directory (cwd)
                    src: ['**/*.png'],      // Files to watch and ignore
                    dest: 'dist/img/',      // Where the output will go
                    ext: '.png'             // Extension of the output
                }
            ]
        },
        jpg: {
            options: {
                progressive: true
            },
            files: [
                {
                    expand: true,           // Dynamix expansion
                    cwd: 'assets/img/',     // current working directory (cwd)
                    src: [                  // Files to watch and ignore
                        '**/*.jpg',
                        '**/*.jpeg'
                    ],
                    dest: 'dist/img/',      // Where the output will go
                    ext: '.jpg'             // Extension of the output
                }
            ]
        },
        gif: {
            options: {
                interlaced: true
            },
            files: [{
                expand: true,               // Dynamix expansion
                cwd: 'assets/img/',         // current working directory (cwd)
                src: ['**/*.gif'],          // Files to watch and ignore
                dest: 'dist/img/',          // Where the output will go
                ext: '.gif'                 // Extension of the output
            }]
        }
    }
})

Lastly, we just list the grunt packages and the names of the tasks that we want/need.

// Load Dependent Plugins ==================/
grunt.loadNpmTasks('grunt-contrib-sass')  
grunt.loadNpmTasks('grunt-contrib-uglify')  
grunt.loadNpmTasks('grunt-contrib-imagemin')

// Tasks ===================================/
grunt.registerTask('default', ['sass','uglify','imagemin'])  

So what's happening here? We have just specified a set of 'strategies' to use for each of our tasks. Each strategy has its own set of rules to follow. Then after loading the tasks in grunt, we tell it that the default task, will run our 3 strategies in one run.

It is now a matter of just doing grunt in the command line and it will run all tasks. In order to have this tasks watching for changes, we need another package. Lets install it with npm install grunt-contrib-watch --save-dev. We need to make some updates on the three parts of the gruntfile.

// Configurations ==========================/
grunt.initConfig({  
    sass:{/* SASS conf */},
    uglify:{/* uglify conf */},
    imagemin:{/* imagemin conf */}, 
    watch: {
        css: {
          files: 'assets/sass/**/*.scss',
          tasks: ['sass'],
          options: {
              spawn: false,
          }
        },
        scripts: {
          files: ['assets/js/**/*.js'],
          tasks: ['uglify'],
          options: {
             spawn: false,
          }
        },
        images: {
          files: ['assets/img/**/*.{png,jpg,jpeg,gif}'],
          tasks: ['imagemin'],
          options: {
            spawn: false,
          }
        }
    }
})

// Load Dependent Plugins ==================/
grunt.loadNpmTasks('grunt-contrib-sass')  
grunt.loadNpmTasks('grunt-contrib-uglify')  
grunt.loadNpmTasks('grunt-contrib-imagemin')  
grunt.loadNpmTasks('grunt-contrib-watch')

// Tasks ===================================/
grunt.registerTask('default', ['watch'])  

Notice we changed the default task to the strategy 'watch'. Inside the watch strategy, we are looking for changes to css, js, and images, and then run their tasks accordingly.

Now, doing grunt in the command line, will start watching for changes. I hope this can get you started with gruntjs. There are lots of things we can do with grunt, this is just scratching the surface with basic tasks. Be sure to take a look at the thousands of plugins for grunt, maybe you find a couple of useful plugins there.

Here is the link to a sample repo for reference.

comments powered by Disqus