Gruntfile.js configuration

This is one way to create Gruntfile.js; alternatively, we can copy and paste the sample Gruntfile from http://gruntjs.com/sample-gruntfile or we can start from scratch. We will begin from scratch so that the process of creating Gruntfile.js can be reviewed and discussed as we apply the configuration in the context of sample_project. When completed, we will have a configuration file that is ready to be used to build our project, which we will discuss in the next chapter.

When starting from scratch, first create an empty file in the root of sample_project named Gruntfile.js. Your project tree should look like the following:

Gruntfile.js configuration

We start with creating the wrapper, which—as discussed—is required in order to inject the Grunt object into the configuration. This is accomplished by the Grunt argument in the anonymous function that is assigned to module.exports. The module.exports function allows the Grunt configuration to be required as a module by Grunt. This allows the module to be imported by Grunt:

Gruntfile.js configuration

Next, we will call on the Grunt object's initConfig method in order to initialize the Grunt configuration object. This method will contain our task configuration code whose properties will be used by the plugins. For now, we will just create the method signature and then discuss its contents:

Gruntfile.js configuration

Now, referring to the user stories, let's use the list of options and plugins to be implemented as a reference for configuration:

  • banner option
  • contrib-jshint
  • contrib-uglify
  • contrib-less
  • contrib-imagemin
  • notify
  • open
  • contrib-watch

Beginning with the banner option, we will create the configuration for a banner that can be used for comment headers for generated files, such as in contrib-uglify plugin. The first requirement will be reading the JSON from package.json so that we can use metadata from the file within the banner. We will use Grunt's file class' readJSON method in order to get these contents for us:

Gruntfile.js configuration

The readJSON method takes a string argument of the path to package.json and imports the metadata to the Grunt configuration. Once imported, we can use template strings in order to access the configuration properties. In this case, we can access these properties through the pkg object, for example, <%= pkg.name %>.

With the package metadata imported to gruntfile, creating the banner with information from package.json is now possible. At this time, some modifications to package.json need to be made to remove some of the boilerplate and add project-specific information, such as the actual project name, author name, and repository location. The top section of metadata in package.json will now look as follows:

"name": "sample_project",
  "private": true,
  "version": "0.0.1",
  "description": "Learning Grunt",
  "repository": "https://myrepository.dr-int/project/sample_project",
  "author": {
    "name": "Douglas Reynolds"
  },

These changes will support the banner comment content that we wish to include in the head of our generated JavaScript file(s). We can now implement this banner code in Gruntfile.js by accessing the properties of the pkg object, as follows:

Gruntfile.js configuration

What we end up with for the banner in this example is text that will provide a message to developers not to modify this file directly. It will provide the name of the application and version along with the date that the file was generated on, location of the repository, and copyright information. Here is an example of what might actually be the output to a file:

/*! *** DO NOT EDIT THIS FILE ***
It is automatically generated in the build 
gruntTest - v0.0.1 - 2015-11-01
https://myrepository.dr-int/project
Copyright (c) 2015 Douglas Reynolds;*/

This completes the banner configuration; the entire Gruntfile.js should now include the following code:

module.exports = function(grunt) {
  grunt.initConfig({
    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
    banner: '/*! *** DO NOT EDIT THIS FILE ***
' +
    'It is automatically generated in the build 
' +
    '<%= pkg.name %> - v<%= pkg.version %> - ' +
      '<%= grunt.template.today("yyyy-mm-dd") %>
' +
      '<%= pkg.repository %>
' +
      '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;*/
',
  });
};

Now it is time to begin the configuration of our first task, contrib-jshint. If you recall, the contrib-jshint task will lint the JavaScript to automate the process of checking for errors in the code. We will want contrib-jshint to lint any JavaScript file in our application, and we will use a special file named .jshintrc to specify some options that will be used by jshint. The contrib-jshint plugin may be configured to use its default options by simply not declaring any options. The following example will show you how contrib-jshint may be tailored to specific linting requirements. First, let's have a look at .jshintrc. Save a file in the root of sample_project named .jshintrc, and then add the following JSON formatted options to the file:

