grunt-purifycss

Introduction

Grunt-purifycss is a useful grunt plugin to remove unused css from your files and also detects dynamically added classes in addition to single page web apps. In this short tutorial I am going to demonstrate its usage:

Getting Started

You can install it from the command line: npm install grunt-purifycss --save-dev The flag --save-dev will get it installed in your project's package.json as well.

Lets consider a very basic example which uses bootstrap and some custom css files. Heres the project structure:-

.
├── css
│   ├── bootstrap.css
│   └── custom.css
├── images
│   ├── browsersync.jpg
│   └── css.jpg
├── index.html
└── js
    └── jquery.js

I have written some demo html content inside the project which utilizes some bootstrap css classes as well as styles from custom.css. If you are interested, I have created a quick codepen demo

Your Gruntfile.js just be configured for the src paths of html and its css paths and the destination of where to write the new lighter css file.

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    purifycss: {
      options: {

      },
      target: {
        src: ['src/*.html'], // Observe all html files
        css: ['src/css/*.css'], // Take all css files into consideration
        dest: 'dest/tmp.css' // Write to this path
      }
    }
  });

  grunt.registerTask('default', ['purifycss']);
};

After running grunt from the command line:

$ grunt
Running "purifycss:target" (purifycss) task
Source Files:  [ 'src/index.html' ]
Style Files:  [ 'src/css/bootstrap.css', 'src/css/custom.css' ]
##################################
Before purify, CSS was 124374 chars long.
After purify, CSS is 10680 chars long. (11.6 times smaller)
##################################
This function took:  1330 ms
File "dest/tmp.css" created.

If you open up dest/tmp.css it will contain css classes used by index.html and all the bloated css code from bootstrap has been removed.

CSS in Javascript

Grunt-purifycss also handles css classes injected using javascript and supports angular templates, React and most of the popular frameworks.

Heres a simple example of js which adds css classes:

$(document).ready(function() {
  $('.m-t').on('click', function() {
    $(this).addClass('m-2t');
  });
});

If you run grunt over here, the tmp.css file that is generated will also contain .m-2t, purifycss works with all javascript frameworks.

Integrating with grunt-usemin

Most of the front-end projects will already have a build process associated with it for concatenation, minification, htmlrevisions, etc. We have already covered grunt-usemin before which uses html comments configuration to decide which files to concat, minify, and revision. We will cover how to integrate purifycss with usemin.

Lets add build configurations in our index.html

CSS:

  <!-- build:css css/styles.css -->
  <link rel="stylesheet" href="css/bootstrap.css">
  <link rel="stylesheet" href="css/custom.css">
  <!-- endbuild -->

Javascript:

<!-- build:js js/script.js -->
  <script src="js/jquery.js"></script>
  <script>
    $(document).ready(function() {
      $('.m-t').on('click', function() {
        $(this).addClass('m-2t');
      });
    });
  </script>
  <!-- endbuild -->

Lets consider a the our configuration Gruntfile.js for usemin:

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    clean: ['dist'],
    copy: {
      generated: {
        src: 'src/index.html',
        dest: 'dist/index.html'
      }
    },
    filerev: {
      options: {
        encoding: 'utf8',
        algorithm: 'md5',
        length: 20
      },
      source: {
        files: [{
          src: [
            'dist/js/*.js',
            'dist/css/*.css'
          ]
        }]
      }
    },
    useminPrepare: {
      html: 'src/index.html',
      options: {
        dest: 'dist'
      }
    },
    usemin: {
      html: 'dist/index.html',
      options: {
        assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js']
      }
    },
    htmlmin: {
      dist: {
        options: {
          removeComments: true,
          collapseWhitespace: true
        },
        files: {
          'dist/index.html': 'dist/index.html'
        }
      }
    }
  });

  grunt.registerTask('default', [
      'clean',
      'copy:generated',
      'useminPrepare',
      'concat',
      'uglify',
      'cssmin',
      'filerev',
      'usemin',
      'htmlmin'
  ]);
};

The above Gruntfile.js will clean your dist folder, concat & minify all js, css assets according config specified in html, put revisions, minify html and copy new folder structure to dist.

Our purifycss step should be after concat step of usemin:

grunt.registerTask('default', [
    'clean',
    'copy:generated',
    'useminPrepare',
    'concat',
    'purifycss', // <---
    'uglify',
    'cssmin',
    'filerev',
    'usemin',
    'htmlmin'
]);

And our purifycss task as well:

purifycss: {
  options: {

  },
  target: {
    src: ['src/index.html', '.tmp/concat/js/*.js'],
    css: ['.tmp/concat/css/*.css'],
    dest: '.tmp/concat/css/styles.css'
  }
},

After running grunt,

$ grunt
Running "clean:0" (clean) task
>> 1 path cleaned.

Running "copy:generated" (copy) task
Copied 1 file

Running "useminPrepare:html" (useminPrepare) task
Configuration changed for concat, uglify, cssmin

Running "concat:generated" (concat) task
File .tmp\concat\css\styles.css created.
File .tmp\concat\js\script.js created.

Running "purifycss:target" (purifycss) task
Source Files:  [ 'src/index.html' ]
Source Files:  [ '.tmp/concat/js/script.js' ]
Style Files:  [ '.tmp/concat/css/styles.css' ]
##################################
Before purify, CSS was 124406 chars long.
After purify, CSS is 27684 chars long. (4.4 times smaller)
##################################
This function took:  1951 ms
File ".tmp/concat/css/styles.css" created.

Running "uglify:generated" (uglify) task
>> 1 file created.

Running "cssmin:generated" (cssmin) task
>> 1 file created. 27.68 kB → 20.99 kB

Running "filerev:source" (filerev) task
Revved 2 files

Running "usemin:html" (usemin) task
Replaced 1 reference to assets

Running "htmlmin:dist" (htmlmin) task
Minified 1 files

Done, without errors.

Note that this currently only works only for 1 css file, and I am working on a quick fix to resolve that.

Found something wrong in the above article, send a pull request in the github repo or notify in the comments below. I will also love to hear about your usage of grunt-purifycss in your projects.

Readme for the Grunt task

grunt-purifycss

Clean unnecessary CSS with PurifyCSS

Getting Started

This plugin requires Grunt ~0.4.5

If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:

npm install grunt-purifycss --save-dev

Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:

grunt.loadNpmTasks('grunt-purifycss');

The "purifycss" task

Usage Examples

In this example, the default options are to specify a target with src files, style files, and an output destination. The plugin will search for style selectors used in the source files, and then output a trimmed down style sheet.

grunt.initConfig({
  purifycss: {
    options: {},
    target: {
      src: ['test/fixtures/*.html', 'test/fixtures/*.js'],
      css: ['test/fixtures/*.css'],
      dest: 'tmp/purestyles.css'
    },
  },
});

Contributing

In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using Grunt.

Readme for the Purifycss

Join the chat at https://gitter.im/purifycss/purifycss

PurifyCSS

A function that takes content (HTML/JS/PHP/etc) and CSS, and returns only the used CSS.

PurifyCSS does not modify the original CSS files. You can write to a new file, like minification.

If your application is using a CSS framework, this is especially useful as many selectors are often unused.




Potential reduction

  • Bootstrap file: ~140k
  • App using ~40% of selectors.
  • Minified: ~117k
  • Purified + Minified: ~35k




Used selector detection

Statically analyzes your code to pick up which selectors are used.

But will it catch all of the cases?

Let's start off simple.

Detecting the use of: button-active

  <!-- html -->
  <!-- class directly on element -->
  <div class="button-active">click</div>
  // javascript
  // Anytime your class name is together in your files, it will find it.
  $(button).addClass('button-active');


