Standardize Your Next.js Project with ESLint and Husky
Tags: nextjs, javascript, typescript, webdev
Published: 2022-01-30 12:33:13

## Disclaimer

> In this article, I’ll focus on Next.js (using Typescript) based project. You can adapt it to your own needs based on your project source code and the problem that you’ve faced.
> 

## Introduction

Based on my experience in the software development world, Javascript (and Typescript) is the “wildest” programming language. We can use any code styles or conventions by our own preference in every project if we use Javascript.

When I work on a personal project, actually it’s not a big problem because I code for myself and only me who know the code, LOL. But imagine this, how if I have to work in a team with several people and each of them has their own code style? BOOOM, it will be chaos right?

This is just a simple reason why we need a standardized convention in our project source code as software engineers. I think it’s a common problem that needs to be reminded so as a developer we have to keep our code structure clean as has been set.

## Why We Need Standardization In Our Project Source Code?

Before we go too far, I think we have to start with “why” first. Why do we need the standardized convention in our code? Here’re the whys.

### Every Team Member Has Their Own Code Style

Like I’ve told in the Introduction section when I was making my personal projects, I code for myself so maybe I can use whatever code style I like. But everything changes when I have a full-time job and have to work in a team with several people. Every team member has their own code style and it may be confusing when I got a task and need to understand someone’s code that has a very different style.

Not only me actually, when other teammates read my code, they were also confused with my code style, LOL. **This is why we need to make an “agreement” so we can use a consistent code style in our code base.**

### To Increase Maintainability and Readability

I have been worked at a software house company that has a project-based work culture. Our task is finished when the requested app is delivered to the client.

I was a newbie junior frontend engineer at that time and I code with barbaric style. In my mind, I just have to finish and deliver it to the client before the deadline. That was a dark moment in my career life, hahaha.

The situation changes when I switch jobs to another company and now I’m working in an in-house company that has their own product that needs to be developed. The main focus is change now.

In the previous company, my main focus is just to code and deliver. But in the current company, I also have to think about how to make my code is maintainable so it will be easier to be improved or updated when needed.

The answer is quite simple, make and follow the code convention so the code style in the project code base is consistent even it was developed by different people. **The consistent code style makes it readable, and if it’s readable, it will be easier to be maintained.**

### Not Only Code but Commit Message Also Need To Be Standardized

When working with a team, it’s important to tell the informative message when pushing a commit to the Github (or Gitlab) repository. **The best code style is useless if the commit message is bad.** Other team members don’t understand the changes that you’ve made, and it can cause confusion and chaos in the future.

