Using ESLint and Prettier in a TypeScript Next.js Project with pre-commit hooks
Tags: nextjs, react, typescript, eslint
Published: 2020-05-21 03:48:06

[Next.js](https://nextjs.org/) has recently become my go to choice for new React projects. Lately I've found myself setting up this boilerplate for using TypeScript and ESLint with prettier over and over again, so I felt it may be useful for anyone out there who also uses this or a similar setup.

If you just want to see the code, here's the link to the [repo on github](https://github.com/diondree/nextjs-boilerplate).

# Next.js Instructions

You can use the Next.js CLI and use their TypeScript example but for me that comes with a few extra files that I'd rather not have to delete :satisfied:
 
So in an empty and git initialized npm project, add the Next.js dependencies using yarn or npm (I prefer yarn). 
*N.B. add `node_modules` to `.gitignore`*

```bash
yarn add next react react-dom
```

Next we add the TypeScript package along with the React and Node types as `dev` dependencies
```bash
yarn add -D typescript @types/react @types/react-dom @types/node
```

Add the following TypeScript configuration (create tsconfig.json file)
```json
{
  "compilerOptions": {
    "allowJs": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "lib": ["dom", "es2017"],
    "module": "esnext",
    "moduleResolution": "node",
    "noEmit": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "strict": true,
    "target": "esnext"
  },
  "exclude": ["node_modules"],
  "include": ["**/*.ts", "**/*.tsx"]
}
```

Now we can add the Next.js development and build scripts to your `package.json`
```json
"scripts": {
  "dev": "next",
  "build": "next build",
  "start": "next start"
}
```

Create the pages directory inside a `src` directory (this is not the default but Next.js supports it) and create the index page file
```bash
mkdir -p src/pages && touch src/pages/index.tsx
```

And place the following boilerplate in the `index.tsx` file
```ts
import { NextPage } from 'next';

const IndexPage: NextPage = () => (
  <div>
    <h1>Hello Next.js 👋</h1>
  </div>
);

export default IndexPage;

```

At this point you should have a working Typescript Next.js project :raised_hands:

# Linting Setup
Now that we have our working project, we can add the linting setup to it.

Add the base dependencies for eslint to work with typescript.
```bash
yarn add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
```

For my linting setup I like to use the `jsx-a11y` for accessibility rules, `react-hooks` for rules using react hooks and `prettier` for styling.

Add the following as `dev` dependencies
```bash
yarn add -D prettier eslint-config-prettier eslint-plugin-jsx-a11y eslint-plugin-prettier eslint-plugin-react eslint-plugin-react-hooks
```

Then create a prettier configuration file (.prettierrc.js or .prettierrc). This is my preferred setup:
```js
module.exports = {
  semi: true,
  trailingComma: 'es5',
  singleQuote: true,
  printWidth: 80,
  tabWidth: 2,
  useTabs: false,
};
```

Next we create the .eslintrc.js with your ESLint configuration (or .eslintrc.json). You can see the configuration I use [here](https://gist.github.com/diondree/1de24e93c354b7986f4010cd0beec230).

Add a lint and optionally a lint-fix script to your `package.json`. Your scripts should now resemble:
```json
"scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start",
    "lint": "eslint src --ext .ts,.tsx",
    "lint:fix": "npm run lint -- --fix"
  },
```

You can now run `yarn lint` to test the ESLint setup. If you used the same `index.tsx` file as I did you should see an error from `jsx-a11y` referring to the emoji. Leave it for now in order to test our pre-commit hook next.

Install `huksy` and `lint-staged` as `dev` dependencies
```bash
yarn add -D husky lint-staged
```

Now add the following `husky` and `lint-staged` configuration to your `package.json` (I use the ESLint fix option for my hooks, you can also just run the lint on your code)
```bash
"lint-staged": {
    "src/**/*.{ts,tsx}": "npm run lint:fix"
 },
 "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
 }
```

At last, now we can try to commit our code to test the pre-commit hooks. Simply `git add` && `git commit` your code to check if the hooks execute. You should see your pre-commit hook fail with the same error as above. You can simply follow the recommendation or remove it and you should be fine.

# Conclusion
Thank you for reading and I hope you found value in the article. This was my very first tech blog post. Please let me know if you have any feedback or things I can do to improve.