Bootstrap 4 – Introducing Grunt

The minifier that we used in the previous section greatly reduced the size of our style sheet and JavaScript files and also helped reduce the overall number of requests required to render MyPhoto. However, using it has one downside—every time that you make a change to either your CSS or JavaScript code during development, you are required to rerun the tool. This greatly slows down development and can even cause frustration and hair-tearing. (Just imagine forgetting to run the minifier, thinking that you ran it, and not seeing your changes appear. You are likely to blame your code as opposed to your forgetfulness.) Therefore, would it not be nice if we could minify and concatenate our files automatically every time that we make a change to our source code?

Meet Grunt, the JavaScript Task Runner ( http://gruntjs.com/). As implied by its name, Grunt is a tool that allows us to automatically run any set of tasks. Grunt can even wait while you code, pick up changes made to your source code files (CSS, HTML, or JavaScript) and then execute a preconfigured set of tasks every time that you save your changes. This way, you are no longer required to manually execute a set of commands in order for your changes to take effect.

Let’s go ahead and install Grunt:

    npm install grunt

Before we can start using run with MyPhoto, we need to tell Grunt:

  • What tasks to run, that is, what to do with the input (the input being our MyPhoto files) and where to save the output
  • What software is to be used to execute the tasks
  • How to name the tasks so that we can invoke them when required

With this in mind, we create a new JavaScript file (assuming UTF-8 encoding), called Gruntfile.js, inside our project root. We will also need to create a JSON file, called package.json, inside our project root. Our project folder should have the following structure (note how we created one additional folder, src, and moved our source code and development assets inside it):

src 
|__bower_components
|__images
|__js
|__styles
|__index.html
Gruntfile.js
package.json

Open the newly created Gruntfile.js and insert the following function definition:

    module.exports = function(grunt) {   
        grunt.initConfig({ 
            pkg: grunt.file.readJSON("package.json") 
        }); 
    }; 

As you can see, this is plain, vanilla JavaScript. Anything that we need to make Grunt aware of (such as the Grunt configuration) will go inside the grunt.initConfig function definition. Adding the configuration outside the scope of this function will cause Grunt to ignore it.

Now open package.json and insert the following:

    { 
        "name": "MyPhoto", 
        "version": "0.1.0", 
        "devDependencies": { 
        } 
    } 

The preceding code should be self-explanatory. The name property refers to the project name, version refers to the project’s version, and devDependencies refers to any dependencies that are required (we will be adding to those in a while).

Great, now we are ready to start using Grunt!

Minification and concatenation using Grunt

The first thing that we want Grunt to be able to do is minify our files. Yes, we already have minifier installed, but remember that we want to use Grunt so that we can automatically execute a bunch of tasks (such as minification) in one go. To do so, we will need to install the grunt-contrib-cssmin package (a Grunt package that performs minification and concatenation . Visit https://github.com/gruntjs/grunt-contrib-cssmin for more information.):

    npm install grunt-contrib-cssmin --save-dev

Once installed, inspect package.json. Observe how it has been modified to include the newly installed package as a development dependency:

    { 
        "name": "MyPhoto", 
        "version": "0.1.0", 
        "devDependencies": { 
            "grunt": "^0.4.5", 
            "grunt-contrib-cssmin": "^0.14.0" 
        } 
    } 

We must tell Grunt about the plugin. To do so, insert the following line inside the function definition within our Gruntfile.js:

    grunt.loadNpmTasks("grunt-contrib-cssmin");

Our Gruntfile.js should now look as follows:

    module.exports = function(grunt) {   
        grunt.initConfig({ 
            pkg: grunt.file.readJSON("package.json") 
        }); 
        grunt.loadNpmTasks("grunt-contrib-cssmin"); 
    }; 

As such, we still cannot do much. The preceding code makes Grunt aware of the grunt-contrib-cssmin package (that is, it tells Grunt to load it). In order to be able to use the package to minify our files, we need to create a Grunt task. We need to call this task cssmin:

 module.exports = function(grunt) { 
   grunt.initConfig({ 
      pkg: grunt.file.readJSON("package.json"), 
        "cssmin": { 
          "target": { 
            "files": {
              "dist/styles/myphoto.min.css": [
                "styles/*.css",
                "!styles/myphoto-hcm.css"
               ]
              } 
            } 
          } 
       }); 
     grunt.loadNpmTasks("grunt-contrib-cssmin"); 
   }; 

Whoa! That’s a lot of code at once. What just happened here? Well, we registered a new task called cssmin. We then specified the target, that is, the input files that Grunt should use for this task. Specifically, we wrote this:

    "src/styles/myphoto.min.css": ["src/styles/*.css"]

The name property here is being interpreted as denoting the output, while the value property represents the input. Therefore, in essence, we are saying something along the lines of “In order to produce myphoto.min.css, use the files a11yhcm.css, alert.css, carousel.css, and myphoto.css“.

Go ahead and run the Grunt task by typing as follows:

    grunt cssmin

Upon completion, you should see output along the lines of the following:

Figure 8.1: The console output after running cssmin

The first line indicates that a new output file (myphoto.min.css) has been created and that it is 3.25 kB in size (down from the original 4.99 kB). The second line is self-explanatory, that is, the task executed successfully without any errors.

Now that you know how to use grunt-contrib-cssmin, go ahead and take a look at the documentation for some nice extras!

Comments are closed.