Chapter 6. Building the Sample Project

In this chapter we will discuss the process of final build configuration and then actually running automated builds of the sample_project. We will learn:

  • Loading tasks: We will have a look at loading tasks to be run, adding them incrementally so we can check the configuration and ensure the expected results are being generated
  • Defining custom and default tasks: The custom tasks will provide the means to configure custom task functionality for specific situations. The default task will allow us to create a launch configuration. This will require only a single command from the terminal to start up our automated build.
  • Functional testing: Functional testing will provide examples of how to run and check the specific outcomes of each of the tasks included in our automated build

Understanding task loading

The process and syntax for loading a task are quite simple and very straightforward. In fact, the basic way to load a task is a simple one-liner using Grunt's loadNpmTasks method.

The syntax is:

grunt.loadNpmTasks('name-of-task'),

The name-of-task, as shown in the example, would be the name of the task as defined in sample_project's package.json devDependencies object. So, for instance, to load grunt-contrib-uglify we would specify it as the argument in the loadNpmTasks method like this:

grunt.loadNpmTasks('grunt-contrib-uglify'),

Using the LoadNpmTasks method

A little about loadNpmTasks. The loadNpmTasks method is a method that loads plugins installed locally with NPM (it will not load tasks installed via other means) and that have been installed relative to the gruntfile. In order to load tasks not installed with NPM, one would use grunt.loadTasks, an alias for grunt.task.loadTasks. Additionally, for tasks that have been installed with NPM, one may also use grunt.task.loadNpmTasks. The alias makes them synonymous. The syntax difference lies in the synonyms:

grunt.loadTasks('name-of-task'),

is the same as:

grunt.task.loadTasks('name-of-task'),

we also have to do:

grunt.loadNpmTasks('name-of-task'),

which is the same as:

grunt.task.loadNpmTasks('name-of-task'),

Calling plugins using the loadNpmTasks method

The following will provide the code for loading each plugin we are using in the sample_project. Note that we installed all of the plugins using NPM, so we will use the loadNpmTasks method for each plugin.

contrib-jshint plugin:

grunt.loadNpmTasks('grunt-contrib-jshint'),

contrib-uglify plugin:

grunt.loadNpmTasks('grunt-contrib-uglify'),

contrib-less plugin:

grunt.loadNpmTasks('grunt-contrib-less'),

contrib-imagemin plugin:

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

contrib-notify plugin:

grunt.loadNpmTasks('grunt-notify'),

contrib-open plugin:

grunt.loadNpmTasks('grunt-open'),

contrib-watch plugin:

grunt.loadNpmTasks('grunt-contrib-watch'),

For this style of loading, all of the loadNpmTasks calls are placed after the configuration section, as follows:

  grunt.loadNpmTasks('grunt-contrib-jshint'),
  grunt.loadNpmTasks('grunt-contrib-uglify'),
  grunt.loadNpmTasks('grunt-contrib-less'),
  grunt.loadNpmTasks('grunt-contrib-imagemin'),
  grunt.loadNpmTasks('grunt-contrib-watch'),
  grunt.loadNpmTasks('grunt-notify'),
  grunt.loadNpmTasks('grunt-open'),

Using the devDependencies object looping method

While this is the way in which Grunt documents the usage of loadNpmTasks, there is a more elegant way. By looping through the devDependencies object to get each one of the dependencies defined within, all of the tasks may be loaded without the need to explicitly load each one. This is done simply with the following syntax:

Object.keys(require('./package.json').devDependencies).forEach(function(dep) {
grunt.loadNpmTasks(dep);
});

Let's break this down. Object is the object which contains the properties (or, in this case, tasks properties) that we wish to use. We will use the Object's keys method to return only the names of the properties, which will be the tasks listed as dependencies in devDependencies. Require includes a defined file and require (./package.json).devDependencies returns the devDependencies object in package.json, which is then looped over for each property and returned and loaded with grunt.loadNpmTasks on each iteration of the loop. Using this approach we could add and remove tasks from package.json and config without having to worry about loading. However, in our case using the Angular-Seed project, there are many tasks in devDependencies that we do not need within our automated build process. For this reason it will be better to explicitly load each task.

At this time our Gruntfile.js 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']
      }
    },
  });
  
  grunt.loadNpmTasks('grunt-contrib-jshint'),
  grunt.loadNpmTasks('grunt-contrib-uglify'),
  grunt.loadNpmTasks('grunt-contrib-less'),
  grunt.loadNpmTasks('grunt-contrib-imagemin'),
  grunt.loadNpmTasks('grunt-contrib-watch'),
  grunt.loadNpmTasks('grunt-notify'),
  grunt.loadNpmTasks('grunt-open'),
};

We have just one more item to add in order to complete our automated build. This is to create our custom and default tasks. While sample_project won't use a custom task, per se, an example of what this is and why we might want to use one or more custom tasks will be discussed in the next section.

..................Content has been hidden....................

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