Photo by Tim Goedhart on Unsplash
Configure ESLint, Prettier, Husky, lint-staged Properly for Next.js
How to Use ESLint, Prettier, Husky, and lint-staged with Next.js for Git Hooks
If you choosed TypeScript
and ESLint
during Next.js CLI, then this article is for you to setup Prettier, Husky, lint-staged properly to proceed ahead and great project structure. If you work with other developer or want to maintain the project in future, then this is a must-do for Next.js project
Packages Install
npm install -D eslint eslint-config-next eslint-config-prettier eslint-plugin-prettier prettier prettier-plugin-tailwindcss eslint-plugin-tailwindcss @typescript-eslint/eslint-plugin @typescript-eslint/parser husky lint-staged
eslint
: The pluggable linting utility for JavaScript and JSX. ESLint is an open source project that helps you find and fix problems with your JavaScript code.eslint-config-next
: This package provides an ESLint configuration optimized for Next.js projects, ensuring adherence to Next.js best practices and conventions.eslint-config-prettier
: Disables ESLint rules that conflict with Prettier formatting, allowing Prettier to handle all code style concerns without interference.eslint-plugin-prettier
: Integrates Prettier into ESLint as a rule, enabling code to be automatically formatted by Prettier whenever ESLint runs.prettier
: A code formatter that enforces a consistent style by parsing and reformatting code according to predefined rules, ensuring readability across different projects.prettier-plugin-tailwindcss
: A Prettier plugin that automatically organizes Tailwind CSS class names in a consistent order according to Tailwind's recommendation.eslint-plugin-tailwindcss
: A ESLint plugin that automatically organizes Tailwind CSS class names in a consistent order according to Tailwind's recommendation and many more.@typescript-eslint/eslint-plugin
: Provides a set of ESLint rules specific to TypeScript, helping to catch and enforce best practices in TypeScript codebases.@typescript-eslint/parser
: An ESLint parser that allows ESLint to parse TypeScript code, enabling linting for TypeScript files.husky
: A tool that enables Git hooks, allowing commands like linting, testing, or formatting to run automatically at key stages of Git workflows, such as before committing.lint-staged
: A tool that runs linters or formatters on only the staged files in Git, ensuring that only the modified files are processed before a commit.
ESLint Config File
ESLint version > 9.0 support eslint.config.js
, So eslint.config.mjs
:
import prettier from "eslint-plugin-prettier";
import tailwindcss from "eslint-plugin-tailwindcss";
import globals from "globals";
import tsParser from "@typescript-eslint/parser";
import path from "node:path";
import { fileURLToPath } from "node:url";
import js from "@eslint/js";
import { FlatCompat } from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
const eslintConfig = [
...compat.extends(
"next/core-web-vitals",
"next/typescript",
"eslint:recommended",
"plugin:@next/next/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"plugin:tailwindcss/recommended",
),
{
plugins: {
prettier,
tailwindcss,
},
languageOptions: {
globals: {
...globals.browser,
...globals.node,
},
parser: tsParser,
ecmaVersion: 12,
sourceType: "module",
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
rules: {
"@typescript-eslint/no-explicit-any": "off",
"react/react-in-jsx-scope": "off",
"prettier/prettier": [
"error",
{
endOfLine: "auto",
},
],
},
},
];
export default eslintConfig;
Previous: eslintrc.json
:
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"next/core-web-vitals",
"next/typescript",
"eslint:recommended",
"plugin:@next/next/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"plugin:tailwindcss/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"prettier"
],
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
],
"react/react-in-jsx-scope": "off"
}
}
Prettier Config File
Newer: prettier.config.mjs
:
// prettier.config.js, .prettierrc.js, prettier.config.mjs, or .prettierrc.mjs
/**
* @see https://prettier.io/docs/en/configuration.html
* @type {import("prettier").Config}
*/
const config = {
trailingComma: "es5",
tabWidth: 2,
semi: true,
singleQuote: false,
bracketSpacing: true,
arrowParens: "always",
jsxSingleQuote: false,
bracketSameLine: false,
endOfLine: "lf",
plugins: ["prettier-plugin-tailwindcss"],
printWidth: 80,
experimentalTernaries: false,
tailwindConfig: "tailwind.config.ts",
tailwindEntryPoint: "tailwind.config.ts",
quoteProps: "as-needed",
proseWrap: "always",
htmlWhitespaceSensitivity: "css",
embeddedLanguageFormatting: "auto",
useTabs: false,
requirePragma: false,
insertPragma: false,
vueIndentScriptAndStyle: false,
singleAttributePerLine: true,
};
export default config;
prettierrc.json
:
{
"printWidth": 80,
"useTabs": false,
"tabWidth": 2,
"trailingComma": "es5",
"semi": true,
"singleQuote": false,
"bracketSpacing": true,
"arrowParens": "always",
"jsxSingleQuote": false,
"bracketSameLine": false,
"endOfLine": "lf",
"plugins": ["prettier-plugin-tailwindcss"]
}
Husky Configurations
Husky
has been installed before during installations.
npx husky init
It creates a .husky/
folder where the Git hooks will reside and the .husky
folder contains a file named “pre-commit“.
This will also add a new script in your package.json
file:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"prepare": "husky",
},
If not added, then please manually add this:
"prepare": "husky",
Add Pre-Commit Hooks:
Add necessary commands to this .husky/pre-commit
file.
npx lint-staged
This will configure Husky.
Lint-staged Configurations
Next, configure lint-staged
in your package.json
same block as scripts
to specify that ESLint and Prettier should run only on staged files. Add the following configuration:
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix './src/**/*.{js,jsx,ts,tsx}'",
"prettier --write './src/**/*.{js,jsx,ts,tsx,css}'"
]
}
This configuration ensures that ESLint will fix any linting issues, and Prettier will format files before they are committed.
Update package.json
Scripts
Add these to your scripts list of package.json
:
"format": "prettier --check './src/**/*.{js,jsx,ts,tsx,css}'",
"format:fix": "prettier --write './src/**/*.{js,jsx,ts,tsx,css}'",
"lint:fix": "eslint --fix './src/**/*.{js,jsx,ts,tsx}'"
Now the script section of package.json
will look like:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"prepare": "husky",
"format": "prettier --check './src/**/*.{js,jsx,ts,tsx,css}'",
"format:fix": "prettier --write './src/**/*.{js,jsx,ts,tsx,css}'",
"lint:fix": "eslint --fix './src/**/*.{js,jsx,ts,tsx}'"
},
Conclusion
This article offers a detailed setup guide for integrating Prettier, Husky, and lint-staged into a Next.js project using TypeScript and ESLint. It provides step-by-step instructions on installing the required packages, configuring ESLint and Prettier, setting up Husky for Git hooks, and configuring lint-staged to maintain code quality before committing changes. Furthermore, it updates project scripts for formatting and linting, ensuring a consistent and maintainable codebase when collaborating with other developers.