Now let's get crazy.

Detecting the use of: button-active

  // Can detect if class is split.
  var half = 'button-';
  $(button).addClass(half + 'active');

  // Can detect if class is joined.
  var dynamicClass = ['button', 'active'].join('-');
  $(button).addClass(dynamicClass);

  // Can detect various more ways, including all Javascript frameworks.
  // A React example.
  var classes = classNames({
    'button-active': this.state.buttonActive
  });

  return (
    <button className={classes}>Submit</button>;
  );




Usage at Build Time

Grunt

Gulp

webpack




Standalone Usage

Install

npm install --save purify-css

Require

var purify = require('purify-css');




Examples


Example with source strings
var content = '<button class="button-active"> Login </button>';
var css = '.button-active { color: green; }   .unused-class { display: block; }';

console.log(purify(content, css));

logs out:

.button-active { color: green; }


Example with glob file patterns + writing to a file
var content = ['**/src/js/*.js', '**/src/html/*.html'];
var css = ['**/src/css/*.css'];

var options = {
  // Will write purified CSS to this file.
  output: './dist/purified.css'
};

purify(content, css, options);


Example with both glob file patterns and source strings + minify + logging rejected selectors
var content = ['**/src/js/*.js', '**/src/html/*.html'];
var css = '.button-active { color: green; } .unused-class { display: block; }';

var options = {
  output: './dist/purified.css',

  // Will minify CSS code in addition to purify.
  minify: true,

  // Logs out removed selectors.
  rejected: true
};

purify(content, css, options);

logs out:

.unused-class


Example with callback
var content = ['**/src/js/*.js', '**/src/html/*.html'];
var css = ['**/src/css/*.css'];

purify(content, css, function (purifiedResult) {
  console.log(purifiedResult);
});


Example with callback + options
var content = ['**/src/js/*.js', '**/src/html/*.html'];
var css = ['**/src/css/*.css'];

var options = {
  minify: true
};

purify(content, css, options, function (purifiedAndMinifiedResult) {
  console.log(purifiedAndMinifiedResult);
});




API in depth

// Four possible arguments.
purify(content, css, options, callback);


The content argument
Type: Array or String

Array of glob file patterns to the files to search through for used classes (HTML, JS, PHP, ERB, Templates, anything that uses CSS selectors).

String of content to look at for used classes.


The css argument
Type: Array or String

Array of glob file patterns to the CSS files you want to filter.

String of CSS to purify.


The (optional) options argument
Type: Object
Properties of options object:
  • minify: Set to true to minify. Default: false.

  • output: Filepath to write purified CSS to. Returns raw string if false. Default: false.

  • info: Logs info on how much CSS was removed if true. Default: false.

  • rejected: Logs the CSS rules that were removed if true. Default: false.

  • whitelist Array of selectors to always leave in. Ex. ['button-active', '*modal*'] this will leave any selector that includes modal in it and selectors that match button-active. (wrapping the string with *'s, leaves all selectors that include it)


The (optional) callback argument
Type: Function

A function that will receive the purified CSS as it's argument.

Example of callback use
purify(content, css, options, function(purifiedCSS){
  console.log(purifiedCSS, ' is the result of purify');
});
Example of callback without options
purify(content, css, function(purifiedCSS){
  console.log('callback without options and received', purifiedCSS);
});




CLI Usage

$ npm install -g purify-css
$ purifycss
usage: purifycss <css> <content> [option ...]

options:
 --min                Minify CSS
 --out [filepath]     Filepath to write purified CSS to
 --info               Logs info on how much CSS was removed
 --rejected           Logs the CSS rules that were removed

 -h, --help           Prints help (this message) and exits


Example CLI Usage
$ purifycss src/css/main.css src/css/bootstrap.css src/js/main.js --min --info --out src/dist/index.css

This will concat both main.css and bootstrap.css and purify it by looking at what CSS selectors were used inside of main.js. It will then write the result to dist/index.css

The --min flag minifies the result.

The --info flag will print this to stdout:

##################################
PurifyCSS has reduced the file size by ~35.2%
##################################

The CLI currently does not support file patterns.

grunt-contrib-compress

Introduction

Grunt-contrib-compress is the official grunt-js plugin from Grunt Team to zip or tar your whole project or a part of your project file and folders. In this short tutorial I am going to demonstrate its usage:

Getting Started

You can install it from the command line: npm install grunt-contrib-compress --save-dev The flag --save-dev will get it installed in your project's package.json as well.

Lets consider a very basic example where we have to just zip the project folder.

 assets
├── css
│   ├── bootstrap.css
│   └── custom.css
├── images
│   └── browsersync.jpg
├── index.html
└── js
    ├── angular.min.js
    ├── bootstrap.min.js
    └── jquery.js

Heres our Gruntfile.js

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    compress: {
      main: {
        options: {
          archive: 'project.zip',
          pretty: true
        },
        expand: true,
        cwd: 'assets/',
        src: ['**/*'],
        dest: '/'
      }
    }
  });

  grunt.registerTask('default', ['compress']);
};

On running grunt:-

$ grunt
Running "compress:main" (compress) task
Created project.zip (278018 bytes)

Done, without errors.

You will find a project.zip folder in your main directory which when unzipped will contain the css, js and images folder same as in the original.

Configurations

Lets say you wanted to configure the way the zip folder is created or you want to create a tar, all these options are available in grunt-contrib-compress.

One of the things that you can configure is the name of the zip folder that is being generated. archive option also accepts functions which returns strings.

options: {
  archive: function() {
    return 'project' + (new Date()).getTime() + '.zip'
  }
}

Lets consider a case where we want to only compress only the javascript and the css files and you have a server that handles CDN and only accepts folder names of 'scripts' and 'styles'.

You can use this the Globbing patterns for files available in this grunt plugin.

Below is the configuration that will be required in order to do that. The dest parameter controls the destination folder for the zipped files, expand makes sure the file folder structure is preserved.

compress: {
  main: {
    options: {
      archive: 'project.zip'
    },
    files: [{
      cwd: 'assets/css/',
      expand: true,
      src: ['**/*'],
      dest: 'styles'
    }, {
      cwd: 'assets/js/',
      expand: true,
      src: ['**/*'],
      dest: 'scripts'
    }]
  }
}

On unzipping, this is the project structure:

project
├── scripts
│   ├── angular.min.js
│   ├── bootstrap.min.js
│   └── jquery.js
└── styles
    ├── bootstrap.css
    └── custom.css

Found something wrong in the above article, send a pull request in the github repo or notify in the comments below. I will also love to hear about your usage of grunt-contrib-compress in your projects.

Readme for the Grunt task

grunt-contrib-compress v1.3.0 Build Status: Linux Build Status: Windows

Compress files and folders

Getting Started

If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:

npm install grunt-contrib-compress --save-dev

Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:

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

This plugin was designed to work with Grunt >= 0.4.x. If you're still using grunt v0.3.x it's strongly recommended that you upgrade, but in case you can't please use v0.3.2.

Compress task

Run this task with the grunt compress command.

Task targets, files and options may be specified according to the grunt Configuring tasks guide.

Node Libraries Used: archiver (for zip/tar) zlib (for gzip).

Options

archive

Type: String or Function
Modes: zip tar

This is used to define where to output the archive. Each target can only have one output file. If the type is a Function it must return a String.

This option is only appropriate for many-files-to-one compression modes like zip and tar. For gzip for example, please use grunt's standard src/dest specifications.

mode

Type: String

This is used to define which mode to use, currently supports gzip, deflate, deflateRaw, tar, tgz (tar gzip) and zip.

