Notes on Grunt

Grunt is a very powerful task runner for automating and improving your development workflow. Even in 2017 when Webpack seems to be the cool kid on the block for concatenating and bundling static assets, there are plenty of tasks that are better handled by Grunt (or Gulp).

Setting Up Grunt

You don’t need grunt-cli to run Grunt tasks! Use npm scripts to define all project related tasks as npm run task-name instead. This way you can swap out Grunt for anything else in the future without changing the name of the related task. For example, here is an excerpt of package.json that uses both Grunt and Webpack for separate tasks:

{
  "scripts": {
    "css": "grunt build:css",
    "js": "webpack --config webpack.config.js",
    "grunt": "grunt"
  }
}

Notice, there is also a generic grunt script for running individual grunt tasks via npm run grunt task-name.

Grunt is Awesome

So far I’ve been using Grunt mainly for transpiling, bundling and minifying JS and CSS files but recently (four years too late) I discovered grunt-wp-deploy by Stephen Harris which enables automated deployments for WordPress plugins to the official plugin repository. There is even wp-readme-to-markdown for converting plugin readme.txt into markdown formatted readme for GitHub. The Gruntfile.js of the Event Organiser plugin is a great example of what is possible.

Grunt for wp-dev-lib

So I began to wondered if we could convert most of the wp-dev-lib magic into Grunt tasks that are written in Javascript instead of Bash. The greatest feature of the wp-dev-lib is that it can report errors only for the parts of code that have changed in the particular commit or pull request. This is especially valuable when working with legacy projects that don’t adhere to any coding standards.

The following scripts are the easiest to convert:

However, the core features are contained in the pre-commit script which does all of this:

  • Sets up environment variables that determine which tasks to run.
  • Determines the Git diff range for which to run the checks.
  • Checks for PHPCS, PHPUnit, Codeception, Vagrant, Docker, JSCS, JSHint and ESLint config files to determine which tasks to run and where.
  • Creates a list of files with changes for each file type such as PHP, JS, CSS and XML.
  • Installs the binaries for running the actual checks.
  • Ensures that no executable files are being committed.
  • Runs all the linters and tests and reports errors only in the current changeset.

The challenge here is to duplicate the patch-level linter reporting. So far I haven’t figured the best way to do that but it’s been an interesting thought experiment.

Finally, we wouldn’t actually need the patch level filtering if the whole codebase matched the coding standards required by each linter. Maybe for legacy projects it’s easier to start by running automated code fixers such as phpcbf and fixmyjs.

Leave a Reply