Integrating ESLint into a legacy codebase
One of the first things I usually do for a new JavaScript project is to set up and configure ESLint. ESLint is a static code analyzer. It’s great for two reasons: First, it helps you enforce a consistent coding style across a team of developers or as a solo dev. This isn’t purely about code aesthetics but about making code more readable. Second, it can spot errors in your code while you’re writing it, and that’s less time head-scratching, debugging, and digging through stack traces. Software development is complicated, and ESLint is one of the tools that can help make your life a little easier. But the primary reason that ESLint is one of the first things I set up is that it becomes increasingly difficult with every line of code you add to the project.
I recently had to integrate ESLint into a project that was two years old, and this is the report that came back:
✖ 5549 problems (3726 errors, 1823 warnings)
3130 errors and 1472 warnings potentially fixable with the `--fix` option.
Just briefly, the thought crossed my mind that it’s not worth the effort to integrate ESLint. Of course, I didn’t want to spend hours manually going through the code to fix everything. I could have just ignored the errors, hoping that I’d be able to purge them bit by bit over time. But I couldn’t stand the red squiggles on the screen and wasn’t sure if everyone on the team would fight them with the same determination as I would, especially without a CI pointing fingers at them.
I needed a way to ensure that the code style would gradually improve with every new commit. What if I could make sure that every file we touch has to get cleaned up? There is a way, of course, and it’s possible with the help of Git:
git diff main --name-only --diff-filter=ACM \
| grep -E '\.(vue|js)$' \
| xargs node_modules/.bin/eslint
The script will only lint the files that have changed from the main branch. Let’s explore the command line-by-line:
git diff main --name-only --diff-filter=ACM
will list the names of all files that have been [A]dded, [C]opied, or [M]odified compared to main.grep -E '\.(vue|js)$'
will filter the list to files that end on.vue
or.js
. You have to adjust this to match the file patterns that you defined in your ESLint settings.- Finally,
xargs node_modules/.bin/eslint
will pass the files as an argument to ESLint.
I saved this as a script in the package.json
file and added it to the workflow on Github Actions. Now, whenever someone touches a file in the project, he has to clean it up before it passes the CI. We are enforcing positive change over time!