Published August 24, 2024 (8 months ago) 3 min read
There are two things to consider when writing code:
Code correctness is essential. Unless you intentionally make your code unreadable, readability is equally important—especially if you are not the only one contributing to the codebase.
This is where formatters and linters become essential tools.
In this guide, I will discuss how to set up Prettier (formatter) and ESLint (linter) in a Next.js project. I will also cover how to run your formatters and linters before you commit your code to Git.
Let's start!
First, let's create a new Next.js project. I will be using pnpm
, but you can use your preferred package manager.
sh
1pnpm create next-app@latest
Select 'Yes' when prompted to use ESLint. This will automatically set up ESLint for you. The rest of the options are up to your preference.
Let's add Prettier to our project. To install, run the following command in your terminal:
sh
1pnpm add --save-dev --save-exact prettier
We usually exclude dependency and build output files because we only want to format the code we maintain.
To skip formatting these files, add a .prettierignore file with the following contents in your root directory:
1/node_modules
2/.pnp
3.pnp.js
4
5# testing
6/coverage
7
8# next.js
9/.next/
10/out/
11
12# production
13/build
14
15# vercel
16.vercel
17
18# typescript
19next-env.d.ts
Prettier has its defaults, but we can configure it according to our preference. Add a .prettierrc file in the root directory of your project and add your preferred configurations. In my case, I have this:
json
1{
2 "endOfLine": "lf",
3 "semi": false,
4 "singleQuote": false,
5 "tabWidth": 2,
6 "trailingComma": "es5",
7}
8
Now, we can format all the supported files in our codebase by running the following command:
sh
1pnpm exec prettier . --write
Add this command into the package.json scripts:
json
1{
2...
3 "scripts": {
4 "dev": "next dev",
5 "build": "next build",
6 "start": "next start",
7 "lint": "next lint",
8 "format": "pnpm exec prettier . --write"
9 },
10...
11}
12
Now, we can run the following command to format the files:
sh
1pnpm format
Next.js has already set up and configured ESLint for us when we created the project. However, ESLint has some rules that conflict with Prettier so we have to add a plugin that resolves these conflicts.
Install eslint-config-prettier:
sh
1pnpm add --save-dev eslint-config-prettier
Next, add prettier
to our eslintrc.json file:
json
1{
2 "extends": ["next/core-web-vitals", "prettier"]
3}
4
lint-staged
is a tool we can use to run operations, such as formatting and linting, on staged git files. To install, run the following command:
sh
1pnpm install --save-dev lint-staged
We need to specify the operations we want lint-staged to run on the staged Git files. To do this, add a lintstagedrc.mjs file at the root directory of your project and add the following contents:
javascript
1import path from "path";
2
3const buildEslintCommand = (filenames) =>
4 `next lint --file ${filenames
5 .map((f) => path.relative(process.cwd(), f))
6 .join(" --file ")}`;
7
8export default {
9 "**/*.ts?(x)": [
10 "prettier --write",
11 () => "tsc -p tsconfig.json --noEmit",
12 buildEslintCommand,
13 ],
14 "**/*.{js,jsx}": ["prettier --write", buildEslintCommand],
15};
16
When we run lint-staged using the following command:
sh
1pnpm exec lint-staged
*.ts
or *.tsx
files, it:*.js
or *.jsx
files but it skips the type checking.Manually running lint-staged every time we commit our code can be quite annoying, and there's a chance we might forget to run it. Husky is a tool that automates this process.
First, we install it:
sh
1pnpm add --save-dev husky
Then, run the script, which will automatically set up Husky in our project:
sh
1pnpm exec husky init
In the .husky/pre-commit file, add the following so that Husky runs lint-staged when committing our code.
1npx lint-staged
Let's try adding a code with error:
typescript
1// src/app/test.tsx
2
3// Let's import a library that does not exist
4import something from "something"
5
When we try to add and commit the code, we should get a nice error preventing us from doing so:
This time, let's replace our code with a correct but unformatted one:
typescript
1// src/app/test.tsx
2const person = {name: "John Doe", email: "[email protected]", description: "A really long string so that this triggers the formatter to break this object out into multiple lines"}
After adding and committing our code, it should be formatted. In my case, it looks something like this:
typescript
1// src/app/test.tsx
2const person = {
3 name: "John Doe",
4 email: "[email protected]",
5 description:
6 "A really long string so that this triggers the formatter to break this object out into multiple lines",
7};
8
Now, you can continue adding code to your project, knowing it will be formatted and error-checked whenever you commit.