In this post, we will be setting up Next.js with Husky and lint-staged to run ESLint and Prettier whenever we commit a file.
If you want to take a look at the final product first, or if you don't care about the step-by-step, here's the accompanying repo.
You probably already know, or can imagine, the advantages of automatically linting and formatting each and every piece of code commited to your repo. So I won't convince you of its merits here, but get straight into the action.
Set up a new Next.js Project
Start by setting up a new Next.js project if you don't have one yet:
npx create-next-app --typescript
# or
yarn create next-app --typescript
Here, we are using the Typescript template. But you can simply leave the --typescript
off if you like to suffer. Your choice, really.
Choose whatever name you want. I'll presume you chose "website" though.
If you want to read more about the process of setting up Next.js, take a look at their getting started guide.
Install Prettier as a devDependency
ESLint will look at your code and try to prevent potential bugs by looking at its semantics. Prettier will look at the formatting and change it according to its rules. Since Next.js comes with ESLint pre-installed and pre-configured, that's already taken care of. That leaves Prettier.
Change into your newly created project folder:
cd website
Then, install Prettier as a devDependency:
npm install --save-dev --save-exact prettier
# or
yarn add --dev --exact prettier
Create an empty Prettier config:
echo {}> .prettierrc.json
This will let tools like your editor know you are using Prettier.
Optional: Create a .prettierignore file
If you plan to use Prettier outside of the Git hook we are setting up below, you should probably create a .prettierignore
file. This allows you to list folders and files you don't want to format.
touch .prettierignore
The Prettier documentation says it's a good idea to base this on your "gitignore and .eslintignore (if you have one)." So ... do that.
If you want to read more about the process of setting up Prettier, take a look at their installation guide.
Edit your .eslintrc
Some of the ESLint rules Next.js comes pre-configured with are about formatting. But we want Prettier to handle everything related to the formatting of our code. This is why we'll install eslint-config-prettier and add it to our .eslintrc
, where it will disable all existing rules that might interfere with Prettier.
Install eslint-config-prettier by running the following:
npm install --save-dev eslint-config-prettier
# or
yarn add --dev eslint-config-prettier
The .eslintrc
Next.js created should look like the following:
// In file .eslintrc
{
"extends": ["next", "next/core-web-vitals"]
}
Change this to the following:
// In file .eslintrc
{
"extends": ["next", "next/core-web-vitals", "prettier"]
}
If you want to read more about the process of combining ESLint and Prettier in a Next.js project, take a look at the Next.js "Usage with Prettier" guide, as well as Prettier's "Integrating with Linters" guide.
Install lint-staged
At this point, you would be able to run ESLint and Prettier manually. But ain't nobody got time for that. Also, "Manually Lint & Format your Code on Commit When Using Next.js" is not the title of this article and I don't want to disappoint you. So let's introduce lint-staged into the mix.
The good thing is that they make it very easy to set up:
npx mrm@2 lint-staged
This will install Husky, a tool that makes is easy to manage Git hooks, and detect which linting and formatting tools are already installed. It will then set everything up more or less correctly. We'll come to the "less" part next.
If you want to read more about the process of setting up lint-staged, take a look at their installation and setup guide, as well as Prettier's pre-commit hook guide.
Edit the Git Hook
After running the above, you should have the following entry in your package.json
:
// In file package.json
// ...
"lint-staged": {
"*.js": "eslint --cache --fix",
"*.{js,css,md}": "prettier --write"
}
Change this to the following:
// In file package.json
// ...
"lint-staged": {
"*.{js,jsx,ts,tsx,css,md}": "prettier --write"
}
This will run Prettier on all staged files of the listed types when you run git commit
.
Now, you would be forgiven to assume that to also run ESLint, we should put it in there as well. But since Next.js comes with its own pre-configured wrapper around ESLint, wich doesn't take the files it operates on as arguments, we will do something slightly different. We will edit the Git hook that Husky created, during the installation of lint-staged, directly. Right now, it should look like this:
# In file .husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
Change this to the following:
# In file .husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn lint:write && npx lint-staged
And then add the following script to your package.json
:
// In file package.json
// ...
"scripts": {
// ...
"lint:write": "next lint --cache --fix",
},
This will call the Next.js version of ESLint and tell it to automatically --fix
any issues that it finds that can be fixed automatically. Also, the --cache
tells it to only do so on changed files.
If you want to read more about the undocumented command line options Next.js' lint command accepts, take a look at my post on the topic.
We're Done!
Now, when you run git commit
, both ESLint and Prettier should check that you don't commit any crap. This should also work when using VSCode's own Git UI. Other Git UIs might have issues though. Sublime Merge for example can't find my node.js installation, most likely because it's installed and managed via nvm. There are almost certainly solutions to this, but since I haven't looked them up yet they fall outside the scope of this tutorial.
Don't forget that you can use or take a look at the accompanying repo.
Hope you found this helpful. If you find any erros or run into issues, feel free to tell me in the comments.
💡 This post was published 2021/07/14 and last updated 2021/07/14. Since node libraries change and break all the time, there's a non-trivial chance that all of this is obsolete and none of it works when you read this in your flying taxi, gulpin' on insect protein shakes sometime in the distant future or, let's be honest here, next week. If so, tell me in the comments and I'll see if an update would still be relevant.
Top comments (6)
thank you very much for this article I learned a lot and I am very thankful. Could commitlint be added to this setup?
Hey @samurai71! It almost certainly could, yes. I haven't had the time to look too much into this, but the commitlint call would probably go ...
we can install prettier vscode extension, and set format on save to true in vscode settings
As with most things in software development, there are multiple ways to achieve similar results, true. But I would say that in most cases, using the VSCode Prettier extension is something you should do in addition to, not instead of, what I described here.
For one thing, the method described runs
next lint
as well. Something you could do as a VSCode script for example, but that would still be more work than just installing one extension and in general, using VSCode scripts for these kind of things doesn't scale too well in my experience.Also, when setting up everything via npm scripts and hooks, this will run in the same way for everyone on your team. No need to commit recommended VSCode plugins, scripts and settings. No need even to use VSCode at all, everyone can use what they want. That way, even that one weirdo on your team who only ever uses emacs will be happy! 😉
I actually did not know setting up Prettier with npm would add more features like these. Back then I thought installing all those lint and prettier would be enough for everything. Thank you for the awesome post!
Glad you found the post useful. 🙂 The difference between using VSCode and npm is easy to overlook, especially when you're just getting started or learning on your own. But many of these things become obvious when you work on a team - especially when some members use different setups.
But I would also say that it's perfectly fine to use whatever works for you in your circumstances. If the plugins are enough right now and you prefer using them, by all means continue to do so. It's something that is easy to change once there's the need for it.