Automatically detected per dest:src pair, but can be overridden per target if desired.

level

Type: Integer
Modes: zip gzip
Default: 1

Sets the level of archive compression.

pretty

Type: Boolean
Default: false

Pretty print file sizes when logging.

File Data

The following additional keys may be passed as part of a dest:src pair when using an Archiver-backed format. All keys can be defined as a Function that receives the file name and returns in the type specified below.

date

Type: Date
Modes: zip tar tgz

Sets the file date.

mode

Type: Integer
Modes: zip tar tgz

Sets the file permissions.

store

Type: Boolean
Default: false

If true, file contents will be archived without compression.

comment

Type: String
Modes: zip

Sets the file comment.

gid

Type: Integer Modes: tar tgz

Sets the group of the file in the archive

uid

Type: Integer Modes: tar tgz

Sets the user of the file in the archive

Usage Examples

// make a zipfile
compress: {
  main: {
    options: {
      archive: 'archive.zip'
    },
    files: [
      {src: ['path/*'], dest: 'internal_folder/', filter: 'isFile'}, // includes files in path
      {src: ['path/**'], dest: 'internal_folder2/'}, // includes files in path and its subdirs
      {expand: true, cwd: 'path/', src: ['**'], dest: 'internal_folder3/'}, // makes all src relative to cwd
      {flatten: true, src: ['path/**'], dest: 'internal_folder4/', filter: 'isFile'} // flattens results to a single level
    ]
  }
}
// gzip assets 1-to-1 for production
compress: {
  main: {
    options: {
      mode: 'gzip'
    },
    expand: true,
    cwd: 'assets/',
    src: ['**/*'],
    dest: 'public/'
  }
}
// compress a file to a different location than its source
// example compresses path/the_file to /the_file inside archive.zip
compress: {
  main: {
    options: {
      archive: 'archive.zip'
    },
  files: [
    {expand: true, cwd: 'path/', src: ['the_file'], dest: '/'}
    ]
  }
},
// use custom extension for the output file
compress: {
  main: {
    options: {
      mode: 'gzip'
    },
    files: [
      // Each of the files in the src/ folder will be output to
      // the dist/ folder each with the extension .gz.js
      {expand: true, src: ['src/*.js'], dest: 'dist/', ext: '.gz.js'}
    ]
  }
}

// use a function to return the output file
compress: {
  main: {
    options: {
      archive: function () {
        // The global value git.tag is set by another task
        return git.tag + '.zip'
      }
    },
    files: [
      {expand: true, src: ['src/*.js'], dest: 'dist/'}
    ]
  }
}

Release History

  • 2016-05-24   v1.3.0   Update to Archiver 1.0. Fix node 6 support.
  • 2016-03-24   v1.2.0   Dependency update.
  • 2016-03-08   v1.1.1   Fix verbose output.
  • 2016-03-04   v1.1.0   Add ability to replace file in the same location.
  • 2016-02-15   v1.0.0   Update archiver, chalk and pretty-bytes.
  • 2015-10-23   v0.14.0   Change to verbose output. Dependency updates archiver 0.16.
  • 2014-12-25   v0.13.0   Update archiver to v0.13. Small fixes.
  • 2014-09-23   v0.12.0   Output update. Prevent zipping dot files and allow for forcing through fail.warn within loop.
  • 2014-08-26   v0.11.0   Update archiver to v0.11.0.
  • 2014-07-14   v0.10.0   Don't apply extensions automatically (use ext or rename).
  • 2014-05-20   v0.9.1   Allow directories to pass-through to archiver via filter.
  • 2014-05-20   v0.9.0   Update archiver to v0.9.0.
  • 2014-04-09   v0.8.0   Update archiver to v0.8.0.
  • 2014-02-17   v0.7.0   Update archiver to v0.6.0.
  • 2014-01-12   v0.6.0   Update archiver to v0.5.0.
  • 2013-11-27   v0.5.3   Allow archive option to be a function.
  • 2013-06-03   v0.5.2   Allow custom extensions using the ext option.
  • 2013-05-28   v0.5.1   Avoid gzip on folders.
  • 2013-04-23   v0.5.0   Add support for deflate and deflateRaw.
  • 2013-04-15   v0.4.10   Fix issue where task finished before all data was compressed.
  • 2013-04-09   v0.4.9   Bump Archiver version.
  • 2013-04-07   v0.4.8   Open streams lazily to avoid too many open files.
  • 2013-04-01   v0.4.7   Pipe gzip to fix gzip issues. Add tests that undo compressed files to test.
  • 2013-03-25   v0.4.6   Fix Node.js v0.8 compatibility issue with gzip.
  • 2013-03-20   v0.4.5   Update to archiver 0.4.1 Fix issue with gzip failing intermittently.
  • 2013-03-19   v0.4.4   Fixes for Node.js v0.10. Explicitly call grunt.file methods with map and filter.
  • 2013-03-14   v0.4.3   Fix for gzip; continue iteration on returning early.
  • 2013-03-13   v0.4.2   Refactor task like other contrib tasks. Fix gzip of multiple files. Remove unused dependencies.
  • 2013-02-22   v0.4.1   Pretty print compressed sizes. Logging each addition to a compressed file now only happens in verbose mode.
  • 2013-02-15   v0.4.0   First official release for Grunt 0.4.0.
  • 2013-01-23   v0.4.0rc7   Updating grunt/gruntplugin dependencies to rc7. Changing in-development grunt/gruntplugin dependency versions from tilde version ranges to specific versions.
  • 2013-01-14   v0.4.0rc5   Updating to work with grunt v0.4.0rc5. Conversion to grunt v0.4 conventions. Replace basePath with cwd.
  • 2012-10-12   v0.3.2   Rename grunt-contrib-lib dep to grunt-lib-contrib.
  • 2012-10-09   v0.3.1   Replace zipstream package with archiver.
  • 2012-09-24   v0.3.0   General cleanup. Options no longer accepted from global config key.
  • 2012-09-18   v0.2.2   Test refactoring. No valid source check. Automatic mode detection.
  • 2012-09-10   v0.2.0   Refactored from grunt-contrib into individual repo.

Task submitted by Chris Talkington

This file was generated on Tue May 24 2016 13:48:49.

grunt-browser-sync

Introduction

Grunt-Browser-Sync is the official grunt-js plugin from BrowserSync to reload your browser on any css file changes. It can create its own server or hook into an existing server. BrowserSync also automatically reloads all tabs which are dependent on that css file which enables you to work seamlessly with multiple devices. If you haven't started using browsersync its recommended you should.

In this tutorial I am going to demonstrate its usage with Grunt.

Getting Started

You can install it from the command line: npm install grunt-browser-sync --save-dev The flag --save-dev will get it installed in your project's package.json as well.

For the first example we will consider a very basic html webpage linked to to 2 css files. On making a change inside the css file, all tabs with that html file open should refresh enabling us to quickly change properties.

Heres the Gruntfile.js for that:

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    browserSync: {
      bsFiles: {
        src: 'css/*.css'
      },
      options: {
        server: {
          baseDir: './'
        }
      }
    }
  });

  grunt.registerTask('default', ['browserSync']);
};

On running grunt from the command line:

$ grunt
Running "browserSync:bsFiles" (browserSync) task
[BS] Access URLs:
 -------------------------------------
       Local: http://localhost:3000
    External: http://192.168.1.33:3000
 -------------------------------------
          UI: http://localhost:3001
 UI External: http://192.168.1.33:3001
 -------------------------------------
[BS] Serving files from: ./
[BS] Watching files...

