[Frontend Note] Frontend engineering: ESLint + Prettier

Set up ESLint and Prettier as the foundation of your frontend project conventions

Posted by Jamie on Saturday, September 10, 2022

Frontend engineering: ESLint + Prettier

Preface

For a frontend project, if you are a one-person team handling all the code yourself, then honestly you can write it however you want — as long as the program runs. But for a team that collaborates with multiple people, or even with outsourced contributors, if you don’t set basic frontend conventions beforehand, then in the mild case people won’t know where to import a component from or where to find the function they need; in the severe case the code becomes hard to read, leading to a situation where the code can only be maintained and modified by the engineer who originally wrote it (commonly known as Legacy Code).

Establishing clear code conventions at the very beginning of a project not only guarantees a baseline of readability and makes maintenance easier, but it also reduces some of the disputes that come up during code review (harmony in the team is the most important thing, right?).

The most basic frontend conventions are setting up Eslint and Prettier — one is a code-quality checker, the other is a code formatter.

Basic ESLint and Prettier setup

Installing dependencies

When using Eslint and Prettier together, some of the settings around “code quality” and “code formatting” will conflict. As shown below: image (image from logrocket)

So we need to resolve this conflict first. The required npm dependencies are eslint, eslint-plugin-prettier, eslint-config-prettier, and prettier.

npm i -D eslint eslint-plugin-prettier eslint-config-prettier prettier

The role of each dependency is shown in the table below:

Dependency Purpose
eslint The ESLint core library
eslint-plugin-prettier Adds Prettier’s rules into ESLint as a plugin
eslint-config-prettier Disables all ESLint rules that conflict with Prettier
prettier The Prettier core library

ESLint and Prettier configuration

After installation, add .eslintrc.js to the project root (you could also use .eslintrc.json, but JSON files cannot have comments, so I prefer .js). Then, following the official recommendation from eslint-plugin-prettier, write the following in .eslintrc.js:

module.exports = {
  // If you have other extends, remember to put prettier last
  "extends": ["plugin:prettier/recommended"]
  "plugins": ["prettier"],
  "rules": {
    "prettier/prettier": "error"
  }
}

Later, if you want to add Prettier rules (e.g. tab=4space), you can write them under the prettier option in "rules":

	"prettier/prettier":[
		"error",
		{
			tabWidth: 4,
		}
	]

Or, simply add a .prettierrc file in the project root and put the rules there.

Bonus: other configuration items in .eslintrc.js

module.exports = {
    env: {},
    extends: [],
    overrides: [],
    parser: '',
    parserOptions:{},
    plugins: [],
    rules: {},
    settings: {},
}
  • env: Defines the environment, telling ESLint which environment variables are available. The full documentation is on the official site. Common ones are:
    • browser — browser global variables, such as window
    • node — NodeJS global variables
    • es6 — ECMAScript 6 features
    • jest — Jest global variables
  • extends: Checks specified file types according to the specified rule sets, e.g. checking ts code with @typescript-eslint/recommended. Items in extends can be thought of as “importing someone else’s already-configured .eslintrc.js”.
    • If rules conflict, the later ones override the earlier ones. That’s why the official guide recommends putting prettier last.
  • plugins: To use third-party plugins in ESLint you have to install them via npm first; you can think of it as “loading the plugin”, but it only takes effect after being defined in extends and rules.
  • rules: The rules being applied.

    • Suppose you’ve installed @typescript-eslint/eslint-plugin via npm — how should extend, plugin, and rule be configured?

      {
          "plugins": [
              "@typescript-eslint"  // plugin declaration    
           ],
          "extends": [
              "eslint:recommended",
              "plugin:@typescript-eslint/recommended" // refers to a category of config objects within the plugin
          ],
          "rules": {
            "@typescript-eslint/rule-name": "error" // applies a specific rule from the @typescript-eslint plugin
          }
      }
      
  • overrides: Lets a group of files (usually based on a filename naming pattern) be excluded from rules, or be checked with a different rule set.

    • Disable a particular rule for xxx.test.js files:

      "rules": {...},
      "overrides": [
      {
        "files": ["*-test.js","*.spec.js"],
        "rules": {
          "no-unused-expressions": "off"
        }
      }
      ]
      
  • parser: ESLint inspects code, and the parser’s job is to convert code into an ESTree, which ESLint then walks and validates.

  • parserOptions: Supplements the parser. For example, the default ESLint doesn’t support every latest ES6 syntax, so if needed you can add { "parserOptions": { "ecmaVersion": 6 } }.

    • Settings for ESLint to parse TypeScript:

      parser: '@typescript-eslint/parser',
      parserOptions: {
          ecmaVersion: 'latest',
          sourceType: 'module',
      },
      
  • settings: A current use case is when a project uses webpack.config.js or tsconfig.json to set up alias imports (ex: import xxx from "@/components/xxx"), causing ESLint to throw errors. In that situation you can use settings to solve the Unable to resolve path to module problem.

    • When using webpack.config.js to set up path aliases, first install eslint-import-resolver-webpack via npm, then update settings in .eslintrc.js:

      "settings": {
      "import/resolver": {
          "webpack":{
              "config":"webpack.config.js"
          }
      }
      }
      
      

VS Code settings

Assuming everyone in your project team uses VS Code as the IDE, you can configure VS Code to automatically fix ESLint and Prettier errors on every save:

  1. Add a folder named .vscode at the project root
  2. Add a settings.json inside that folder
  3. Write the following JSON:

    {
    "editor.codeActionsOnSave": {
      "source.fixAll.eslint": true
    },
    "eslint.alwaysShowStatus": true,
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
    "editor.formatOnSave": true
    }
    
    

(The line "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" } is so that ESLint can format some JS files in the project root, like webpack.config.js, etc.)

Conclusion

Basically, the ESLint+Prettier setup is done — the rest comes down to team consensus.

In the next post, we will look at what additional setup is needed in a Vue/React + Typescript project.

ChangeLog

  • 20220911 - added conclusion
  • 20220901 - init
  • 20260501–translate by claude code