Thankfully, there’s [Conventional Commit](https://www.conventionalcommits.org/en/v1.0.0/) that can help the developers to make a proper commit message before they push their code to the Git Repository. 

## How To Standardize The Project Source Code?

I’ll tell you based on my experience as a front-end engineer. Luckily there are some tools that can help us to make the code convention. Here’s what I usually use.  

- [Prettier](https://prettier.io/) (Code Formatter)
- [ESLint](https://eslint.org/) (Linter for JS-based project)
- [Next Lint](https://nextjs.org/docs/basic-features/eslint) (built-in linter for Next.js)
- [Husky](https://github.com/typicode/husky) (automated linter trigger)
- [Lint Staged](https://github.com/okonet/lint-staged) (run linter before commit)
- [Commit Lint](https://commitlint.js.org/#/) (check the commit message before committing)

> For giving an example purpose, I’ve prepared a simple Next.js (Typescript) project. You can use https://github.com/yehezkielgunawan/next-tailwind-polos if you want to try to standardize the source code using those tools. You can clone it to your local device and don’t forget to install the dependencies using `yarn` or `npm install`

Here’s what we’ll do in the next section:

- Configure [Prettier](https://prettier.io/docs/en/install.html)
- Configure base [ESLint](https://bobobox.atlassian.net/wiki/spaces/BD/pages/2520154113/Frontend+Recommended+Code+Style+Guide+React+Based#In-Next.js-Project-[TYPESCRIPT-Based]) rules
- Install & configure the base [husky](https://typicode.github.io/husky/#/) setting (*Reference: Husky setting [Yehez-Tailwind-Starter](https://github.com/yehezkielgunawan/yehezgun-new/tree/main/.husky)*)
- Install & configure [lint-staged](https://github.com/okonet/lint-staged) and [commitlint](https://commitlint.js.org/#/guides-local-setup)

> In the steps below I’ll use yarn, actually, you can just adapt it by your preference if you use npm. You can see the official docs so you can match them by your need.

### Prettier Configuration

I assume that you’ve already cloned the example project source code, so I will focus on the tool's functionality.

Make sure you’re open the project folder through VS Code or your terminal, then run `yarn add --dev --exact prettier`. Then create a file named `.prettierrc.json` in the root folder, or you can just run `echo {}> .prettierrc.json` in your terminal.

In the `.prettierrc.json` file, you can fill the configuration like below or you can fill it by your needs (reference: [Prettier Config Options](https://prettier.io/docs/en/options.html)).

```json
{
  "endOfLine": "lf",
  "semi": true,
  "singleQuote": false,
  "tabWidth": 2,
  "trailingComma": "es5"
}
```

Now, you can just run `yarn prettier --write [directory scope]` to format your code. Or if you use VS Code, you can set **Format on Save** in your VS Code Settings. You also can use the shortcut to manually format the file (using VS Code) by pressing `Shift + Option + F` (in MacBook) or `Shift + CTRL + F` (in Windows).

### Configure The Base ESLint Rules

Because we use Next.js we will use [ESLint for Next.js](https://nextjs.org/docs/basic-features/eslint). But luckily in the newest Next.js version, it has automatically installed when we initiate the project. So in this case, we just focus on the `eslintrc.json` file wherein the root project.

But make sure, the `lint` command exists in the `package.json` file.

```json
"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  }
...
```

Here are my ESLint rules in `eslintrc.json`. You don’t have to imitate this 100%, just match it by your own preference or current needs.

```json
{
  "env": {
    "node": true
  },
  "extends": [
    "next/core-web-vitals",
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "parser": "@typescript-eslint/parser",
  "plugins": ["import", "unused-imports", "@typescript-eslint"],
  "settings": {
    "import/resolver": {
      "node": {
        "extensions": [".js", ".jsx", ".ts", ".tsx"],
        "moduleDirectory": ["node_modules", "src/"]
      }
    }
  },
  "rules": {
    "no-unused-vars": "off",
    "@typescript-eslint/no-unused-vars": "off",
    "@typescript-eslint/explicit-module-boundary-types": "off",
    "@typescript-eslint/no-non-null-assertion": "off",
    "@typescript-eslint/no-inferrable-types": "off",
    "@next/next/no-img-element": "off",
    "unused-imports/no-unused-imports": "error",
    "unused-imports/no-unused-vars": [
      "warn",
      {
        "vars": "all",
        "varsIgnorePattern": "^_",
        "args": "after-used",
        "argsIgnorePattern": "^_"
      }
    ],

    "no-eq-null": "warn",
    "import/order": [
      "warn",
      {
        "groups": [
          ["builtin", "external"],
          "internal",
          "parent",
          ["sibling", "index"],
          "object"
        ],
        "newlines-between": "always",
        "alphabetize": {
          "order": "asc",
          "caseInsensitive": true
        }
      }
    ],
    "complexity": "warn",
    "no-console": ["error"]
  }
}
```

In this case, I use third-party ESLint plugins like [import](https://www.npmjs.com/package/eslint-plugin-import), [unused-import](https://www.npmjs.com/package/eslint-plugin-unused-imports), and [typescript-eslint](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin).

After the config process is finished, you can run `yarn lint` to check if your code is already matched with the ESLint rules or not. You can also run `yarn lint --fix` to automatically fix your code based on the rules that have been set. Remember that sometimes we need to manually edit the code, so don’t overly rely on the automated fixing code.

### Configure Husky Base Setting

Want some automation addition? I usually use [Husky](https://typicode.github.io/husky/#/) to automate the checking process before committing or pushing to the Github Repository.

Because we’re using yarn, we’ll install it by running `npx husky-init && yarn` in the terminal. It will automatically generate the `prepare` command in `package.json` and a base pre-commit config.


![husky install](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mow4oovc9qxz5omym7vt.gif)

After that, we’ll install the [Lint Staged](https://github.com/okonet/lint-staged) to trigger and run lines on git staged files by executing `npx mrm@2 lint-staged`. It will automatically generate the base command triggers in `pre-commit` husky config file. After that, you can delete or modify the content by your own preference. After that, it will run the linter before the commit process. So you have to make sure that your code is matched with the linter rules.


![Lint staged install](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tjua26xupptx6ldnzm8u.gif)

Like I’ve mentioned before, not only code, we also need to standardize our commit message before pushing it to the Github repository. So we’ll set [Commit Lint](https://commitlint.js.org/#/guides-local-setup) by executing `yarn add --dev @commitlint/config-conventional @commitlint/cli` in the terminal.

Don’t forget to set the commitlint config as our base commit config by running this command in the terminal.

```bash
echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
```

Now integrate the commit lint into the husky config by executing `yarn husky add .husky/commit-msg 'yarn commitlint --edit $1'` . It will generate a new husky config file named `commit-msg`.


![commit-msg](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/582zmbmylmh0vtdomfrc.png)

Now you cannot make any “barbaric” commit message anymore, LOL.

![commitlint](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iydc23euxo6bbjaoxf3k.png)

Want to add some additional config before pushing your code to Git Repository? For example, I run `npx husky add .husky/pre-push 'yarn lint'` to generate the husky config that triggers the linter before pushing my code.


![pre-push](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2vwks591pfcxon0h0oui.gif)

And YEAH!!! IT’S FINISHED. Note that, you don’t have to imitate my method 100%. You can match it with your needs.

## Closing

Actually this is not an absolute way. There are so many ways or even tools that also help us to standardize our source code. Hope it helps you guys. I’m sorry if still there’s some grammar error. I’m still learning how to write in English properly, hahaha. Let me know if you want to discuss something in the comment section.