/ Programming

Eslint-Watch

It's been awhile since I have posted anything on my blog. I felt like with the recent news of Eslint-Watch jumping up to 40,000 downloads a month it might be time to talk a little bit about the motivation behind why it was created.

Eslint-Watch was created because of Eslint issue GH-2513 and Eslint-Loader issue GH-21. When I was working at Towers Watson, we were transitioning from Angular to Webpack and React. In that process, we wanted to follow a strict linting pattern using Eslint. While trying to get our code linted, we integrated Eslint-Loader so that way the lint was run each time we built our assets using Webpack.

Back then, there were a couple of issues with Eslint-Loader. One of those problems was that Eslint-Loader couldn't lint the file you were working on. It was either the whole project or nothing at all. Back then, eslint --cache flag wasn't a thing and our project was huge with over 20,000 lint errors so it would take 30-40 seconds just to run the lint. Not only that but you would have to find the file you were working on within the 100+ files and 20,000+ error list. That's kind of a problem if you wanted fast feedback on the file you were working on at the time.

Some other problems we had with Eslint-Loader was GH-21. Basically, it didn't care about the cascading rules feature. It would take the parent config and apply the rules to all files.

Say goodbye to "mocha": true.

So in my spare time, I started to implement a file watcher that would run Eslint when I would save a file. I didn't run into the same cascading issues as the Eslint-Loader since I relied on Eslint to find out what config it should be using for a given file.

The code was extremely simple. Only a couple of files were needed to satisfy the problems we were seeing. The only thing I needed to do was add a --watch/-w command to Eslint and bam! Done. Or at least I thought so.

There was a lot of code I was copying from eslint directly so I threw up an issue on Eslint's Github page to see if they would be interested in a --watch flag GH-2513. The creator of the tool said that it was out of scope for the project and that there are other tools such as Gulp, Grunt or Webpack that can offer filesystem watching and execute Eslint.

Feeling a bit defeated, I thought about it a bit more and decided that a --watch flag could be a cool and necessary feature for Eslint. Not everyone is using Gulp, Grunt or Webpack in their projects. It seems like a big dependency and a lot of configuration to bring in for just watching the file system and running a lint. So Eslint-watch was published at 1.0.0 3 days later.

Since then there have been several changes made to Eslint-Watch. I added several formatters because there were some issues with knowing how many errors and warnings were in a file. In some cases I didn't care what the issues were, I just wanted to know how many issues were in a given file. At the time, we had over 20,000 issues in the entire project so I was going to tackle the biggest culprit in linting errors.

Help Text Parser

The biggest problem I ran into was trying to extend Eslint's options. The original way I made eslint-watch extend Eslint's options was copy paste. Like I said, there was a lot of code being duplicated across both projects. Since Eslint's options were updating pretty frequently I asked the community if they would be willing to expose their options array for better extensibility. After some discussion, that was also declined. So, I did what I thought would be the easiest solution to reducing the number of times I had to update the project and wrote a help-text parser.

The help-text parser was one of the bigger things about this project. It itself has added a lot of fragility around the project as the help text is the first thing that is activated when Eslint-Watch is executed. So if they add any type of headers or change the order of which things are displayed, it will break.

Looking forward

Eslint-Watch has been one of my pet projects for a year and a half now and I am still planning on moving forward with it. The main problems I run into now are whether or not I have constructed the tool correctly. I am facing problems with callback hell and async workflows that need to somehow be solved in an elegant way. One of my next initiatives is rewriting it in ES6 using babeljs so I can utilize object destructuring and spread operations. Who knows, maybe I will attempt at making it more event driven and see if I can speed up some of the bottlenecks that are presented.

A bit of history

Here is the code comparisons of V1 to V2 as well as V2 to master.