{
  "curly": true,
  "eqeqeq": true,
  "latedef": true,
  "noarg": true,
  "undef": true,
  "unused": true,
  "boss": true,
  "eqnull": true,
  "node": true
}

There are two basic types of options that can be configured for jshint: enforcing and relaxing. Enforcing options will produce errors and/or warning messages, whereas relaxing will suppress warnings.

  • curly: This enforces that curly braces are used around blocks in loops and conditions rather than allowing the omission of braces in some cases.
  • eqeqeq: This enforces === and !== as opposed to using == or != syntax.
  • latedef: This will ensure that variables are not used prior to their definition. noarg prohibits arguments.caller and arguments.callee, which are deprecated in future versions of JavaScript.
  • undef: This enforces that all the variables be explicitly declared. unused warns about the variables that are defined but then never used.
  • boss: This is a relaxing option that suppresses warnings about assignments where comparisons are expected.
  • eqnull: This is a relaxing option that suppresses warnings about the == null comparisons. node is used to define global variables in applications that are running inside of the node environment, such as Grunt in the case of sample_project.

For more information on jshint, refer to the NPM jshint documentation at https://www.npmjs.com/package/jshint. Note that in the .jshintrc project, there were also a series of options created by the Angular Seed project scaffolding. These are not discussed here as they are being used by the framework.

Our configuration in Gruntfile.js for contrib-jshint is simply to provide a list of source files that should be linted, any options that should be included, such as .jshintrc, and the inclusion of linting Gruntfile.js, as this too is a JavaScript file and we want to ensure that there are no coding errors in our configuration file. Our current contrib-jshint configuration will look like the following:

// Task configuration.
jshint: {
  files: ['scripts/main.js'],
  gruntfile: {
    options: {
      jshintrc: '.jshintrc'
    },
    src: 'Gruntfile.js'
  }
}

The file's configuration defines the path of an array of files that will be linted. The gruntfile specifies the options to be used; in this case, these are located in .jshintrc. The options may be omitted in order to use jshint's default options, or rather than using the .jshintrc file, the options may be specified as a JSON formatted list. Finally, the source path of this gruntfile is defined so that Gruntfile.js will be included in the linting.

The contrib-uglify plugin is the next task that we will configure. Recall that contib-uglify plugin is a code minimizer that will compress our code and output the minimized code to our deployment location. It will use our banner in its output as well as our pkg object to dynamically generate filenames. Here is the contrib-uglify plugin configuration:

uglify: {
options: {
banner: '<%= banner %>'
},
dist: {
src: 'scripts/main.js',
dest: 'build/scripts/<%= pkg.name %>.<%= pkg.version %>.min.js'
},
}

The uglify configuration provides you with a definition of options that, in this case, takes our banner. The banner content is called in through the template string notation, <%= banner %>, which will then be prepended to the minified file output. The dist configuration object specifies the source and destination locations for the files to be minified. The src parameter provides the file to be minified, and dest creates the path and filename of the distribution file to be generated.

Here is the configuration file that we have written thus far:

Gruntfile.js configuration

The next plugin to configure is contrib-less, which will compile LESS into CSS and place the compiled CSS in the appropriate deployment directory. By now, the pattern of configuration should be evident. Each task configuration is different; however, the general format of each is quite similar. Here is the contrib-less configuration code for us to discuss:

less: {
  options: {
     paths: ["styles"]
  },
  dist: {
    src: 'styles/main.less',
    dest: 'styles/main.css'
   }
}

First, an options object is defined with a paths property that defines the directory name that contrib-less will scan for @import directives (normally the same directory as the source file location). Next, the dist object defines the src and destination paths to be used to create the CSS distribution file. The contrib-less plugin will compile the file in the source directory into CSS and write the new file to the distribution location. If there are any @import directives, contrib-less will include these in the compilation.

