Lint only touched files with Webpack

Recently I had to add a linter on a project in which the codebase was never linted before. I am talking about a big codebase in which a team have worked on it for years already.

Obviously, the amount of errors thrown from the linter, was such a big number to become an useless information.

With my team mates, we agreed on run the linter only on the “touched” files: the behaviour we wanted was to get the linter parsing every file that gets changes.

So, if I am working on the file A, until I don’t save it, the linter throw 0 errors (because of no file parsed). When I do save the file A, then the linter parses it and throw (maybe!) errors.

Looking around in the web, wasn’t obvious how to do it: so I planned to write the code to do it myself – using a watcher to detect file changes – as part of Webpack configuration (the best solution would be to relay on git to detect changes I believe, not a watcher, but will be the next step).

This is the implementation (inside the webpack.config.js), I paste it as it is now:

// Dependencies for Webpack (usually this goes at the top)
var logger = require('reliable-logger');
var watch = require('watch');
var CLIEngine = require('eslint').CLIEngine

// ...

// place this when you want in the file, accordingly to your own organisation
// preferences!
// This is the function to run watcher and linter
var configureLinterAndWatchFiles = function() {
  var changedFiles = [];
  var formatter;
  var report;
  var SEPARATOR = "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////";

  // TODO I got the feeling that one of those settings is breaking the
  // linter (probably the path resolving?)
  var linter = new CLIEngine({
    // TODO do I need this? Looks like I don't...
    // envs: ["node"],
    // TODO what is the default?
    useEslintrc: true,
    // TODO I find weird that I get no error with this: configFile:
    // "../.eslintrc1111"
    // make sure that the configuration file is correctly picked up
    configFile: ".eslintrc",
    // TODO useless if your root is src
    // ignorePath: "node_modules"
    // TODO probably both useless... the first I still don't get it,
    // the second you are enforcing the filtering yourself by checks
    // cache: false,
    // extensions: [".js", ".jsx"]
  });

  var fileUpdatedFn = function(f) {
    // TODO I would prefer much more to get the list of changed files from
    // git status (how to?). Here I am building my own
    // resetting the array only for debug purpose
    // changedFiles = [];
    if(/.js$/.test(f) || /.jsx$/.test(f)) {
      changedFiles.push(f);
      logger.info(SEPARATOR);
      report = linter.executeOnFiles(changedFiles);
      logger.info(formatter(report.results));
    }
  };

  // get the default formatter
  formatter = linter.getFormatter();

  watch.watchTree('src', function(f, curr, prev) {
    if (typeof f == "object" && prev === null && curr === null) {
      // Finished walking the tree
    } else if (prev === null) {
      // f is a new file
    } else if (curr.nlink === 0) {
      // f was removed
      } else {
      // f was changed
      fileUpdatedFn(f);
    }
  });
};

// last bit: running the function!
module.exports = function(callback, options){
  // ...
  configureLinterAndWatchFiles();
}

It is still to be improved but it does the job, so good to share it!
Thanks for reading!

This entry was posted in Javascript and tagged , , , , , . Bookmark the permalink.

Leave a Reply

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 )

Connecting to %s