How to Kick-start a Next.js/TypeScript Project with ESlint, and Husky

Today, I'm gonna be sharing how I kickstart my Next.js app.

Although I'm new to Next.js, I've been writing React code with Create React App, Typescript, ESlint, and Husky for a while and am pretty much used to those systems. When it comes to linting, Next.js and Create React App might have their own optimal settings for ESlint, but I guess the fundamental rules of coding are almost the same for both of them. So I think I'm eligible to share how I create my Next.js app with those tools even though I'm new to the framework!

First off, create your Next.js project

To create a project, you have to run this command;

npx create-next-app [your app name]

Then, run the command below to create the src directory and move pages and styles directories into it because you will end up adding lots of directories later, and it will be kinda messy otherwise.

cd [your app name]
mkdir src && mv pages styles src

Your src directory should look something like this;

.
└─ src
    ├─ pages
    └─ styles

Add TypeScript

TypeScript has already been the de facto standard for React development to build your app safely, and there is no doubt about it.

So, run this command to add TypeScript in your Next.js project;

yarn add -D typescript @types/react @types/node

You have to add tsconfig.json in the root directory.

touch tsconfig.json

Replace .js extension with .tsx or .ts, and run yarn dev if you want to make sure Typescript works.

Here's my tsconfig.json;

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "baseUrl": "./",
    "paths": {
      "src/*": [
        "./src/*"
      ],
    }
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

The above is pretty much the same as the initial configuration that Next.js creates for you.

But there are some differences like I set "strict" to be true.

And here is my favorite part;

"compilerOptions": {
  ...,

  "baseUrl": "./",
  "paths": {
    "src/*": [
      "./src/*"
    ],
  }
}

This allows you to use absolute paths when importing your own components or functions in your tsx file (and you don't need to change the Webpack configuration). For those wondering why you should use absolute paths, read this article.

Add ESlint (with prettier)

Nothing special, just run these commands;

yarn add -D eslint prettier eslint-plugin-react
yarn add -D eslint-config-prettier eslint-plugin-prettier
yarn add -D @typescript-eslint/parser @typescript-eslint/eslint-plugin

And add .eslintrc.json to your root directory

touch .eslintrc.json

And this is my favorite ESlint setting;

{
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:prettier/recommended",
    "prettier"
  ],
  "plugins": [
    "@typescript-eslint",
    "react"
  ],
  "settings": {
    "react": {
      "version": "detect"
    }
  },
  "parser": "@typescript-eslint/parser",
  "env": {
    "browser": true,
    "node": true,
    "es6": true
  },
  "parserOptions": {
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "rules": {
    "react/react-in-jsx-scope": "off",
    "@typescript-eslint/explicit-module-boundary-types": "off",
    "prettier/prettier": [
      "error", {
        "doubleQuote": true,
        "endOfLine": "auto"
      }
    ],
    "react/no-unescaped-entities": "off",
    "no-console": "warn"
  }
}

My favorite parts are

  • "endOfLine": "auto" to make sure it won't throw an annoying "Delete " error
  • "doubleQuote": true to set double quote as the standard quotation
  • "no-console": "warn" to make sure I won't forget to delete console codes I used to check values

Let's move on!

Add Husky (with lint-staged)

Husky enables you to run specific commands before committing your code. Combined with lint-staged, which checks lint errors in your staged files, you can check or fix your codes that are going to be committed.

Run this command to download lint-staged first;

yarn add -D lint-staged

To configure how you check your files when committing, add this code to the bottom of your package.json.

"lint-staged": {
    "*.{ts,tsx}": "eslint --max-warnings=0 --ext .tsx --ext .ts --fix"
 }

And your package.json should look like this; ;

{
  ...,

  "dependencies": {
   ...,
  },
  "devDependencies": {
   ...,
  },
  "lint-staged": {
    "*.{ts,tsx}": "eslint --max-warnings=0 --ext .tsx --ext .ts --fix"
  }
}

By the way, I accept no errors or warnings when committing by adding --max-warnings=0 in the above code.

Next, you have to add and initialize husky by running this code;

npx husky-init && yarn

This will create a directory called .husky in the root directory.

In .husky/pre-commit, you have to add, yarn lint-staged.

So, husky/pre-commit will look like this;

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint-staged

If you want to make sure husky and lint-staged you just added work, try committing erroneous codes. If it stops you from committing bad codes, that means it's working.

If you're done taking those steps, you're good to go!!

Conclusion

That's it for today's post. I'm new to Next.js, and there might be some changes to this post in the future. But I hope this article helps some Next.js developers kick-start their projects with the necessary tools!

Of course, there is no perfect way to develop a web app (not just with Next.js but other frameworks as well) but trying to find best for you is really important.

So, keep coding!