Next in line is contrib-imagemin, which will be used for the minification of images. This process will compress the images in the project's image source directory and output the compressed versions to a distribution deployment directory. The contrib-imagemin plugin has not yet been installed in the project; we can use this as a quick review on installing a plugin with Node Package Manager (NPM). Installation of contrib-imagemin is accomplished with the same npm install command:

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

After running the installation command, contrib-imagemin will be installed in the node-modules directory located at the root of sample_project. Additionally, the plugin will be registered in package.json devDependencies with a line that will resemble grunt-contrib-imagemin": "^0.9.4. At this point, we can go forward with the configuration in Gruntfile.js:

imagemin: {
   dynamic: {
      files: [{
        expand: true,
        cwd: 'images/',
        src: ['**/*.{png,jpg,gif}'],
        dest: 'dist/'
      }]
   }
}

Imagemin provides you with two types of target configurations: static and dynamic. In a static configuration, each file and destination is listed specifically, such as images/img.png: dist/img.png. In this example, the path and filename of source and destination are explicit. In the preceding code example, a dynamic target is being configured. Notice that a dynamic target is specified that contains the file's configuration. Expand is set to true, which will enable dynamic expansion, and cwd is the source path relative to the CWD. Notice that src is configured to use wildcards.

The path wildcard, **/*.{png,jpg,gif}, is of interest, which reads as follows: match any number of characters (**/), including (/), and then match any number of characters (*) (.) match png, jpg, or gif file extensions. Using this matching syntax, we can traverse the images directory for any image name that is of a png, jpg, or gif type. Finally, the destination location is defined as the dist directory. It is recommended to use the grunt-newer plugin with contrib-imagemin, which can be configured to run only contrib-imagemin on files that have changed. This helps reduce unnecessary minification time wasted on images that have not changed since last being compressed. Have a look at the NPM grunt-newer plugin documentation for more information at https://www.npmjs.com/package/grunt-newer.

The notify is the next plugin to be configured and is really one of the coolest plugins. Getting notifications on the status is convenient and keeps a developer from having to leave their IDE to go look at the Terminal output. With notify, we can provide feedback with automated desktop notifications in OS X Notification Center, Growl, or Windows 8+ Notifications, for example. We have not yet installed notify in sample_project, so, as usual, run the NPM installation command on notify:

npm install grunt-notify –save-dev

This installs notify in the node-modules directory and adds an entry to devDependencies, which will look similar to grunt-notify": "^0.4.1. The notify configuration will include each plugin that you wish to receive a notification of the status of success or failure along with a custom title and message for success. In failure, the notification will include the error or warning message. The sample_project configuration will look as follows:

notify: {
  jshint: {
options: {
          title: 'Linting Complete',
          message: 'jshint finished',
      }
  },
  uglify: {
options: {
          title: 'Minification Complete',
          message: 'javascript is minified'
      }
  },
  less: {
options: {
          title: 'LESS Compiled',
          message: 'CSS is generated'
      }
  },
  imagemin: {
options: {
          title: 'Images Minified',
          message: 'Images are minified'
        }
     }
  }

In sample_project, there will be notifications for tasks to include contrib-jshint, contrib-uglify, contrib-less, and contrib-imagemin. The configuration includes a block for each plugin to be configured with notifications. Within each block is an options object with title and message properties. Title is optional and message is required. This configuration will set up notifications for each of the defined tasks and then present the build status notification for each task.

When the build has completed successfully, it will be convenient for the application to open, refreshed with changes, in the default browser. To begin, we need to install grunt-open using NPM:

npm install grunt-open --save-dev

The open can be found in the node-modules directory and will be registered in package.json devDependencies, similar to grunt-open": "^0.2.3. Once installed, configuration is straightforward with the following implementation:

open : {
  dev : {
    path: 'http://localhost:8000/app/index.html',
    app: 'Google Chrome'
  }
}

