Prerequisites

  • Node installed
  • A little gulp and npm knowledge is beneficial, but not required

Some people prefer to see the code first, so if you would like to download a working demo, the files can be found here (be sure to run npm i to install the dependencies).

What is linting?

Linting is the process of checking your code for potential errors. Linting tools usually allow you to specify a set of rules to check your code against. These rules can vary from general code layout, like maximum line length and code indentation, to how you declare functions.

Why lint?

Linters help you to write standardised code to ensure quality, minimise errors and increase readability. This is helpful when working in teams to ensure all developers are writing code in the same way. In day-to-day work, if developers are working with various files that have a consistent layout, it makes the code easier to read, which means developers can work faster, saving time. Linters also offer performance benefits in highlighting inefficient or unused code. Naturally we want the best user experience for our customers and keeping the code as efficient and lightweight as possible to reduce page load time is a big part of that.

ESLint

Some of the most popular JavaScript linting tools are ESLint, JSHint, JSLint and JSCS – we’re going to be using ESLint. It’s very flexible, easy to use and has the best ES6 support, which will be helpful if we introduce more modern JavaScript (that will be transpiled for older browsers using https://babeljs.io/). All rules for ESLint can be found here: https://eslint.org/docs/rules/.

A great starting point – Airbnb JavaScript Style Guide

Instead of writing our own exhaustive list of JavaScript rules, we can use a ruleset defined by the developers at Airbnb, and then adjust it to suit our preferences. The Airbnb JavaScript Style Guide is well known among JavaScript developers and used by some big companies: Lonely Planet, National Geographic and Sainsburys to name a few. It’s a great place to start.

Using ESLint with Gulp

We could install ESLint globally and run it from the command line using the command eslint. However, in this tutorial we are going to be using ESLint in a gulp project and that means we can install ESLint, and all necessary dependencies, locally. This is beneficial for other people on the project as all dependencies are kept neatly inside the project (listed in the package.json) and won’t require any extra work or global installations.

Installing our dependencies

If you don’t yet have gulp installed, in terminal navigate to the root of your project folder and run:

npm install gulp --save-dev

Note the --save-dev will add the package to your package.json as development dependencies.

Here are the ESLint dependencies we are going to install:

  • eslint – the ESLint tool
  • gulp-eslint – the gulp plugin for ESLint
  • eslint-config-airbnb – the Airbnb ESLint configuration (rule set)
  • eslint-plugin-react – a plugin to add react-specific rules for ESLint to use
  • eslint-plugin-import – a plugin to add linting ES2015+ (ES6+) import/export syntax
  • eslint-plugin-jsx-a11y – a plugin to check accessibility of JSX elements (react)

To install all of these run (again from the root of your project folder):

npm install gulp gulp-eslint eslint-config-airbnb eslint eslint-plugin-react eslint-plugin-import eslint-plugin-jsx-a11y --save-dev

Adding an ESLint configuration file

We now need to add an ESLint configuration file, which will tell our linting process what standards and rules our code needs to meet. We could have a file named .eslintrc in the root of our user folder, which would set global default linting rules. Instead, we will have an .eslintrc file in the root of our project folder to set rules for this individual project.

To create the file, in terminal go to the root of your project and run

touch .eslintrc

This will create the file and we can add our rules to it. Note this file begins with a full stop so might not be visible in mac finder or windows explorer but should be visible in your code editor/IDE.

Open up the file and add the following:

{
    "env": {
       "es6": true,
       "browser": true,
       "node": true,
       "jquery": true
    },
    "extends" : "airbnb",
    "rules" : {
    }
}

This will set our linting up to work with ES6, the browser, node, jQuery and use Airbnb’s configuration/ruleset. We can add extra rules that will override those in the Airbnb ruleset in the rules object. For example, if you would rather indent using tabs (you reckless animal), your rules would look like:

"rules" : {
    "indent": ["error", "tab"]
}

View more rules here: https://eslint.org/docs/rules/ You can specify error, warn, or off to choose how a rule should be flagged or if it’s disabled entirely.

Adding a gulp ESLint task

Now we have ESLint installed and our rules ready, we need to add our gulp task and dependencies to our gulpfile.js which will run our linting. In your gulp file you will need the following:

var gulp = require('gulp');
var eslint = require('gulp-eslint');

gulp.task('eslint', () => {
    return gulp.src('./exampleCode.js')
    .pipe(eslint())
    .pipe(eslint.format())
    .pipe(eslint.failAfterError())
});

Be sure to link the src to your JavaScript file, or lint all the JS files in a directory using globbing - return gulp.src(‘./folder-path/**/*.js’)

Now if we run gulp eslint from the command line it should highlight our issues. For example, if our exampleCode.js file contained:

function exampleFunction() {
    var testObject = {
        'name':"Ash Connolly",
        'location':"Sheffield"
    };
    return testObject.name + ', ' + testObject.location;
}

exampleFunction();

…it would return the following errors:

~/Ash/sites/eslint-tutorial $gulp eslint
[15:37:42] Using gulpfile ~/Ash/sites/eslint-tutorial/gulpfile.js
[15:37:42] Starting 'eslint'...
[15:37:43] 
/Users/Ash/Ash/sites/eslint-tutorial/exampleCode.js
  2:1   error  Expected indentation of 2 spaces but found 4    indent
  2:5   error  Unexpected var, use let or const instead        no-var
  3:1   error  Expected indentation of 4 spaces but found 8    indent
  3:9   error  Unnecessarily quoted property 'name' found      quote-props
  3:16  error  Strings must use singlequote                    quotes
  3:16  error  Missing space before value for key 'name'       key-spacing
  4:1   error  Expected indentation of 4 spaces but found 8    indent
  4:9   error  Unnecessarily quoted property 'location' found  quote-props
  4:20  error  Missing space before value for key 'location'   key-spacing
  4:20  error  Strings must use singlequote                    quotes
  4:31  error  Missing trailing comma                          comma-dangle
  5:1   error  Expected indentation of 2 spaces but found 4    indent
  6:1   error  Expected indentation of 2 spaces but found 4    indent
  6:12  error  Unexpected string concatenation                 prefer-template

✖ 14 problems (14 errors, 0 warnings)
  14 errors, 0 warnings potentially fixable with the `--fix` option.

[15:37:43] 'eslint' errored after 1.48 s
[15:37:43] ESLintError in plugin 'gulp-eslint'
Message:
    Failed with 14 errors

Now we can see parts of our code that don’t align with the rules.

The magical fix

One of the great things about ESLint is that it can ⚡️ fix our code for us!⚡️ To do this we need to create a new task that will both lint and fix the code.

First of all we need to install an npm module called gulp-if which allows to us to check if ESLint has fixed the file, before we update the file.

npm install gulp-if --save-dev

Now in our gulp file we need to:

  • Add the new gulp-if dependency
  • Add a new function to check if ESLint has fixed the file
  • And then add our new task that both lints and fixes the file.

Our entire gulp file will now look like this:

var gulp = require('gulp');
var eslint = require('gulp-eslint');
var gulpIf = require('gulp-if'); // new dependency added


gulp.task('eslint', () => {
    return gulp.src('./exampleCode.js')
    .pipe(eslint())
    .pipe(eslint.format())
    .pipe(eslint.failAfterError())
});

// new function added to check if ESLint has run the fix
function isFixed(file) {
    return file.eslint !== null && file.eslint.fixed;
}

// new lint and fix task
gulp.task('eslint-fix', () => {
    return gulp.src('./exampleCode.js')
    .pipe(eslint({
        fix: true, 
    }))
    .pipe(eslint.format())
    // if running fix - replace existing file with fixed one
    .pipe(gulpIf(isFixed, gulp.dest('./')))
    .pipe(eslint.failAfterError())
});

Now if we run gulp eslint-fix we should get the following:

~/Ash/sites/eslint-tutorial $gulp eslint-fix
[15:38:52] Using gulpfile ~/Ash/sites/eslint-tutorial/gulpfile.js
[15:38:52] Starting 'eslint-fix'...
[15:38:54] Finished 'eslint-fix' after 1.51 s

Now we can see that all of our previous problems have been removed and the contents or our exampleCode.js file has been updated in various ways.

Before:

function exampleFunction() {
    var testObject = {
        'name':"Ash Connolly",
        'location':"Sheffield"
    };
    return testObject.name + ', ' + testObject.location;
}

exampleFunction();

After:

function exampleFunction() {
  const testObject = {
    name: 'Ash Connolly',
    location: 'Sheffield',
  };
  return `${testObject.name}, ${testObject.location}`;
}

exampleFunction();

Changes made:

  • All indentation has been updated
  • Var changed to ES6 const
  • Unnecessary quoting of object property removed
  • Double quotes changed to single in object values
  • Space before object values added
  • Added trailing comma for last object property
  • Return string has been changed to an ES6* template literal.

And that’s it! All our linting is working and it can fix our code for us! 😀 When running the fix you should be confident that you understand the issues and changes made after running the fix to ensure that your JS behaves as expected. 

* Please note the last change involves converting a JavaScript string to an ES6 JavaScript template literal, which as an ES6 feature, is not supported in all browsers. To enable use of ES6 JavaScript in older browsers you will need to transpile it using https://babeljs.io/.

If you would like to download a working demo containing all the code in this tutorial please click here (be sure to run npm i to install the dependencies).

Advanced example

If you would like to see a more advanced gulp task where we can pass options via the command line, we can use the advanced example below (note this requires you to install a new dependency by running npm i yargs --save-dev):

var gulp = require('gulp');
var eslint = require('gulp-eslint');
var gulpIf = require('gulp-if');
var argv = require('yargs').argv; 

gulp.task('eslint', () => {
    var target = argv.file ? argv.file : './exampleCode.js';
    var fixCode = argv.fix ? true : false;

    return gulp.src(target, {base: "./"})
    .pipe(eslint({
        fix: fixCode, 
    }))
    .pipe(eslint.format())
    .pipe(gulpIf(isFixed, gulp.dest('./')))
    .pipe(eslint.failAfterError())
});

We can now pass ESLint a specific file to lint, if we don’t it will use the default target in the gulp task, currently set to ./exampleCode.js. We can also set a flag to fix the file using --fix.

Here is a list of example commands you could pass to the eslint gulp task:

gulp eslint                                      // lint default target(s)
gulp eslint --fix                                // lint + fix all default target(s)
gulp eslint --file ./folder/filename.js          // lint supplied file
gulp eslint --file ./folder/filename.js --fix    // lint + fix supplied file

Enjoy, and happy linting! 😀