Now you can open up the same url in multiple browsers as well as visit 192.168.1.33:3000 from your smartphone. Once you change anything inside custom.css all the tabs will reload. BrowserSync also has the ability to sync scroll, form, refresh actions and also provides you with a control panel UI. screenshot

External Server

Many a times we will have an external server built on express / php / django / rails and we want to use BrowserSync and grunt with it. Sweat not! BrowserSync has this support built-in using its proxy featured.

This is the only option that you need to change:

options: {
  proxy: 'localhost:80'
}

You can even add port, logs watchOptions and middlewares.

Here is the full list of options.

Found something wrong in the above article, send a pull request in the github repo or notify in the comments below. I will also love to hear about your cool hacks around grunt-image-embed.

Readme for the Grunt task

grunt-browser-sync NPM version

A grunt task for the browser-sync module.

Follow @browserSync for news & updates.

Getting Started

This plugin requires Grunt ~0.4.1

If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins.

About

For a full list of features, please visit https://github.com/shakyShane/browser-sync

Install

npm install grunt-browser-sync --save-dev

Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:

grunt.loadNpmTasks('grunt-browser-sync');

Usage

Please see the Grunt JS section of the Official BrowserSync Documentation.

Support

If you've found Browser-sync useful and would like to contribute to its continued development & support, please feel free to send a donation of any size - it would be greatly appreciated!

Support via Gittip Support via PayPal

Contributing

In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using Grunt.

grunt-image-embed

Introduction

Grunt-image-embed is a superb grunt-js plugin for converting your images in your stylesheets to base64 encoded data URI strings to reduce HTTP requests. This plugin is extremely useful if you want to improve pagespeed by converting your small images / icons into data URIs which reduces the number of calls and thus decrease the loading time.

Getting Started

You can install it from the command line: npm install grunt-image-embed --save-dev The flag --save-dev will get it installed in your project's package.json as well.

For the first basic example we will consider a simple stylesheet which references an image from local folder and an image from remote url. Using the below configuration you should be able to convert them into data URIs. You will be able to use that

Heres the Gruntfile.js for that:

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    imageEmbed: {
      dist: {
        src: ['css/custom.css'],
        dest: 'css/output.css'
      }
    }
  });

  grunt.registerTask('default', 'imageEmbed');
};

The above task will scan your css/custom.css file and convert all the images into data URIs. On running grunt:

$ grunt
Running "imageEmbed:dist" (imageEmbed) task
Encoding file: images\grunt-logo.png
Encoding file: http://jquer.in/favicons/apple-touch-icon-57x57.png
File "css/output.css" created.

Previously, this is what custom.css looked like:

.grunt {
  width: 128px;
  height: 128px;
  background: url('../images/grunt-logo.png') no-repeat;
}

After running grunt, this what output.css looks like:

.grunt {
  width: 128px;
  height: 128px;
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABGdBTUEAALGPC/.....5CYII=) no-repeat;
}

There, you should reduced 2 additional HTTP requests.

Usage with grunt-usemin

Grunt-usemin is an excellent starting point for those looking to automate their front-end development workflows, it provides all the basic tools necessary for scaffolding a basic grunt project. We had earlier covered grunt-usemin before.

Grunt Usemin consists of two tasks useminPrepare which will prepare your scaffolding or generate the grunt code for concat, uglify, cssmin, filerev and later usemin which will actually do the replacement and should be called later.

The concat task creates a .tmp directory with the following structure:-

.tmp
└── concat
    ├── css
    └── js

We have to use our task grunt-image-embed after concat:generated task in grunt-usemin, this can be done by registerTask function by changing the order of the tasks called. Here's the relevant snippet:

'copy:generated',
'useminPrepare',
'concat',
'imageEmbed',

One more thing to be added to the .tmp folder will be your relevant image assets because grunt-image-embed won't work for local assets unless it finds the relative paths. This can be easily done by grunt-contrib-copy. Here is the relevant snippet of code:

copy: {
  cwd: 'images/',
  src: '**/*',
  dest: '.tmp/concat/images',
  expand: true
}

The above code will look inside your images folder and copy the relevant tree or file-folder structure as it is to .tmp/concat/images

The final Gruntfile.js using grunt-usemin and grunt-image-embed

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    imageEmbed: {
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/concat',
          src: ['css/*.css'],
          dest: '.tmp/concat'
        }]
      }
    },
    copy: {
      generated: {
        files: [{
          src: 'index.html',
          dest: 'dist/index.html'
        }, {
          cwd: 'images/',
          src: '**/*',
          dest: 'dist/images',
          expand: true
        }, {
          cwd: 'images/',
          src: '**/*',
          dest: '.tmp/concat/images',
          expand: true
        }]
      }
    },
    filerev: {
      options: {
        encoding: 'utf8',
        algorithm: 'md5',
        length: 20
      },
      source: {
        files: [{
          src: [
            'dist/js/*.js',
            'dist/css/*.css'
          ]
        }]
      }
    },
    useminPrepare: {
      html: 'index.html',
      options: {
        dest: 'dist'
      }
    },
    usemin: {
      html: 'dist/index.html',
      options: {
        assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js']
      }
    },
    htmlmin: {
      dist: {
        options: {
          removeComments: true,
          collapseWhitespace: true
        },
        files: {
          'dist/index.html': 'dist/index.html'
        }
      }
    }
  });

  grunt.registerTask('default', [
      'copy:generated',
      'useminPrepare',
      'concat',
      'imageEmbed',
      'uglify',
      'cssmin',
      'filerev',
      'usemin',
      'htmlmin',
  ]);
};

On running grunt:

$ grunt
Running "copy:generated" (copy) task
Copied 3 files

Running "useminPrepare:html" (useminPrepare) task
Configuration changed for concat, uglify, cssmin

Running "concat:generated" (concat) task
File .tmp\concat\css\styles.css created.
File .tmp\concat\js\scripts.js created.

Running "imageEmbed:dist" (imageEmbed) task
Encoding file: .tmp\concat\images\grunt-logo.png
Encoding file: http://jquer.in/favicons/apple-touch-icon-57x57.png
File ".tmp/concat/css/styles.css" created.

Running "uglify:generated" (uglify) task
>> 1 file created.

Running "cssmin:generated" (cssmin) task

Running "filerev:source" (filerev) task
Revved 4 files

Running "usemin:html" (usemin) task
Replaced 1 reference to assets

Running "htmlmin:dist" (htmlmin) task
Minified 1 files

Done, without errors.

Using this grunt configuration, you have concatenated, minified and revisioned your css and js files, minified your html file as well as replaced your background images by data-uris.

Found something wrong in the above article, send a pull request in the github repo or notify in the comments below. I will also love to hear about your cool hacks around grunt-image-embed.

Readme for the Grunt task

Grunt Image Embed

This task converts all data found within a stylesheet (those within a url( ... ) declaration) into base64-encoded data URI strings. This includes images and fonts.

Created by Eric Hynds @erichynds with major contributions from dancingplatypus.

Features

  • Supports both local & remote images.
  • Ability to specify a size limit. Default is 32kb which is IE8's limit.
  • Existing data URIs will be ignored.
  • Skip specific images by specifying a directive comment.
  • Ability to purge images that have been encoded
  • Includes two helpers: encode_stylesheet to encode a stylesheet, and encode_image to encode an image.

Getting Started

Install this plugin with the command:

npm install grunt-image-embed

Next, add this line to your project's grunt file:

grunt.loadNpmTasks("grunt-image-embed");

Lastly, add configuration settings to your grunt.js file (see below).

Documentation

This task has two required properties, src and dest. src is the path to your stylesheet and dest is the file this task will write to (relative to the grunt.js file). If this file already exists it will be overwritten.