In this example, open is configured with a dev environment object that contains path and app properties. Multiple environment configurations can be contained within open, for instance, dev, test, and prod environments can be configured to meet your requirements. In this case, we will configure a single development environment to open our application in our local node HTTP server that is running on localhost port 8000 with a path to index.html: http://localhost:8000/app/index.html. Additionally, Google Chrome is used as the browser to open and run the sample_project application. When run, Google Chrome will be launched and the changes will be updated for the testing.

Finally, we will configure contrib-watch. As this has already been installed, we can go right into the configuration. Recall first that watch chains tasks to change events so that other tasks may run automatically when files change. The contrib-watch plugin is key for us to fully automate the build process; otherwise, each time we wish to build, we would need to go to the Terminal window and run the Grunt command to kick off the build process. Configuration of watch is typical, as shown here in the implementation:

watch: {
      gruntfile: {
        files: 'Gruntfile.js',
        tasks: ['jshint','uglify','less','imagemin'],
      },
      scripts: {
        files:['scripts/*.js','styles/*.less'],
        tasks: ['default']
      }
    }

The watch task has two objects specified to watch in this configuration. The first is to look for changes in Gruntfile.js itself. In the case of sample_project, contrib_watch is configured to run contrib-jshint, contrib-uglify, contrib-less, and contrib-imagemin if Gruntfile.js changes. As seen in the configuration, the files property defines which file(s) to watch and the tasks property defines which tasks to run when the specified file(s) change. In the second half of the configuration, we are setting up a scripts watch that will watch any files with .js extensions that exist in the scripts directory as well as files that have the .less extension located in the styles directory. When any of these files change, watch will run the default task, which we will look at in the next chapter.

At this point, our Gruntfile.js configuration should look like the following:

module.exports = function(grunt) {
  'use strict';
  grunt.initConfig({
    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
    banner: '/*! *** DO NOT EDIT THIS FILE ***
' +
    'It is automatically generated in the build 
' +
    '<%= pkg.name %> - v<%= pkg.version %> - ' +
      '<%= grunt.template.today("yyyy-mm-dd") %>
' +
      '<%= pkg.repository %>
' +
      '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;*/
',
    // Task configuration.
    jshint: {
      files: ['scripts/main.js'],
      gruntfile: {
        options: {
          jshintrc: '.jshintrc'
        },
        src: 'Gruntfile.js'
      }
    },
    uglify: {
      options: {
        banner: '<%= banner %>'
      },
      dist: {
        src: 'scripts/main.js',
        dest: 'build/scripts/<%= pkg.name %>.<%= pkg.version %>.min.js'
      },
    },
    less: {
      options: {
        paths: ["styles"]
      },
      dist: {
        src: 'styles/main.less',
        dest: 'styles/main.css'
      }
    },
    imagemin: {
      dynamic: {
        files: [{
          expand: true,
          cwd: 'images/',
          src: ['**/*.{png,jpg,gif}'],
          dest: 'dist/'
        }]
      }
    },
    notify: {
      jshint: {
        options: {
          title: 'Linting Complete',
          message: 'jshint finished',
        }
      },
      uglify: {
        options: {
          title: 'Minification Complete',
          message: 'javascript is minified'
        }
      },
      less: {
        options: {
          title: 'LESS Compiled',
          message: 'CSS is generated'
        }
      },
      imagemin: {
        options: {
          title: 'Images Minified',
          message: 'Images are minified'
        }
      },
      watch: {
        options: {
          title: 'Watch Started',
          message: 'Watch is running'
        }
      }
    },
    open : {
      dev : {
        path: 'http://localhost:8000/app/index.html',
        app: 'Google Chrome'
      }
    },
    watch: {
      gruntfile: {
        files: 'Gruntfile.js',
        tasks: ['jshint','uglify','less','imagemin'],
      },
      scripts: {
        files:['scripts/*.js','styles/*.less'],
        tasks: ['default']
      }
    },
  });
};
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.81.154