ESLint x Prettier: The Right Way To Start A JavaScript Project
Tags: javascript, eslint, prettier
Published: 2024-06-29 06:06:39

> _In 2022, **ESLint** (`v8.21.0`) introduced a new configuration system nicknamed "Flat Config." This post is dedicated to this edition._

It's very easy to initialize a new JavaScript project; you just need a code editor, a runtime environment, a terminal, and you're good to go!

Similarly, it's just as easy to ruin a web project by making the code unreadable, unmaintainable, and thus generating technical debt...

Indeed, since JavaScript is a very loosely typed language, anything is quickly allowed:

- Omitting semicolons at the end of lines;
- Using single and double quotes within the same block of code;
- Declaring variables but not using them;
- Lines of code that are too long...

This flexibility of the language is both a strength and a weakness, which should be addressed by defining best practices before development begins. Thus, properly structured code will promote collaborative work and the scalability of the project.

To achieve this, there are two essential tools that will bring rigor to your web project: the **linter** and the **formatter**.

### Definitions

**Linter**: A code analysis tool that detects syntax issues.

**Formatter**: A tool that formats the code to make it readable.

> _**NB**: I insist on the fact that these are two distinct tools. Although the **linter** can format some parts of the code, it isn't its role. This task is reserved for the **formatter**._

## Starting Your JavaScript Project

To illustrate how each tool works, I suggest creating a new JavaScript project (without a _framework_) using [ViteJS](https://vitejs.dev).

```sh
npm create vite@latest my-awesome-project -- --template vanilla
```

Like a recipe, let's install the initial dependencies provided with **ViteJS**, and then add the new libraries: [ESLint](https://eslint.org) and [Prettier](https://prettier.io)!

```sh
npm install --save-dev eslint @eslint/js prettier eslint-config-prettier eslint-plugin-prettier
```

> _**NB**: For future reference, a project scaffolded with ViteJS operates directly in `module` mode. This means your `.js` files are implicitly `.mjs` files. Likewise, you will need to explicitly name your files `.cjs` to write with CommonJS syntax._

Once the **linter** and **formatter** dependencies are correctly installed, you still need to create their respective configuration files: `eslint.config.js` and `prettier.config.js`.

> _**NB**: ESLint and Prettier configuration files can take several forms, including the following: `.eslintrc.js`, `.eslintrc.cjs`, `.eslintrc.json`, `.eslintrc.yaml`, `.prettierrc`, `.prettierrc.json`, `.prettierrc.yaml`, `.prettierrc.js`, `prettier.config.cjs`, or `.prettierrc.toml`._

## Linter Configuration

Let's start by setting up the **linter** to use it in our new project.

Here is an initial version of the `eslint.config.js` file:

```js
import globals from 'globals';
import js from '@eslint/js';

export default [
  {
    files: ['**/*.js', '**/*.jsx']
  },
  {
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.node
      }
    }
  },
  js.configs.recommended,
  {
    rules: {
      'no-console': 'warn'
    }
  }
];
```

This initial configuration is sufficient to run ESLint from a new terminal to check the syntax of JavaScript files: `npx eslint [file|dir]`

I recommend adding this execution as a script in your `package.json`: `npm run lint`

```json
{
  "name": "my-awesome-project",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "lint": "eslint"
  },
  "devDependencies": {
    "@eslint/js": "^9.5.0",
    "eslint": "^9.5.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-prettier": "^5.1.0",
    "prettier": "^3.3.0",
    "vite": "^5.2.0"
  }
}
```

By adding a `console.log()` statement in a `.js` file of your project, you should get the following result after invoking the **linter**.

```sh
/home/dmnchzl/my-awesome-project/counter.js
  5:5  warning  Unexpected console statement  no-console

✖ 1 problem (0 errors, 1 warning)
```

## Prettier Configuration

Now, let's set up the formatter by editing the `prettier.config.js` file:

```js
export default {
  arrowParens: 'avoid',
  printWidth: 120,
  semicolons: true,
  singleQuote: true,
  trailingComma: 'none',
};
```

> _**NB**: Prettier has a default configuration. In the above file, I only override the parameters I want for my project._

Similar to ESLint, you now just need to run Prettier (`npx prettier --write [file|dir]`) to format the JavaScript files.

It's also possible to save a new script in your `package.json`: `npm run format`

```json
{
  "name": "my-awesome-project",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "lint": "eslint",
    "format": "prettier --write \"**/*.{js,jsx}\""
  },
  "devDependencies": {
    "@eslint/js": "^9.5.0",
    "eslint": "^9.5.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-prettier": "^5.1.0",
    "prettier": "^3.3.0",
    "vite": "^5.2.0"
  }
}
```

## ESLint x Prettier

The last step is to interface the two tools! This means controlling the **formatter**'s syntax through the **linter**.

To do this, simply add Prettier's configuration to the ESLint rules (don't forget to enable the plugin):

```js
import globals from 'globals';
import js from '@eslint/js';
import prettierRecommended from 'eslint-plugin-prettier/recommended';

export default [
  {
    files: ['**/*.js', '**/*.jsx']
  },
  {
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.node
      }
    }
  },
  js.configs.recommended,
  prettierRecommended,
  {
    rules: {
      'no-console': 'warn',
      'prettier/prettier': [
        'warn',
        {
          arrowParens: 'avoid',
          printWidth: 120,
          semicolons: true,
          singleQuote: true,
          trailingComma: 'none'
        }
      ]
    }
  }
];
```

And there you go! From now on, ESLint will be able to alert you whenever the Prettier format is not respected.

Try removing one or more semicolons at the end of a line or misaligning your lines...

```sh
/home/dmnchzl/my-awesome-project/counter.js
  2:18  warning  Insert `;`                      prettier/prettier
  3:22  warning  Replace `(count)` with `count`  prettier/prettier
  4:20  warning  Insert `;`                      prettier/prettier
  5:46  warning  Insert `;`                      prettier/prettier
  6:4   warning  Insert `;`                      prettier/prettier
  7:67  warning  Insert `;`                      prettier/prettier
  8:16  warning  Insert `;`                      prettier/prettier
```

Now you know that the rigor of a web project does not come alone; it also relies on many tools, including the **linter** and the **formatter**.

To go further, I invite you to install the [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) and [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) extensions, depending on your favorite code editor (Visual Studio Code in my case). This way, you will benefit from additional features such as syntax highlighting when linting rules are not followed, or automatic code formatting upon file saving.

Enjoy 👍