An example configuration looks like this:

grunt.initConfig({
  imageEmbed: {
    dist: {
      src: [ "css/styles.css" ],
      dest: "css/output.css",
      options: {
        deleteAfterEncoding : false,
        preEncodeCallback: function (filename) { return true; }
      }
    }
  }
});

Optional Configuration Properties

ImageEmbed can be customized by specifying the following options:

  • maxImageSize: The maximum size of the base64 string in bytes. This defaults to 32768, or IE8's limit. Set this to 0 to remove the limit and allow any size string.

  • baseDir: If you have absolute image paths in your stylesheet, the path specified in this option will be used as the base directory.

  • deleteAfterEncoding: Set this to true to delete images after they've been encoded. You'll want to do this in a staging area, and not in your source directories. Be careful.

  • preEncodeCallback: function that takes full path to the image to be encoded and returns either true (proceeed with default encoding), false (abort the encoding, fail with error) or String, which will be used as the result of the encoding.

  • regexInclude - Regular expression testing against file types to include. Defaults to all (/.*/g). To only include images, you might set this to /\.(jpg|png|gif|jpeg)/gi.

  • regexExclude - Regular expression testing against file types to exclude. Defaults to none (``/$^/g). To exclude fonts for example, you might set this to/.(eot|woff|ttf|svg)/gi`.

Skipping Images

Specify that an image should be skipped by adding the following comment directive after the image:

background: url(image.gif); /*ImageEmbed:skip*/

Compatibility

Version >= 0.3.0 of this plugin is compatible with Grunt 0.4.x. Versions 0.0.1 through 0.2.0 are only compatible with Grunt 0.3.x.

License

Copyright (c) 2013 Eric Hynds (@erichynds) Licensed under the MIT License.

time-grunt

Introduction

time-grunt is a utility grunt plugin from Sindre Sorhus for calculating the time it took for each task in executing your grunt build setup. Additionally it can be used to pass the timing stats for your own analysis.

Getting Started

Lets consider Gruntfile.js from the previous post which utilizes grunt-usemin and grunt-contrib-html to minify, concat, revision your static assets as well as minify html file. First you will need to install it

npm install time-grunt --save-dev

All you need is to add the below line to get time statistics:

require('time-grunt')(grunt);

On running grunt from the command line:

Execution Time (2015-05-09 08:33:15 UTC)
uglify:generated  16.2s  █████████████████████████████████████████████████████████████ 91%
cssmin:generated     1s  ████ 6%
Total 17.7s

You might find out that tasks that less than 1% are hidden to reduce the clutter.

On running grunt --verbose you will get the whole output:

Execution Time (2015-05-09 08:34:53 UTC)
loading tasks        20ms  0%
copy:generated       90ms  █ 1%
useminPrepare:html  100ms  █ 1%
concat:generated     90ms  █ 1%
uglify:generated     8.8s  ███████████████████████████████████████████████████████████ 91%
cssmin:generated    490ms  ████ 5%
filerev:source       30ms  0%
usemin:html          50ms  █ 1%
htmlmin:dist         30ms  0%
Total 9.7s

Readme for the Grunt task

grunt-contrib-htmlmin

Introduction

Grunt-contrib-htmlmin is an official plugin from the grunt-js team to minify your project's html source code files before pushing to production with options to remove whitespace and comments.

Getting Started

You can install it from the command line: npm install grunt-contrib-htmlmin --save-dev The flag --save-dev will get it installed in your project's package.json as well.

For the first example we will consider a simple html file which you need to copy and then minify to dist folder. The index file contains some comments, some paragraphs and some buttons.

Heres the Gruntfile.js for that:

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    htmlmin: {
      dist: {
        options: {
          removeComments: true,
          collapseWhitespace: true
        },
        files: {
          'dist/index.html': 'index.html'
        }
      }
    }
  });

  grunt.registerTask('default', ['htmlmin:dist']);
};

On running grunt from the command line, a new index.html is generated in the dist folder.

Original index.html: 2.00 Kb, Minified dist/index.html: 1.43Kb, Savings: 0.57 Kb = 28.5% compression

Using it with grunt usemin

We have earlier covered grunt-usemin which concatenates your css and js files based on comments in your html files. Note that grunt-contrib-htmlmin uses html-minifier in the background for compressing your html files.

You will also need to install the following grunt plugins:

npm install grunt-contrib-copy grunt-contrib-uglify grunt-contrib-concat grunt-contrib-cssmin grunt-usemin grunt-filerev --save-dev

Using the previous grunt usemin Gruntfile.js and adding the grunt-htmlmin task to it:

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    copy: {
      generated: {
        src: 'index.html',
        dest: 'dist/index.html'
      }
    },
    filerev: {
      options: {
        encoding: 'utf8',
        algorithm: 'md5',
        length: 20
      },
      source: {
        files: [{
          src: [
            'dist/js/*.js',
            'dist/css/*.css'
          ]
        }]
      }
    },
    useminPrepare: {
      html: 'index.html',
      options: {
        dest: 'dist'
      }
    },
    usemin: {
      html: 'dist/index.html',
      options: {
        assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js']
      }
    },
    htmlmin: {
      dist: {
        options: {
          removeComments: true,
          collapseWhitespace: true
        },
        files: {
          'dist/index.html': 'dist/index.html'
        }
      }
    }
  });

  grunt.registerTask('default', [
      'copy:generated',
      'useminPrepare',
      'concat',
      'uglify',
      'cssmin',
      'filerev',
      'usemin',
      'htmlmin'
  ]);
};

The above grunt-task will concat, uglify, compress, revision your css.js files, change dependencies in your html, then minify your html files, and then copy those files to your dist folder.

On running grunt:

$ grunt
Running "copy:generated" (copy) task
Copied 1 file

Running "useminPrepare:html" (useminPrepare) task
Configuration changed for concat, uglify, cssmin

Running "concat:generated" (concat) task
File .tmp\concat\css\minified.css created.
File .tmp\concat\js\minified.js created.

Running "uglify:generated" (uglify) task
>> 1 file created.

Running "cssmin:generated" (cssmin) task

Running "filerev:source" (filerev) task
Revved 2 files

Running "usemin:html" (usemin) task
Replaced 1 reference to assets

Running "htmlmin:dist" (htmlmin) task
Minified 1 files

Done, without errors.

From the comments:

It might become cumbersome to specify multiple html files for compressing, Here's the way to automatically do that. Because grunt-contrib-htmlmin doesn't support replacing [issue], we first copy it to .tmp and from there to dist/

Inside htmlmin task:

files: [{
  expand: true,
  cwd: 'dist/',
  src: ['*.html'],
  dest: '.tmp/'
}]

Inside copy task

html: {
  files: [{
    expand: true,
    cwd: '.tmp',
    src: ['*.html'],
    dest: 'dist/'
  }]
}

You will also have to append copy:html as a task in your default task list.

Now, the index.html in dist/ folder will contain no whitespaces and comments. Heres the link to the gist for Gruntfile.js and package.json

Found something wrong in the above article, send a pull request in the github repo or notify in the comments below. I will also love to hear about your cool hacks around grunt-htmlmin.

Readme for the Grunt task

grunt-contrib-htmlmin v2.0.0 Build Status: Linux Build Status: Windows

Minify HTML

Getting Started

If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:

npm install grunt-contrib-htmlmin --save-dev

Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:

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

Htmlmin task

Run this task with the grunt htmlmin command.

Issues with the output should be reported on the htmlmin issue tracker.

Options

See the html-minifier options.

Example

grunt.initConfig({
  htmlmin: {                                     // Task
    dist: {                                      // Target
      options: {                                 // Target options
        removeComments: true,
        collapseWhitespace: true
      },
      files: {                                   // Dictionary of files
        'dist/index.html': 'src/index.html',     // 'destination': 'source'
        'dist/contact.html': 'src/contact.html'
      }
    },
    dev: {                                       // Another target
      files: {
        'dist/index.html': 'src/index.html',
        'dist/contact.html': 'src/contact.html'
      }
    }
  }
});

grunt.registerTask('default', ['htmlmin']);

Release History

  • 2016-07-19   v2.0.0   Updated html-minifier to v3.0.1. Note that Node.js < 4 isn't supported anymore.
  • 2016-07-13   v1.5.0   Updated html-minifier to v2.1.7.
  • 2016-04-19   v1.4.0   Updated html-minifier to v2.0.0.
  • 2016-04-10   v1.3.0   Updated html-minifier to v1.5.0.
  • 2016-03-31   v1.2.0   Updated html-minifier to v1.4.0.
  • 2016-03-18   v1.1.0   Updated html-minifier to v1.3.0.
  • 2016-03-04   v1.0.0   Updated html-minifier to v1.2.0. Point main to task. Drop peerDeps.
  • 2015-10-28   v0.6.0   Updated html-minifier to v1.0.0.
  • 2015-09-25   v0.5.0   Updated html-minifier to v0.8.0.
  • 2015-02-06   v0.4.0   Updated html-minifier to v0.7.0.
  • 2014-05-05   v0.3.0   Drop Node.js 0.8 support. Updated html-minifier to v0.6.0.
  • 2014-02-09   v0.2.0   Rewrite task. Drop concat support.
  • 2013-04-06   v0.1.3   Fail target when minify encounters an error.
  • 2013-04-05   v0.1.2   Update html-minifier which fixes IE conditional comments and prefixed HTML elements <ng-include>, <ng:include>.
  • 2013-02-18   v0.1.1   First official release for Grunt 0.4.0.
  • 2013-01-30   v0.1.1rc7   Updating grunt/gruntplugin dependencies to rc7. Changing in-development grunt/gruntplugin dependency versions from tilde version ranges to specific versions.
  • 2013-01-09   v0.1.1rc5   Updating to work with grunt v0.4.0rc5. Switching to this.filesSrc API.
  • 2012-11-01   v0.1.0   Initial release.

Task submitted by Sindre Sorhus

This file was generated on Tue Jul 19 2016 00:45:48.

grunt-wiredep

Blog post

Grunt wiredep is a quick grunt plugin that helps you inject bower packagers, i.e., links to your dependencies in your front-end source code.

For example, if you have a jade templating system in your project and every time you install a bower module you want to update that in your source code, this is the grunt plugin to use.

The way this works is you define in your html/jade/ the wrapper where you want to include dependencies

<!-- bower:js -->
This is the place where your script tags will be inserted
<!-- endbower -->

Using Bower

You will have to make sure you have bower installed on your machine before starting. If not, it can be installed using:

npm install -g bower

Initiate bower by running:

bower init

Follow the command line tutorial and it will generate your bower.json for your project.

Getting started

From the command line in your project folder run the following:

npm install grunt-wiredep --save-dev

This will make sure that grunt-wiredep is installed a development dependency in your package.json. Here is your Gruntfile.js:

module.exports = function(grunt) {

  grunt.loadNpmTasks('grunt-wiredep');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.initConfig({
    wiredep: {
      task: {
        src: ['index.html']
      }
    }
  });

  grunt.registerTask('default', ['wiredep']);
};

Here is your index.html, you can have configuration in multiple files:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>How to use Grunt Wirdep</title>
  <!-- bower:css -->
  <!-- endbower -->
</head>
<body>
  <!-- bower:js -->
  <!-- endbower -->
</body>
</html>

Now install bootstrap via bower:

bower install bootstrap --save grunt

Now after running grunt wiredep, the bootstrap components will appear in your index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>How to use Grunt Wirdep</title>
  <!-- bower:css -->
  <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
  <!-- endbower -->
</head>
<body>
  <!-- bower:js -->
  <script src="bower_components/jquery/dist/jquery.js"></script>
  <script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>
  <!-- endbower -->
</body>
</html>

Automating

Grunt is all about automating, its become redundant to run two commands of bower install and grunt wiredep everytime we want to install any dependency. The solution is to use grunt-watch to moniter changes over bower_components and run grunt-wiredep everytime something changes.

You will first need to install grunt-watch npm install grunt-contrib-watch --save-dev

And Change your Gruntfile.js to include the watch task:

watch: {
  files: ['bower_components/*'],
  tasks: ['wiredep']
}

grunt.registerTask('changes', ['watch']);

The above 'watch' task will moniter for any changes in bower_components folder and will run the grunt tasks specified in the 'tasks' option.

$ grunt changes
Running "watch" task
Waiting...

Now open the same project folder in another tab in your terminal and install angular-js bower install angular --save

Now go back to the original tab which is running the grunt watch task. You will observe the following output:

>> File "bower_components\angular" added.
Running "wiredep:task" (wiredep) task

Done, without errors.

Our grunt-wiredep task has run after angular folder in bower_components has been created and if you looked at your index.html:

  <script src="bower_components/jquery/dist/jquery.js"></script>
  <script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>
  <script src="bower_components/angular/angular.js"></script>

The angular depedency was automatically included.

Found something wrong in the above article, send a pull request in the github repo or notify in the comments below. I will also love to hear about your cool hacks around grunt-wiredep.

grunt-exec

Blog post

Grunt Exec is a powerful grunt plugin which provides a wrapper over shell (cmd) commands and which can be modified from your Gruntfile.js.

Getting Started

npm install grunt-exec --save-dev

You want to execute a very simple shell command that just outputs hello echo hello

So Here is the Gruntfile.js for that:

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    exec: {
        list_files: {
            cmd: 'echo hello'
        }
    }
  });

  grunt.registerTask('default', ['exec:list_files']);
};

Heres what you get when you run this from the command line:

$ grunt
Running "exec:sayHello" (exec) task
hello

Done, without errors.

More advanced working

Lets say you have a more advanced working environment and when pushing to production you want to delete the temporary files or folders that might have been created.

You might also want to delete npm-debug.log or some other log files that was useful for debuggind but you want it cleaned before pushing to production.

By using grunt-exec removing unnecessary files becomes very easy and you reduce one manual step.

For our example, we will consider a case where you have both a .tmp folder and npm-debug.log file which you want to delete before producionizing.

Here's the project tree before running the task

.
├── Gruntfile.js
├── npm-debug.log
├── .tmp
├── package.json
└── README.md

After executing grunt from the command line:

Running "exec:removeLogs" (exec) task

Running "exec:removeTmp" (exec) task

Done, without errors.

Heres the project tree after running the task

.
├── Gruntfile.js
├── package.json
└── README.md

Here is the corresponding Gruntfile.js

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    exec: {
        removeLogs: {
            cmd: 'rm *.log',
            stderr: false
        },
        removeTmp: {
            cmd: 'rm -rf .tmp',
            stderr: false
        }
    }
  });

  grunt.registerTask('default', ['exec:removeLogs', 'exec:removeTmp']);
};

See how easy it is Every project might have some manual steps, if they can be executed from the shell, you should consider shifting them to grunt-exec. It might save you a good deal of time by automating those small yet important tasks.

I will love to hear about your cool hacks around grunt-exec in the comments below

Readme for the Grunt task

build status

grunt-exec

Grunt plugin for executing shell commands.

NPM NPM

Installation

Install grunt-exec using npm:

$ npm install grunt-exec --save-dev

Then add this line to your project's Gruntfile.js:

grunt.loadNpmTasks('grunt-exec');

Usage

This plugin is a multi task, meaning that grunt will automatically iterate over all exec targets if a target is not specified.

If the exit code generated by the specified shell command is greater than 0, grunt-exec will assume an error has occurred and will abort grunt immediately.

Properties

  • command (alias: cmd): The shell command to be executed. Must be a string or a function that returns a string.
  • stdin: If true, stdin will be redirected from the child process to the current process allowing user interactivity (EXPERIMENTAL)
  • stdout: If true, stdout will be printed. Defaults to true.
  • stderr: If true, stderr will be printed. Defaults to true.
  • cwd: Current working directory of the shell command. Defaults to the directory containing your Gruntfile.
  • exitCode (alias: exitCodes): The expected exit code(s), task will fail if the actual exit code doesn't match. Defaults to 0. Can be an array for multiple allowed exit codes.
  • callback: The callback function passed child_process.exec. Defaults to a noop.
  • options: Options to provide to child_process.exec. NodeJS Documentation
    • cwd String Current working directory of the child process
    • env Object Environment key-value pairs
    • encoding String (Default: 'utf8')
    • shell String Shell to execute the command with (Default: '/bin/sh' on UNIX, 'cmd.exe' on Windows, The shell should understand the -c switch on UNIX or /s /c on Windows. On Windows, command line parsing should be compatible with cmd.exe.)
    • timeout Number (Default: 0)
    • maxBuffer Number largest amount of data (in bytes) allowed on stdout or stderr - if exceeded child process is killed (Default: 200*1024)
    • killSignal String (Default: 'SIGTERM')
    • uid Number Sets the user identity of the process. (See setuid(2).)
    • gid Number Sets the group identity of the process. (See setgid(2).)

If the configuration is instead a simple string, it will be interpreted as a full command itself:

exec: {
  echo_something: 'echo "This is something"'
}

Command Functions

If you plan on doing advanced stuff with grunt-exec, you'll most likely be using functions for the command property of your exec targets. This section details a couple of helpful tips about command functions that could help make your life easier.

Passing arguments from the command line

Command functions can be called with arbitrary arguments. Let's say we have the following exec target that echoes a formatted name:

exec: {
  echo_name: {
    cmd: function(firstName, lastName) {
      var formattedName = [
        lastName.toUpperCase(),
        firstName.toUpperCase()
      ].join(', ');

      return 'echo ' + formattedName;
    }
  }
}

In order to get SIMPSON, HOMER echoed, you'd run grunt exec:echo_name:homer:simpson from the command line.

Accessing grunt object

All command functions are called in the context of the grunt object that they are being ran with. This means you can access the grunt object through this.

Example

The following examples are available in grunt-exec's Gruntfile.

grunt.initConfig({
  exec: {
    remove_logs: {
      command: 'rm -f *.log',
      stdout: false,
      stderr: false
    },
    list_files: {
      cmd: 'ls -l **'
    },
    list_all_files: 'ls -la',
    echo_grunt_version: {
      cmd: function() { return 'echo ' + this.version; }
    },
    echo_name: {
      cmd: function(firstName, lastName) {
        var formattedName = [
          lastName.toUpperCase(),
          firstName.toUpperCase()
        ].join(', ');

        return 'echo ' + formattedName;
      }
    }
  }
});

Testing

$ cd grunt-exec
$ npm test

Issues

Found a bug? Create an issue on GitHub.

https://github.com/jharding/grunt-exec/issues

Versioning

For transparency and insight into the release cycle, releases will be numbered with the follow format:

<major>.<minor>.<patch>

And constructed with the following guidelines:

  • Breaking backwards compatibility bumps the major
  • New additions without breaking backwards compatibility bumps the minor
  • Bug fixes and misc changes bump the patch

For more information on semantic versioning, please visit http://semver.org/.

License

Original Copyright (c) 2012-2014 Jake Harding Copyright (c) 2016 grunt-exec Licensed under the MIT License.

grunt-jsonlint

Blog post

Grunt-jsonlint is a small yet a very useful tool for validating your project json files which might be some static data, some configuration file through the task-runner grunt.

Getting Started

You have the below project folder structure:

├── config
│   └── config.json
├── data
│   └── cities.json
├── Gruntfile.js
├── package.json
└── README.md

Inside the data folder, you have some contants json list inside data for example cities.json, countries.json, currencies.json while inside config folder you will have a json folder containing the credentials/configurations for your project. Now multiple people might be colloborating on the constants and the config files and you need to make sure all your json files are validated. This grunt plugin will validate all your json files so that you dont run into issues in production.

From your command line run:

npm install grunt-jsonlint --save-dev

Lets say you have this config.json:

{
  "configkey1": "configvalue1",
  "configkey2": "configvalue2",
  "configkey3": "configvalue3",
}

After you run grunt from the command line:

$ grunt
Running "jsonlint:sample" (jsonlint) task
>> File "config/config.json" failed JSON validation.
Warning: Parse error on line 4:
...3": "configvalue3",}
----------------------^
Expecting 'STRING', got '}' Use --force to continue.

Aborted due to warnings.

Oops! A typo over there on line3, Lets fix it.

{
  "configkey1": "configvalue1",
  "configkey2": "configvalue2",
  "configkey3": "configvalue3"
}

Running grunt now:

$ grunt
Running "jsonlint:sample" (jsonlint) task
>> 2 files lint free.

Done, without errors.

You just got saved hours from debugging this in production. if you have any json files inside your project you should integrate this plugin.

Would love to know your thoughts in the comments below:

Readme for the Grunt task

grunt-jsonlint Build Status

Validate JSON files from grunt.

Requires grunt 1.0+ and node 4.0+.

Install

npm install grunt-jsonlint --save-dev

Configure

Add the following (multi-)task to your Gruntfile:

jsonlint: {
  sample: {
    src: [ 'some/valid.json' ],
    options: {
      formatter: 'prose'
    }
  }
}

Add the following to load the task into your Gruntfile:

grunt.loadNpmTasks('grunt-jsonlint');

An error will be thrown if the JSON file contains syntax errors. To prefer an error format compatible with Visual Studio, change the formatter to 'msbuild'.

Here's a simple tutorial on how to use grunt-jsonlint

Formatting

Add the following (multi-)task to your Gruntfile:

jsonlint: {
  all: {
    src: [ 'some/valid.json' ],
    options: {
      format: true,
      indent: 2,
    }
  }
}
  • format, when true JSON.stringify will be used to format the JavaScript (if it is valid)
  • indent, the value passed to JSON.stringify, it can be the number of spaces, or string like "\t"

Reporting

There are a few options available for reporting errors:

Error message format

The standard error message format (prose) is optimized for human reading and looks like:

>> File "test/invalid.json" failed JSON validation at line 9.

This is customizable to conform to the Visual Studio style by specifying the formatter option as msbuild, like:

jsonlint: {

  visualStudioExample: {
    src: [ 'test/invalid.json' ],
    options: {
      formatter: 'msbuild'
    }
  }

}

The output will look like:

>> test/invalid.json(9): error: failed JSON validation

Error reporting

By default, the raw error from the underlying jsonlint library comes through to the grunt output. It looks like:

Error: Parse error on line 9:
...        "2"        "3",      ],      
----------------------^
Expecting 'EOF', '}', ':', ',', ']', got 'STRING'

To customize this, change the reporter option to jshint (the format is inspired by how jshint formats their output, hence the name):

jsonlint: {

  jshintStyle: {
    src: [ 'test/invalid.json' ],
    options: {
      reporter: 'jshint'
    }
  }

}

The output will look like:

 9 |     "3"
         ^ Expected 'EOF', '}', ':', ',', ']' and instead saw '3'

The default reporter is called exception since it simply relays the raw exception.

Roadmap

The underlying jsonlint library has many features not yet exposed. Each of these would be valuable in grunt.

  • Schema validation
  • Sort file by key

Running tests

Unit tests are provided for automated regression testing. The easiest way to run them is with

$ npm install
$ npm test

Alternatively, if you have grunt-cli installed, you could use grunt directly with

$ npm install
$ grunt test

Which does the same thing.

Release History

  • 2013-02-20 v1.0.0 First official release
  • 2013-09-19 v1.0.1 Do not log every validated file
  • 2013-10-31 v1.0.2 Add output of count of successfully linted JSON file for issue
  • 2013-11-16 v1.0.3 Fix output of count of successfully linted JSON files.
  • 2013-11-18 v1.0.4 Updated for latest dependencies.
  • 2015-10-11 v1.0.5 Updated for latest dependencies.
  • 2015-10-29 v1.0.6 CJSON support thanks to @fredghosn, unit tests
  • 2015-12-23 v1.0.7 Include file name and JSON source line number in error messages
  • 2016-05-27 v1.0.8 Option to format JSON file thanks to @robblue2x
  • 2016-06-11 v1.1.0 Enhanced error reporting for better human reading and Visual Studio integration.

grunt remove logging calls

Blog post

Grunt Remove logging Calls is a grunt plugin for removing the console logging statements made in your javascript files. You can use this plugin to remove logging for production while also keeping console.log statements for development for better debugging.

There are two plugins for this grunt-remove-logging and grunt-remove-logging-calls. For simple use you should use grunt-remove-logging and for more comprehensive development grunt-remove-logging-calls will be a better option

Getting Started

Depending upon your use case, To install this in your project, run npm install grunt-remove-logging-calls grunt-remove-logging --save-dev

A very simple example would be that you have got this folder structure:

.
├── css
│   ├── bootstrap.css
│   ├── codemirror.css
│   └── mystyle.css
├── Gruntfile.js
├── index.html
├── js
│   ├── bootstrap.min.js
│   ├── jquery.js
│   └── myscript.js
├── package.json
└── README.md

In your myscript.js file you have some simple logging statements:

$(document).ready(function() {
  console.log("document is ready");
  $("#submit").on("click", function() {
    console.log("Submit Button Clicked");
  });
});

You have got some console.log statements for debugging purposes in your js files which you want to remove for production. This can be easily done using grunt-remove-logging-calls.

grunt.initConfig({
  removelogging: {
    dist: {
      files: [{
        expand: true,
        src: ['*.js'],
        cwd: 'js/',
        dest: 'dist/js/'
      }]
    }
  }
});

After you run grunt from the command line, new js files are created in dist/ folder and the logging statements are removed the new myscript.js:

$(document).ready(function() {

  $("#submit").on("click", function() {

  });
});

How to use grunt-remove-logging with grunt-usemin

For most of my projects, grunt-usemin is the plugin that I will use because its easy to setup. I have already written a blog post about using grunt-usemin in your projects.

Grunt-remove-logging-calls is based on Esprima tree, so it can handle minified code as well as complicated cases like console.log('hello: ' + foo(), bar()) easily.

The below configuration for grunt files will make only comment all the console.logs statements not remove them.

removeLoggingCalls: {
  files: ['dist/js/*.js'],
  options: {
    methods: ['log', 'info', 'assert'],
    strategy: function(consoleStatement) {
      return '/* ' + consoleStatement + '*/';
    }
  }
}

But one parameter that I found difficult to handle was the addition of comma in minified js files. Github Issue.

So if my script.js file is:

$(document).ready(function(){
  console.log('Document is ready');
  $("#submit").on("click", function() {
    console.log("Submit Button Clicked");
  });
})

the resultant js file minified by uglify looks like:

$(document).ready(function(){console.log("Document is ready"),$("#submit").on("click",function(){console.log("Submit Button Clicked")})});

the resultant javascript file after applying remove logging calls:

$(document).ready(function(){/*console.log("Document is ready")*/,$("#submit").on("click",function(){/*console.log("Submit Button Clicked")*/})});

which when run in the browser results in an error of Unexpected token , So how do we use grunt-remove-loggging in conjunction with grunt-usemin without breaking the existing javascript was the problem statement which lead me to this blog post which gave me the idea for the trick.

By using any variable like debugVar before the comma, we can avoid syntax error.

So this will not result in an error:

var debugVar = '';
$(document).ready(function(){$("#submit").on("click",function(){if(window.DEBUG){console.log("Submit Button Clicked")}debugVar})});

Of course we need to define debugVar before

<script>
    window.debugVar = '';
</script>

This is what the resultant Gruntfile.js looks like:

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    copy: {
      generated: {
        src: 'index.html',
        dest: 'dist/index.html'
      }
    },
    filerev: {
      options: {
        encoding: 'utf8',
        algorithm: 'md5',
        length: 20
      },
      source: {
        files: [{
          src: [
            'dist/js/*.js',
            'dist/css/*.css'
          ]
        }]
      }
    },
    useminPrepare: {
      html: 'index.html',
      options: {
        dest: 'dist'
      }
    },
    usemin: {
      html: 'dist/index.html',
      options: {
        assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js']
      }
    },
    removeLoggingCalls: {
      files: ['dist/js/*.js'],
      options: {
        methods: ['log', 'info', 'assert'],
        strategy: function(consoleStatement) {
          return 'if(window.DEBUG){' + consoleStatement + '}debugVar';
        }
      }
    }
  });

  grunt.registerTask('default', [
    'copy:generated',
    'useminPrepare',
    'concat',
    'uglify',
    'cssmin',
    'filerev',
    'usemin',
    'removeLoggingCalls'
  ]);
};

Go run this in your browser.

The strategy parameter in removeLoggingCalls accepts a function with console.log statement as the first argument and will replace that with whatever string you return. Simply put you can even have this:

removeLoggingCalls: {
  files: ['dist/js/*.js'],
  options: {
    methods: ['log', 'info', 'assert'],
    strategy: function(consoleStatement) {
      return 'if(window.DEBUG){' + consoleStatement + '}debugVar';
    }
  }
}

This would make sure that if you have window.DEBUG = true, all the console.logs will be printed in production as well. As usual this blog post as well as this code is available on github.

Readme for the Grunt task

grunt-remove-logging-calls

About

This plugin removes/replaces all or any part of console logging statements from javascript code. It handles complex cases like console.log('hello: ' + foo(), bar()) because it's based on the syntax tree given by Esprima.

Getting Started

This plugin requires Grunt. Install this plugin with the command:

npm install grunt-remove-logging-calls

Once the plugin has been installed, enable it inside the Gruntfile:

grunt.loadNpmTasks('grunt-remove-logging-calls');

Finally, add some configuration.

Configuration

grunt.initConfig({
    // ...

    removeLoggingCalls: {
        // the files inside which you want to remove the console statements
        files: ['src/**/*.js'],
        options: {
            // an array of method names to remove
            methods: ['log', 'info', 'assert'], 

            // replacement strategy
            strategy: function(consoleStatement) {
                // comments console calls statements
                return '/* ' + consoleStatement + '*/';

                // return ''; // to remove 
            },

            // when the logging statement is ended by a semicolon ';'
            // include it in the 'consoleStatement' given to the strategy
            removeSemicolonIfPossible: true

        }
    }

    // ...
});

If you want to integrate this with grunt usemin, here the blog post explaining it.