My Grunt Worker

grunt-logo-large

I thought it would be a good idea to share how I have set up one of my Grunt Files. This follows on from the style guide post where I described why use style guides and also what one I use.

In the configuration there are some shared properties and settings, so to start my Grunt file I have set up some variables to store the string locations. This then saves on them having to be repeated between modules and when there is a folder change or an update then it is one change for all.

I have mainly used the Grunt JS set up for the JavaScript processing, for which I have started with the linter for my projects. I like to follow the Airbnb style guide for both the JavaScript and the CSS, so this is the guide I have made the linter follow. The linter I have chosen to use is the JS Hint as it is very well supported and works with the Airbnb guide, however I use the JS Hint for Visual Studio full code editor only and then I use the eslint (link eslint)with Visual Studio Code (VS Code). This is because I started with the eslint with VS Code, but found that JS Hint worked better with the full edition.

To set this module up you can use the ‘jshintrc’ file, but to save on loading and maintaining multiple files I decided to drop the settings in the Grunt file directly. The source for the configuration is here on the Airbnb Github.

After the files have been checked for formatting errors, I wanted to collect all the small JavaScript files and concatenate them together. Therefore I decided to use the ‘grunt-contrib-concat’. This simple module gathers all the JavaScript files from a configured location and concatenates them into a single location. There are two issues with this method and why I don’t tend to use this all the time. One is that it concatenates from top to bottom of the files, so unless your desired order is alphabetical then this create a requirement issue. For this I tend to use RequireJS being one of the best method to save on loading time and create a simple configuration. The other issue is that once it concatenates the sources into a single file, and you run it again, it doesn’t clean out the previous run. Instead it keeps on concatenating the sources, so you start to get duplications of source. To tackle this you can use the ‘grunt-contrib-clean’ to clear out the previous content. Pass this module the concatenated file location and run it before the ‘grunt-contrib-concat’ to have a clean source location.

Just to get the file size even smaller, the last module I use is the ‘grunt-contrib-uglify’. This is set up basically the same as the previous concatenate module with source and its destination. The module will take the single concatenated file and then minify it to the chosen location.

Finally for the JavaScript is the QUnit module, and you can put this in between any of the modules before. I like to test it on the file I am going to be using in the production site to test on what will be used. The QUnit module requires the PhantomJS Node package to run the test, so this will need to be installed but you can check out the version in my example files. I again like to use this module as it is well supported and also easy to use. For the Grunt configuration the test needs to be in a HTML file formation, which you can read more at QUnit JS.

The CSS modules are much smaller and also simpler to use, because instead of using any minifies, concatenates or other modules I just use a pre-compiler.  The pre-compiler will do all the above except the minimisation, but this is up to you if you need it done.

The only thing I have got in the Grunt file for CSS is the linter. As mentioned before I use the Airbnb style guide, so I have of course use this guide with the preferred linter. The linter used is ‘grunt-stylelint’ that pulls in the configuration file from a JavaScript directory. The only other configuration needed is to tell the linter where to lint.

So now all the configuration is set up and ready, but without running this file manually the Grunt Worker won’t be working. Therefore we need something to keep an eye on the files for if anything changes and for that we have the ‘grunt-contrib-watch’. In the configuration of this module, point it to the folders you want it to watch and then set up what you want it to do. In the tasks you enter a string array of the modules you want to run if a file changes and also the order to do them in.

This is then the finished product of how I have configured my Grunt file. Depending on different projects, editors and languages this can differ, but it is a base to start. Please feel free to share how you configure your Grunt files.

Here are links to all the grunt Git Hub:

Here is my grunt configuration:

 
// Generic File Variables
const BaseDirectory = 'assets/';
const WildCardFolder = '**/';
const MainLocation = 'main/';
const MainFile = MainLocation + 'main';

 
// JavaScript File Variables
const FileDirectoryJs = BaseDirectory + 'core/js/';
const WildCardFileJs = '*.js';
const FileLocationJS = FileDirectoryJs + WildCardFolder + WildCardFileJs;
const FileDirectoryJsUnitTest = ['core/js/JsUnitTest/QUnit.html'];

 
// CSS File Variables
const FileDirectoryCss = BaseDirectory + 'core/css';
const WildCardFileCss = '*.css';
const WildCardFileLess = '*.less';
const FileLocationCSS = FileDirectoryJs + WildCardFolder + WildCardFileCss;
const FileLocationLess = FileDirectoryJs + WildCardFolder + WildCardFileLess;

 
module.exports = function (grunt) {
grunt.initConfig({
jshint: {
files: [FileLocationJS],
options: {
/*
* ENVIRONMENTS
* =================
* Source: https://github.com/airbnb/javascript/blob/master/linters/.jshintrc
*/

 
// Define globals exposed by modern browsers.
'browser': true,

 
// Define globals exposed by jQuery.
'jquery': true,

 
// Define globals exposed by Node.js.
'node': true,

 
// Allow ES6.
'esversion': 6,

 
/*
* ENFORCING OPTIONS
* =================
*/

 
// Force all variable names to use either camelCase style or UPPER_CASE
// with underscores.
'camelcase': true,

 
// Prohibit use of == and != in favor of === and !==.
'eqeqeq': true,

 
// Enforce tab width of 2 spaces.
'indent': 2,

 
// Prohibit use of a variable before it is defined.
'latedef': true,

 
// Enforce line length to 100 characters
'maxlen': 100,

 
// Require capitalized names for constructor functions.
'newcap': true,

 
// Enforce use of single quotation marks for strings.
'quotmark': 'single',

 
// Enforce placing 'use strict' at the top function scope
'strict': true,

 
// Prohibit use of explicitly undeclared variables.
'undef': true,

 
// Warn when variables are defined but never used.
'unused': true,

 
/*
* RELAXING OPTIONS
* =================
*/

 
// Suppress warnings about == null comparisons.
'eqnull': true
}
},
concat: {
all: {
src: [FileLocationJS],
dest: FileDirectoryJs + MainFile + '.js'
}
},
uglify: {
all: {
src: [FileLocationJS],
dest: FileDirectoryJs + MainFile + '.min.js'
}
},
clean:
[FileDirectoryJs + MainLocation + WildCardFileJs]
,
qunit: {
all: FileDirectoryJsUnitTest
},
stylelint: {
options: {
configFile: 'stylelint-config-airbnb.js',
syntax: 'less'
},
src: [FileDirectoryCss + WildCardFileCss,
FileDirectoryCss + WildCardFileLess, CardFileLess]
},
watch: {
files: [FileDirectoryCss, FileDirectoryJs],
tasks: ['clean', 'concat', 'stylelint', 'jshint', 'qunit', 'uglify']

 
}
});
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-stylelint');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-uglify');

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

Advertisements

Leave a message please

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s