Consistent JavaScript Code
Konrad JaguszewskiReading Time: 4 minutes
Some time ago I had a dream. I was creating a new project. I was thinking about all cutting-edge technologies I could use in it. My team was very small at the beginning. Everything was going smoothly, we were developing fast and without problems, it was great. Somewhere along the way new people started joining us and they brought gifts. But the gifts were treacherous, they were different coding standards and formattings. After some time I saw that from our perfectly organized code a new entity started emerging. It was a creature that could have had its origin in one of Lovecraft's stories. In its left hand it was holding 4 spaces and in the right one 1 tab. One of its eyes was a semicolon while the other was looking at me with empty void. I woke up screaming. I couldn't sleep for a week after that incident and the creature still haunts me in my dreams to this day.
I'm pretty sure a lot of developers had an experience similar to mine. We all know that reading code which has different formattings and standards implemented is hard and tiring. In this tutorial we will learn how to stop this nightmarish beast from rising and how to fight it, if it's too late for prevention. We will focus on JavaScript today, but if you are interested in PHP make sure to check this great post from Maciek.
Linters
Linters are very handy tools. They can analyse the code and compare it with a provided configuration. They look for places where our code doesn't follow the defined styleguide, let us know about such places and can even fix them.
We will use one of the most popular JS linters - ESLint - combined with a styleguide made by Airbnb.
Setting up
To be able to use ESLint and test some code, first we need to create a new project using:
$ npm init
We are now able to install ESLint:
$ npm install eslint --save-dev
Configuring ESLint
We have ESLint installed in our project, but we need to configure it to use the desired styleguide. Fortunately there is a nice way to set it up:
$ ./node_modules/.bin/eslint --init
The configurator will ask us a couple questions ("❯" shows the selected answer):
? How would you like to use ESLint? To check syntax only To check syntax and find problems ❯ To check syntax, find problems, and enforce code style
? What type of modules does your project use? JavaScript modules (import/export) CommonJS (require/exports) ❯ None of these
? Which framework does your project use? React Vue.js ❯ None of these
? Where does your code run? (Press <space> to select, <a> to toggle all, <i> to invert selection) ❯◉ Browser ◯ Node
? How would you like to define a style for your project? (Use arrow keys) ❯ Use a popular style guide Answer questions about your style Inspect your JavaScript file(s)
? Which style guide do you want to follow? (Use arrow keys) ❯ Airbnb (https://github.com/airbnb/javascript) Standard (https://github.com/standard/standard) Google (https://github.com/google/eslint-config-google)
? What format do you want your config file to be in? (Use arrow keys) ❯ JavaScript YAML JSON
After these questions ESLint will ask us to install additional packages (of course we answer "yes") and create a new file - .eslintrc.js
. In my case it looks like this:
module.exports = { env: { browser: true, es6: true, }, extends: 'airbnb-base', globals: { Atomics: 'readonly', SharedArrayBuffer: 'readonly', }, parserOptions: { ecmaVersion: 2018, }, rules: { }, };
Linting the code
Before we use ESLint, we need to have some code to test. You can use it on any real project, but I've created an example file just for this purpose. You can download it here.
Now it's time for linting:
$ ./node_modules/.bin/eslint .
Whoa! That's a lot of errors! ESLint just checked all the files and showed us the lines that don’t meet the Airbnb styleguide requirements. In my case it looks like this:
1:8 error Unable to resolve path to module 'whatwg-fetch' import/no-unresolved 2:8 error 'foo' is defined but never used no-unused-vars 2:17 error Unable to resolve path to module './foo' import/no-unresolved 4:1 error Unexpected var, use let or const instead no-var 5:1 error Unexpected var, use let or const instead no-var 5:5 error 'b' is assigned a value but never used no-unused-vars 10:1 error Expected indentation of 2 spaces but found 4 indent 11:1 error Expected indentation of 2 spaces but found 4 indent 13:1 error Expected indentation of 2 spaces but found 4 indent 14:1 error Expected indentation of 2 spaces but found 4 indent 16:1 error Expected indentation of 2 spaces but found 4 indent 17:1 error Expected indentation of 2 spaces but found 4 indent 21:1 error Expected indentation of 2 spaces but found 4 indent 22:1 error Expected indentation of 2 spaces but found 4 indent 23:1 error Expected indentation of 4 spaces but found 8 indent 24:1 error Expected indentation of 2 spaces but found 4 indent 24:12 error Unnecessary 'else' after 'return' no-else-return 25:1 error Expected indentation of 4 spaces but found 8 indent 26:1 error Expected indentation of 2 spaces but found 4 indent 29:10 error 'run' is defined but never used no-unused-vars 30:1 error Expected indentation of 2 spaces but found 4 indent 30:5 warning Unexpected console statement no-console 31:2 error Newline required at end of file but not found eol-last ✖ 23 problems (22 errors, 1 warning) 17 errors and 0 warnings potentially fixable with the `--fix` option.
Each error on the list consists of line number, description and the rule's name. The full list of rules can be found here.
We have a lot of "indent" errors. It makes sense, because Airbnb styleguide advises to use 2 spaces for indentation. The thing is I like to use 4 spaces and don't want to change it. So let's tweak the configuration a little bit.
Changing the configuration
In order to use a different indentation we need to open the configuration file and overwrite the default rule. The documentation is very helpful in showing us how exactly we can change different settings. Here's the "indent" rule.
We just need to add our rule to the .eslintrc.js
file:
rules: { 'indent': ['error', 4] },
After running the linting command again we can see that a lot of errors has been resolved:
1:8 error Unable to resolve path to module 'whatwg-fetch' import/no-unresolved 2:8 error 'foo' is defined but never used no-unused-vars 2:17 error Unable to resolve path to module './foo' import/no-unresolved 4:1 error Unexpected var, use let or const instead no-var 5:1 error Unexpected var, use let or const instead no-var 5:5 error 'b' is assigned a value but never used no-unused-vars 24:12 error Unnecessary 'else' after 'return' no-else-return 29:10 error 'run' is defined but never used no-unused-vars 30:5 warning Unexpected console statement no-console 31:2 error Newline required at end of file but not found eol-last ✖ 10 problems (9 errors, 1 warning) 4 errors and 0 warnings potentially fixable with the `--fix` option.
Not that bad as before, but our code can still look better.
Automatic fixing
You've probably noticed a small message below the errors list - "4 errors and 0 warnings potentially fixable with the --fix
option". What a nice guy this ESLint! Can it be true that it want's to fix our errors for us? Well, we need to find out. Go ahead and add the suggested --fix
option:
$ ./node_modules/.bin/eslint example.js --fix
Wow, it really did fix our code! Not everything, but it's a great feature. It can save us a lot of time. The code is still not perfect though.
Fixing the code manually
In the ESLint output we can see that there are two errors, because it was unable to resolve paths to some modules. We need to investigate it. The modules are on top of the file:
import 'whatwg-fetch'; import foo from './foo';
It looks like we don't have these modules in the project. Moreover, we don't even use them. It should be safe to remove them.
Awesome! Our list of errors is getting smaller and smaller:
2:7 error 'b' is assigned a value but never used no-unused-vars 25:10 error 'run' is defined but never used no-unused-vars 26:5 warning Unexpected console statement no-console
As an exercise try to resolve the remaining errors by yourself 🙂
When we see no errors it means our work is done.
Conclusion
By using tools like ESLint we are able to enforce the same style of writing code in the whole project. Therefore, making the code style consistent and easier to look at.
Using such tools brings many benefits, for example, it saves time by eliminating the need of checking for code formatting issues during code reviews and improves overall readability. Also, when the project grows and new developers need to start coding, it is easier for them to follow the rules if they are the same over the whole project.
I encourage everyone to try it and explore overriding or even creating custom rules, depending on your preferences.
Co-authors of the post: Tomasz Kulka and Konrad Jaguszewski.