Grunt - Getting Started

By Ron Royston

May 2018

Table of Contents

Introduction

Automation of tasks related to web development. Grunt, "The JavaScript Task Runner". In addition to file concatenation, linting, and minification, Grunt delivers a plugin that offers the equivalent of PHP's include. Static content such as page headers, navigation bars, or footers are automatically inserted across several HTML files, or web pages. Write header.html and footer.html in standalone files and Grunt automatically inserts them in all of your production .html files for you on demand. Without Grunt, change the footer on one page and you must then manually replicate, i.e. copy and paste, that update across all of your HTML files that contain that footer content.

Adopting and deploying Grunt is not trivial but this is a situation where one takes 1 step back to make leaps forward. Admittedly, I spent several hours reading and experimenting before getting Grunt running properly. The effort has already paid off. This article should enable you to get up and running with Grunt in minutes. Write once, paste everywhere, in milliseconds.

Setup

Developers use an Integrated development environment, IDE, rather than a simple text editor. Eclipse is a free favorite. I use Cloud9, an online IDE. Now install Grunt. There is no reason to regurgitate the installation steps which are already published by the Grunt team. Install Grunt now.

Grunt is modular in that the features are installed as plugins. Each plugin installs in a matter of seconds. Quick and easy. The example in this article utilizes grunt-processhtml, grunt-contrib-uglify, grunt-contrib-concat, grunt-contrib-htmlmin, and grunt-contrib-cssmin. Install these now.

The Process HTML Plugin

The processhtml plugin looks for specifically worded HTML comment sections and replaces them with the HTML snippets you specify. For example, a centralized footer snippet located at includes/footer.html gets inserted into any HTML file that includes the below code, at that location in the target document(s).

                
<!-- build:include includes/footer.html -->
<!-- /build -->
                
            

NOTE: the specified filepath in HTML files located in subfolders should specify reverse directory lookup, i.e. .., as in includes/footer.html. This is because the includes directory is one level up relative to subfolders in your source folder.

Folder Structure

The Grunt code below assumes a specific folder structure on your development machine / IDE. This code should be in Gruntfile.js in the root of your directory. Create a source, staging, and public folder in your root directory. Inside your source folder you have 4 folders - articles, css, includes, and js. Folder Structure Image All your .html files such as index.html, about.html, etc go here in the source folder. Your JavaScript goes in the js, CSS in the css flder, and finally I have an articles section on my webpage / webapp - thus the articles folder. You might have a different subfolder or set of subfolders, but this example shows how it's done.

Grunt Configuration

Starting out, one specifies each file that Grunt should touch as well as what operations Grunt should perform. This is spelled out in your Grunt file, or Gruntfile.js. Add a new HTML file, or webpage, and you must manually tell Grunt to process it by including it in your Gruntfile.js. This manual approach grows unwieldy as the number of HTML files, or webpages, your app has so automating Grunt with wildcards is key. Configured as below Grunt touches every HTML file in my source folder as well as my articles subfolder each time I run Grunt. The staging folder is a midway holding point that Grunt circles back to before performing its final task of dropping all files to the production public folder. Note the expand: true and src: ['*.html', 'articles/*.html', '!**/includes/**'],. This is what tells Grunt to touch all HTML files.

Grunt Code

                
module.exports = function(grunt) {
    grunt.initConfig({
        processhtml: {
            dist: {
                options: {
                    process: true,
                },
            files: [{
                expand: true,
                cwd: 'source/',
                src: ['*.html', 'articles/*.html', '!**/includes/**'],
                dest: 'staging/',
                ext: '.html'
                }]
            }
        },
        uglify: {
            my_target: {             
                files: {
                    'staging/script.min.js': ['source/js/script.js']
                }
            }
        },
        concat: {
            js: {
                src: ['source/js/firebase.js', 'source/js/firestore.js', 'source/js/mdc-web.min.js', 'staging/script.min.js'],
                dest: 'public/app.min.js',
            },
        },
        htmlmin: { // Task
            dist: { // Target
                options: { // Target options
                    removeComments: true,
                    collapseWhitespace: true
                },
                files: [{
                    expand: true,
                    cwd: 'staging/',
                    src: ['**/*.html'],
                    dest: 'public/',
                    ext: '.html'
                }]
            }
        },
        cssmin: {
            target: {
                files: {
                    'public/app.min.css': ['source/css/mdc-web.min.css', 'source/css/style.css']
                }
            }
        }
    });
    grunt.loadNpmTasks('grunt-processhtml');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-htmlmin');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.registerTask('default', ['processhtml', 'uglify', 'concat', 'htmlmin', 'cssmin']);
};
                
            

Troubleshooting

There is a useful -- verbose switch that shows task details so use grunt -- verbose if you are having issues. One issue I encountered was using the % sign in one of my .html files since Grunt sees these as argument delimiters. The fix is to simply use the HTML character code.

Conclusion

Grunt is not a toy and it is raw. One missing letter or comma in a single file and it will fail and throw a funky error. However, the time savings of using the Grunt tool are well worth it. If you are a professional developer, automating mundane tasks is mandatory and Grunt is a widely used automation tool. I am very pleased with Grunt and will continue using it.

Dialog Title

Cell Phone Number

Your order ID is . The grand total is , or bitcoin.

Delete location?





A password reset link will be emailed to you.




New users register here for an email authenticated account.

Forget your password? Click here to have a new one emailed to you.

Find a bug? Experience an error? How can we do better? We appreciate your feedback.

email
facebook
github
google
twitter

Delete order? This action cannot be undone.

Delete order? This action cannot be undone.