Photo by Dan Cristian Pădureț on Unsplash
Automate Prettier, ESLint, Husky and Lint-Staged with a NextJS and Typescript Project
Recently, I had an exciting opportunity to work on an open-source project where I had the task of setting up a Next.js project with all the necessary tools like Prettier, ESLint, Husky, and Lint-Staged. It was a valuable learning experience, and now I'm thrilled to share the step-by-step process with you in this article. If you're curious, you can also explore the project through my GitHub repository.
https://github.com/Prateema1/nextjs-starter-template-with-typescript
Let's dive in and discover how we can automate code formatting and linting in a Next.js and TypeScript project. The same method can also be applied to set up code formatting and linting in a React project with slight modifications.
Introduction
Working within a team can present its fair share of challenges, especially when it comes to maintaining a consistent codebase that appears as if it has been written by a single person. To achieve this, adhering to a unified code style and format becomes essential.
Maintaining code quality and adhering to consistent coding standards are essential aspects of any software development project. In this blog post, we will explore how to automate code formatting and linting processes using popular tools like Prettier, ESLint, Husky, and Lint-Staged with a Next.js and TypeScript project. By following the steps outlined in this guide, you'll be able to set up a robust development environment that enforces code quality automatically.
Why Use Prettier, ESLint, Husky, and Lint-Staged?
Prettier is a code formatter that helps maintain a consistent code style across your project. ESLint, on the other hand, is a powerful linter that identifies and reports on patterns or code that doesn't follow best practices. Husky allows you to add Git hooks to run scripts before committing or pushing code. Lint-Staged is a tool that enables running scripts on staged files before they are committed. By combining these tools, you can automate code formatting and linting, ensuring that your codebase remains clean and error-free.
Step 1: Setting Up a Next.js and TypeScript Project
To get started, create a new Next.js project with TypeScript by running the following command:
npx create-next-app --typescript new-app-name --use-npm
// --use-npm is to ensure project is generated using npm instead of yarn.
Step 2: Installing the Required Dependencies
Next, navigate to your project directory and install the necessary dependencies:
cd your-project-directory
npm install --save-dev prettier eslint eslint-config-prettier husky lint-staged
// --save-dev flag is to ensure that packages are installed as Dev dependencies
To ensure consistent code style and adherence to best practices, we will be implementing two essential tools for our project:
ESLint: This tool enforces coding standards and helps us follow best practices in our codebase. It identifies potential issues and provides recommendations to improve code quality.
Prettier: Prettier automatically formats our code files, ensuring a consistent and uniform style across the entire project. It takes care of formatting details such as indentation, line length, and quotes, saving us time and effort.
Husky: Husky enables us to set up Git hooks, which perform actions before committing or pushing code. This helps us enforce conditions and maintain code quality.
Lint-staged: Lint-staged works with Husky to optimize our workflow. It checks or formats staged files using linters and code formatters, ensuring clean and consistent code before committing.
By using ESLint and Prettier together, we can establish a standardized coding style and maintain a high level of code quality throughout the development process. Together, Husky and Lint-staged automate tasks, enforce quality, and enhance our coding practices.
Step 3: Configuring Prettier
Create a .prettierrc file (configuration file) in the root of your project and define your preferred code formatting rules. For example:
{
"semi": true,
"tabWidth": 2,
"printWidth": 140,
"singleQuote": true,
"trailingComma": "all",
"jsxBracketSameLine": true,
"endOfLine": "auto",
"useTabs": false
}
Also, create a .prettierignore file at the root of your project. You can include all the automatically generated build files that you don't want prettier to format.
.next
dist
node_modules
Now we can add a new script to package.json so we can run Prettier:
package.json
...
"scripts: {
...
"prettier": "prettier --write ."
}
You can now run:
npm run prettier
// Or yarn prettier (if you are using yarn)
It will automatically format, fix and save all files in your project you haven't ignored.
Step 4: Configuring ESLint
Create a .eslintrc.json file in the root of your project and define your ESLint configuration. You can also create .eslintrc.js or ts file depending upon your set-up. Here's an example configuration:
{
"extends": ["next", "next/core-web-vitals", "eslint:recommended"],
"rules": {
"no-unused-vars": 2,
"indent": ["error", 2]
// Add any additional rules or overrides here
}
}
You can test out your config by running:
npm run lint
Now that we have set up ESLint and Prettier, we've made significant progress in improving our code quality and consistency.
Let's set up the configuration for the file types to be checked and formatted before committing to using lint-staged.
Step 4: Set Up Lint-Staged
Please ensure that you have already installed lint-staged
as a development dependency. Next, open your package.json
file and add the following configuration for lint-staged
:
// package.json file
{
"name": "nextjs-starter-template-with-typescript",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"prettier": "prettier --write .",
"test": "jest"
},
"dependencies": {
"next": "13.3.4",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@commitlint/cli": "^17.6.3",
"@commitlint/config-conventional": "^17.6.3",
"@testing-library/dom": "^9.2.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/jest": "^29.5.1",
"@types/node": "18.16.3",
"@types/react": "18.2.0",
"@types/react-dom": "18.2.1",
"eslint": "8.39.0",
"eslint-config-next": "13.3.4",
"eslint-config-prettier": "^8.8.0",
"husky": "^8.0.3",
"jest": "^29.5.0",
"lint-staged": "^13.2.2",
"prettier": "^2.8.8",
"ts-jest": "^29.1.0",
"typescript": "^5.0.4"
},
"lint-staged": {
"*.{js,ts,tsx}": [
"eslint --fix",
"prettier --write"
]
}
}
In the provided package.json
file, we have a configuration for a Next.js starter template with TypeScript. Let's go through the different sections and their purposes briefly:
name
: Specifies the name of the project.version
: Indicates the version of the project.private
: Sets the project as private, meaning it won't be published to any public package registry.scripts
: Defines various commands to run during the development process. For example:dev
: Runs the Next.js development server.build
: Builds the Next.js project.start
: Starts the Next.js production server.lint
: Runs the ESLint linter for code analysis.prettier
: Runs Prettier to automatically format code.test
: Runs Jest for testing purposes.
dependencies
: Lists the dependencies required for the project, such as Next.js, React, and React DOM.devDependencies
: Lists the development dependencies required during the development process, including ESLint, Prettier, Husky, Jest, and TypeScript.lint-staged
: Configures the lint-staged tool to run ESLint and Prettier on the staged files before committing them.
Feel free to customize the linter files according to your project's requirements. You can modify the existing rules, add more rules, or include additional plugins as needed. Initially, using linter tools in a project can feel overwhelming, so I've kept the setup minimal to make it easier to get started.
Now, we can take it a step further by using Husky to create Git hooks.
These hooks will help us catch errors and automatically fix code formatting whenever we make a git commit. This ensures that we won't accidentally push bad code and helps to streamline our development process. Let's dive in and learn how to set up Husky and make the most of these useful hooks.
Step 5: Configuring Husky
First of all, let's understand the concept of Git hooks.
Git hooks are scripts that run at different stages of the Git process, such as when staging files, making commits, or pushing code. At each of these stages, we can set up scripts that need to run successfully for the process to proceed. If any of the conditions are not met, the process will fail.
In summary, Git hooks provide us with the ability to impose certain criteria on our codebase, allowing commits and push to proceed only if the code meets those criteria. This helps maintain a high standard of code quality and ensures that our project remains in a desirable state. One of the most popular enablers for setting up Git hooks is Husky.
As we have already installed Husky. We will proceed with further steps:
npm pkg set scripts.prepare="husky install"
npm run prepare
Running the above command will generate a .husky directory in your project. This directory is where your hooks will reside. It's important to include this directory in your code repository since it's meant for other developers to utilize, not just for your personal use. Also, it will automatically add the following script to your package.json file.
package.json
...
"scripts: {
...
"prepare": "husky install"
}
Add a hook:
npx husky add .husky/pre-commit "npx lint-staged"
git add .husky/pre-commit
Note: Set up the pre-commit git hook to run lint-staged. Additionally, the statement above indicates that for our commitment to be successful, the lines need to be executed and pass without any issues.
Make a commit:
git commit -m "Keep calm and commit"
// # `npx lint-staged` will run every time you commit
At the end of the project set-up, your package.json file will look like the following:
// package.json file
{
"name": "nextjs-starter-template-with-typescript",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"prettier": "prettier --write .",
"prepare": "husky install",
"pre-commit": "lint-staged",
"test": "jest"
},
"dependencies": {
"next": "13.3.4",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@commitlint/cli": "^17.6.3",
"@commitlint/config-conventional": "^17.6.3",
"@testing-library/dom": "^9.2.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/jest": "^29.5.1",
"@types/node": "18.16.3",
"@types/react": "18.2.0",
"@types/react-dom": "18.2.1",
"eslint": "8.39.0",
"eslint-config-next": "13.3.4",
"eslint-config-prettier": "^8.8.0",
"husky": "^8.0.3",
"jest": "^29.5.0",
"lint-staged": "^13.2.2",
"prettier": "^2.8.8",
"ts-jest": "^29.1.0",
"typescript": "^5.0.4"
},
"lint-staged": {
"*.{js,ts,tsx}": [
"eslint --fix",
"prettier --write"
]
}
}
Conclusion
By following the steps outlined in this guide, we have successfully set up ESLint, Prettier, Husky and Lint-staged in our Next.js and TypeScript projects. These tools allow us to enforce code quality, maintain consistent code formatting, and catch errors before committing or pushing code. We have configured ESLint with a Next.js and TypeScript-specific configuration, defined code formatting rules in a .prettierrc file, and set up Git hooks with Husky to automatically run linters and code formatters on staged files before each commit. This automation helps us ensure that our codebase adheres to the defined standards, promotes collaboration within the team, and improves overall code quality. With these tools in place, we can confidently develop and maintain a clean and organized codebase, making our development process more efficient and productive.
Thanks for Reading! 🙌
See you in the next blog! Until then, keep learning and sharing.
Let’s connect: