orange
orange

Reputation: 8090

eslint on dynamically changing file list

I'd like to run eslint on modified files only. I've created a new run target in package.json to run eslint from command line (git diff --name-only --relative | grep -E '.*\\.(vue|js)$' | xargs eslint --ext .js,.vue). In theory, this should work fine, but there's a little transformation step happening in my project (a string replacement) when bundling the files with webpack that will throw off eslint (some non-standard markup will be expanded to JS).

What are my options and how would I go about implementing them? For instance, could I execute a particular webpack rule/loader and pipe the result to eslint? Another option I see is to include eslint into the webpack rule/loader process (instead of executing it from the command line), but how would I then filter on files that are currently modified (could this be handled by a temporary file that contains the git diff... result?)

Upvotes: 1

Views: 1405

Answers (1)

orange
orange

Reputation: 8090

I've got a somewhat working approach. I chose to modify webpack.base.conf.js instead of going for the command line solution to make use of the already existing string replacement loader.

The files are collected in the WebpackBeforeBuildPlugin callback function and instead of a regex based test variable, a function is used which checks against the previously collected files.

const exec = require('child_process').exec;
const WebpackBeforeBuildPlugin = require('before-build-webpack');
var modFilesList = new Set([]);
const srcPath = resolve('.');

...
      rules: [{
        test: function(filename) {
          let relFilename = path.relative(srcPath, filename);
          let lint = modFilesList.has(relFilename);
          return lint
        },
        loader: 'eslint-loader',
        include: resolve('src'),
        exclude: /node_modules/,
        options: {
          formatter: require('eslint-friendly-formatter'),
          cache: false
        }
      }, {
       ... other string replacement loader ...
      }


   plugins: [
    ...
    new WebpackBeforeBuildPlugin(function(stats, callback) {
      // Collect changed files before building.
      let gitCmd = 'git diff --name-only --relative | grep -E ".*\\.(vue|js)$"';
      const proc = exec(gitCmd, (error, stdout, stderr) => {
        if (stdout) {
          let files = stdout.split('\n');
          modFilesList = new Set(files);
        }
        if (error !== null) {
          console.log(`exec error: ${error}`);
        }
      });
      callback();
    })
  ]

The only problem at the moment is that when git file changes occur, they don't trigger a re-linting based on these file changes (i.e. new file is changed, or previously (before starting webpack-dev-server) changed file changes are discarded). I checked everything I could. The change is registered and stored in modFilesList, the test function is executed and returns true (for a new change in a previously unchanged file) or false in case the change was discarded. I also played with the cache option to no avail. It seems that at initial load, eslint-loader caches the files it will lint in future (don't know if that's a result of using a test function instead of a regex or also the case with the regex). Is anyone having an idea or has seen this before (eslint-loader not updating the file list)?

Update

This seems to be a problem with webpack (or one of the other loaders) as the eslint-loader isn't even executed when the file changed. The test function however is executed which is a bit weird. I don't fully understand how loaders work or how they play together, so there might be some other loader that is causing this...

Upvotes: 0

Related Questions