Locastic Sep 29

Bulletproof static code analysis for React

4 min read –

First of all, let’s clarify what even is static code analysis.

Wikipedia says:

Static program analysis is the analysis of computer software that is performed without actually executing programs, in contrast with dynamic analysis, which is analysis performed on programs while they are executing. In most cases the analysis is performed on some version of the source code, and in the other cases, some form of the object code.”

In other words, static analysis simply parse the code you wrote, validate it against the rules you defined, and gives you immediate feedback whether or not your code meets defined requirements (typos and type errors while you write the code)

I like the opinion that static code analysis is the first and lowest level of the testing pyramid. Unlike more advanced levels of testing like integration or unit testing, static analysis can be performed against the code without actually running it (no servers or build processes). That alone makes it the fastest and simplest testing tool.

https://testingjavascript.com/

The way it works is quite simple:

  • compiler finishes the “static analysis” phase
  • product is the AST (Abstract syntax tree)
  • the tree gets traversed and validated against the defined rules

Static analysis for React

There are two things I set up by default on every React project I work on:

  • ES Lint – code linter for enforcing certain code style
  • Prettier – code formatting tool

ES Lint is probably one tool you always want to have present in the codebase. It analyzes the code and quickly finds problems. The fixes it provides are syntax aware which means it will not cause funky bugs. And the best part – you can adjust it according to your needs, which means it’s fully customizable. You can define the set of rules, extend some popular set of rules, etc.

Pettier on the other hand is used to ensure you have consistent code style trough out the project without having to worry different team members will commit different code styles to the codebase. For example, you want the same indentation, line length, single or double quotes, etc.

Setup

npm install --save-dev eslint prettier

In order for Prettier to work with ES Lint, prettier-plugin needs to be installed as well:

npm install --save eslint-plugin-prettier

ES Lint configuration

To configure the ES Lint we can use .eslintrc, a file which would look something like this:

{
    "env": {
      "browser": true,
      "es6": true
    },
    "parser": "babel-eslint",
    "extends": ["airbnb", "prettier", "prettier/react"],
    "globals": {
      "Atomics": "readonly",
      "SharedArrayBuffer": "readonly"
    },
    "parserOptions": {
      "ecmaFeatures": {
        "jsx": true,
        "modules": true
      },
      "ecmaVersion": 2018,
      "sourceType": "module"
    },
    "plugins": ["react", "prettier"],
    "rules": {
      "prettier/prettier": "error",
      "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
      "react/forbid-prop-types": [0, { "forbid": ["any"] }],
      "react/prop-types": 0,
      "react/destructuring-assignment": 0,
      "react/sort-comp": 0,
      "react/no-did-update-set-state": 0,
      "react/jsx-boolean-value": 0,
      "prefer-template": 1,
      "prefer-const": 1,
      "no-unused-vars": 1,
      "import/prefer-default-export": 1,
      "import/no-extraneous-dependencies": 1,
      "import/no-unresolved": 1
    }
  }

Using this file, everything is configurable. Under the rules key, we can change the certain rule to display as a warning, error, or not display at all (disable it). The pluginskey is used to define the set of plugins we want to use (notice the “prettier” plugin we installed before). If you’d like to extend some popular set of ES Lint rules, let’s say Airbnb’s one, you can do that under the extends key. You can find more about configuring the ES Lint on the https://eslint.org/.

Now the linter is all set up, how to run it?

You can add the following lines to you package.json scripts:

"scripts": {
	"lint" : "eslint ." //to lint all files
	"lint:fix" : "eslint --fix", //to fix all eslint errors
}

If you’re using the VS Code you can install the ES Lint plugin for it (probably other code editors have it too ).

The files you don’t want to lint you can ignore using .eslintignore:

dist
node_modules
public

Prettier configuration

It’s worth to mention that Prettier is not as configurable as ES Lint, but it really has all you need for code formatting. We can use .prettierrc file to configure it:

{
	"printWidth": 80,
	"tabWidth": 2,
	"useTabs": true,
	"semi": true,
	"singleQuote": true,
	"trailingComma": "none",
	"bracketSpacing": true,
	"newline-before-return": true,
	"no-duplicate-variable": [true, "check-parameters"],
	"no-var-keyword": true,
	"arrowParens": "avoid",
}

You can find full set of options available on the https://prettier.io/docs/en/options.html

Again, if you are using VS Code there is a Prettier plugin available to install but there are also commands to run the code formatting manually:

//package.json

"scripts": {
	"prettier": "prettier --check",
	"prettier:fix": "prettier --write"
}

For ignoring certain files you can use .prettierignore file (in the same way like .eslintignore).

And there you go. Everything is set up, you are good to start coding with confidence the ES Lint gives you by checking you don’t make silly mistakes like redeclaring the same variable, not closing bracket, or using something that doesn’t exist, while Prettier will make sure your code is readable and consistent trough out the whole project.

Bonus

There is one more thing I like to add to make sure the code with liniting errors and unformatted code cannot be committed to the version control provider at all. It’s the Husky, git hooks tool that allows you to run the scripts before commit, push, etc. Let’s take it a bit further with Lint Staged which allows us to check only staged files. The configuration goes like this:

First, installation:

npm install --save-dev husky lint-staged

Second, package.json:

{
	....

	"lint-staged": {
			"*.+(js|jsx)": [
      "eslint --fix",
    ],
    "*.+(json|css|md)": [
      "prettier --write",
    ]
	},
		
	"husky": {
	   "hooks": {
	      "pre-commit": "lint-staged"
    }
  }
}

That’s it. Now every time the code is committed hook will execute, validate the files you want to commit and either fix the errors for you or warn you there is some error that can’t be auto fixed.