Code standarization is crucial for maintaining consistency among individuals within a team, improving readability, and reducing errors. In this article, we will explore code standardization using ESLint, and Prettier for our Next.js project to achieve good code standardization.
To get started with ESLint in a Next.js project, we need to install ESLint, Prettier, and some additional plugins as devDependencies. Here is the list:
npm install eslint^8 prettier^3 ... --save-dev
Check this boilerplate config if u want to skip for manually write eslint and prettier config https://github.com/asepkh/documentation/tree/main
Here's our eslint configuration (will always be updated for any feedback and improvements) as .eslintrc.json
{
"extends": [
"next/core-web-vitals",
"prettier",
"plugin:jsx-a11y/recommended",
"plugin:prettier/recommended",
"plugin:tailwindcss/recommended",
"plugin:eslint-plugin-prettier/recommended"
],
"plugins": ["react", "prettier", "tailwindcss", "jsx-a11y"],
"ignorePatterns": [
"node_modules/",
".next/",
"!.prettierrc.js",
"!.eslintrc.js",
"**/*.config.js"
],
"rules": {
"import/order": [
"error",
{
"groups": [
"builtin",
"external",
"internal",
["parent", "sibling", "index"],
"object"
],
"pathGroups": [
{
"pattern": "@/**/*",
"group": "internal",
"position": "before"
}
],
"pathGroupsExcludedImportTypes": ["builtin"],
"alphabetize": {
"order": "asc"
},
"newlines-between": "always"
}
],
"react/function-component-definition": [
"warn",
{
"namedComponents": "arrow-function",
"unnamedComponents": "arrow-function"
}
],
"react/jsx-pascal-case": "error",
"camelcase": ["error", { "properties": "never" }],
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "off",
"prettier/prettier": ["error", {}, { "usePrettierrc": true }],
"@next/next/no-img-element": "off",
"tailwindcss/classnames-order": "off",
"tailwindcss/no-custom-classname": "off",
"tailwindcss/no-contradicting-classname": "error",
"react/no-unescaped-entities": "off",
"no-unused-vars": "error",
"@typescript-eslint/no-unused-vars": [ // typescript only, remove this line for javascript
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
],
"@typescript-eslint/no-explicit-any": "error" // typescript only, remove this line for javascript
},
"settings": {
"react": {
"version": "detect"
}
},
"root": true
}
The extends
property allows you to use predefined ESLint configurations. This helps in quickly setting up a base configuration that adheres to best practices.
"extends": [
"next/core-web-vitals",
"prettier",
"plugin:prettier/recommended",
"plugin:tailwindcss/recommended",
"plugin:eslint-plugin-prettier/recommended"
]
next/core-web-vitals
: Enforces best practices and performance improvements specific to Next.js.prettier
: Integrates Prettier to handle code formatting rules.plugin:prettier/recommended
: Applies recommended Prettier settings to ESLint.plugin:tailwindcss/recommended
: Applies recommended Tailwind CSS linting rules.plugin:eslint-plugin-prettier/recommended
: Treats Prettier rules as ESLint rules, ensuring consistent formatting.The plugins
property specifies additional ESLint plugins that add extra rules and capabilities.
"plugins": ["react", "prettier", "tailwindcss"]
react
: Adds React-specific linting rules.prettier
: Integrates Prettier's formatting rules into ESLint.tailwindcss
: Adds Tailwind CSS-specific linting rules.The ignorePatterns
property specifies files and directories to be ignored by ESLint.
"ignorePatterns": [
"node_modules/",
".next/",
"!.prettierrc.js",
"!.eslintrc.js",
"**/*.config.js"
]
node_modules/
: Ignores dependencies..next/
: Ignores Next.js build output.!.prettierrc.js
, !.eslintrc.js
: Ensures these configuration files are not ignored.**/*.config.js
: Ignores all configuration files with the .config.js
extension.The rules
property defines custom linting rules to enforce specific coding standards.
"rules": {
"import/order": [
"error",
{
"groups": [
"builtin",
"external",
"internal",
["parent", "sibling", "index"],
"object"
],
"pathGroups": [
{
"pattern": "@/**/*",
"group": "internal",
"position": "before"
}
],
"pathGroupsExcludedImportTypes": ["builtin"],
"alphabetize": {
"order": "asc"
},
"newlines-between": "always"
}
],
"react/function-component-definition": [
"warn",
{
"namedComponents": "arrow-function",
"unnamedComponents": "arrow-function"
}
],
"react/jsx-pascal-case": "error",
"camelcase": ["error", { "properties": "never" }],
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "off",
"prettier/prettier": ["error", {}, { "usePrettierrc": true }],
"@next/next/no-img-element": "off",
"tailwindcss/classnames-order": "off",
"tailwindcss/no-custom-classname": "warn",
"tailwindcss/no-contradicting-classname": "error",
"react/no-unescaped-entities": "off",
"no-unused-vars": "error",
"@typescript-eslint/no-unused-vars": [ // typescript only, remove this line for javascript
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
],
"@typescript-eslint/no-explicit-any": "error" // typescript only, remove this line for javascript
}
import/order
: Enforces a specific order for import statements to improve readability.
groups
: Specifies the order of import groups (builtin, external, internal, etc.).pathGroups
: Customizes the order for specific patterns, such as internal imports starting with @/
.alphabetize
: Alphabetizes imports within each group.newlines-between
: Enforces new lines between import groups.react/function-component-definition
: Warns if function components are not defined as arrow functions.
namedComponents
: Requires named components to be defined as arrow functions.unnamedComponents
: Requires unnamed components to be defined as arrow functions.react/jsx-pascal-case
: Enforces PascalCase for user-defined JSX components.
camelcase
: Enforces camelCase naming convention for variables and functions.
properties
: Specifies that properties are not required to follow camelCase.react-hooks/rules-of-hooks
: Enforces the rules of React Hooks.
react-hooks/exhaustive-deps
: This rule is turned off to allow more flexibility in managing dependencies in React Hooks.
prettier/prettier
: Enforces Prettier formatting rules.
usePrettierrc
: Ensures that Prettier uses the configuration specified in .prettierrc
.@next/next/no-img-element
: This rule is turned off to allow the use of the <img>
element instead of Next.js's <Image />
component.
tailwindcss/classnames-order
: This rule is turned off to prevent conflicts with Prettier's Tailwind CSS class name order.
tailwindcss/no-custom-classname
: Warns about the use of custom class names that are not part of Tailwind CSS.
tailwindcss/no-contradicting-classname
: Enforces that there are no contradicting class names in Tailwind CSS.
The settings
property provides additional configuration for specific plugins.
@typescript-eslint/no-unused-vars
(typescript only) : This rule detects and reports on variables that are declared but never used in your TypeScript code.
error
: This setting will throw an error if unused variables are detected.argsIgnorePattern
: This option specifies a pattern for function arguments that should be ignored by this rule. In this case, any argument starting with an underscore (`_`) will be ignored.varsIgnorePattern
: Similar to `argsIgnorePattern`, but for variables. Any variable starting with an underscore will be ignored.@typescript-eslint/no-explicit-any
(typescript only): The any
type in TypeScript essentially turns off type checking for the variable it's applied to, which can lead to type-related bugs. This rule encourages you to use more specific types, improving type safety in your code.
"settings": {
"react": {
"version": "detect"
}
}
react.version
: Automatically detects the React version to use.The root
property indicates that this is the root ESLint configuration file, preventing ESLint from looking for configurations in parent directories.
"root": true
import/order
This rule enforces a specific order and group for import statements to improve readability, as long as you've installed prettier and enable format on save, this rules you can ignore because its automatically corrected by prettier itself, if not you can manually run npm run prettier --write .
Incorrect Code:
import React, { useState } from 'react'; // external
import path from 'path'; // builtin
import customHook from '@/hooks/customHook'; // internal
import { myFunction } from '../utils'; // parent
import './styles.css'; // sibling
import { anotherFunction } from './helpers'; // sibling
import { myObject } from './'; // index
Correct Code:
import path from 'path'; // builtin
import React, { useState } from 'react'; // external
import customHook from '@/hooks/customHook'; // internal
import { myFunction } from '../utils'; // parent
import './styles.css'; // sibling
import { anotherFunction } from './helpers'; // sibling
import { myObject } from './'; // index
react/function-component-definition
This rule warns if function components are not defined as arrow functions.
Incorrect Code:
function MyComponent() {
return <div>Hello World</div>;
}
Correct Code:
const MyComponent = () => {
return <div>Hello World</div>;
};
react/jsx-pascal-case
This rule enforces PascalCase for user-defined JSX components.
Incorrect Code:
const myComponent = () => {
return <div>Hello World</div>;
};
Correct Code:
const MyComponent = () => {
return <div>Hello World</div>;
};
camelcase
This rule enforces camelCase naming convention for variables and functions.
Incorrect Code:
const my_variable = 10;
Correct Code:
const myVariable = 10;
tailwindcss/no-contradicting-classname
This rule enforces that there are no contradicting class names in Tailwind CSS.
Incorrect Code:
<div className="bg-blue-500 bg-red-500">Hello World</div>
Correct Code:
<div className="bg-blue-500">Hello World</div>
no-unused-vars
This rule enforces that there are no unused variables in the code.
Incorrect Code:
const unusedVariable = 42;
const MyComponent = () => {
return <div>Hello World</div>;
};
Correct Code:
const MyComponent = () => {
return <div>Hello World</div>;
};
@typescript-eslint/no-unused-vars
- (typescript only)
This rule detects and reports on variables that are declared but never used in your TypeScript code
error
: This setting will throw an error if unused variables are detected.argsIgnorePattern
: This option specifies a pattern for function arguments that should be ignored by this rule. In this case, any argument starting with an underscore (_
) will be ignored.varsIgnorePattern
: Similar to argsIgnorePattern
, but for variables. Any variable starting with an underscore will be ignored.This configuration is useful when you want to declare variables or function parameters that you don't intend to use, but want to keep for clarity or future use. By prefixing them with an underscore, you're telling ESLint to ignore them.
Incorrect Code:
function exampleFunction(unusedParam: string, usedParam: number) {
console.log(usedParam);
}
const unusedVariable = 5;
Correct Code:
function exampleFunction(_unusedParam: string, usedParam: number) {
console.log(usedParam);
}
const _unusedVariable = 5;
@typescript-eslint/no-explicit-any
This rule disallows the use of the any
type in TypeScript.
The any
type in TypeScript essentially turns off type checking for the variable it's applied to, which can lead to type-related bugs. This rule encourages you to use more specific types, improving type safety in your code.
Incorrect Code:
function example(param: any) {
console.log(param);
}
const value: any = "string";
Correct Code:
function example(param: unknown) {
console.log(param);
}
const value: string = "string";
Here's our prettier configuration (will always be updated for any feedback and improvements) as .prettierrc.json
{
"plugins": ["prettier-plugin-tailwindcss"],
"semi": true,
"singleQuote": false,
"trailingComma": "all",
"printWidth": 80,
"tabWidth": 2,
"endOfLine": "auto",
"proseWrap": "always"
}
"plugins": ["prettier-plugin-tailwindcss"]
This specifies additional plugins to be used by Prettier. In this case, prettier-plugin-tailwindcss
is included to automatically sort Tailwind CSS classes in your code.
<!-- Before -->
<div class="text-center bg-red-500 p-4"></div>
<!-- After (sorted by plugin) -->
<div class="bg-red-500 p-4 text-center"></div>
"semi": true
This setting enforces the use of semicolons at the end of statements.
// Before
const foo = 'bar'
// After
const foo = 'bar';
"singleQuote": false
This setting enforces the use of double quotes for strings instead of single quotes.
// Before
const foo = 'bar';
// After
const foo = "bar";
"trailingComma": "all"
This setting enforces the use of trailing commas wherever possible, such as in objects, arrays, and function parameters.
// Before
const obj = {
foo: 'bar',
baz: 'qux'
};
// After
const obj = {
foo: 'bar',
baz: 'qux',
};
"printWidth": 80
This setting specifies the maximum line length that Prettier will wrap on. Lines longer than 80 characters will be wrapped.
// Before
const longString = "This is a very long string that will be wrapped by Prettier because it exceeds the print width of 80 characters.";
// After
const longString =
"This is a very long string that will be wrapped by Prettier because it exceeds the print width of 80 characters.";
"tabWidth": 2
This setting specifies the number of spaces per indentation level.
// Before
function foo() {
console.log('bar');
}
// After
function foo() {
console.log('bar');
}
"endOfLine": "auto"
This setting maintains existing end-of-line characters (LF or CRLF) in the file. It helps to avoid issues with different operating systems.
"proseWrap": "always"
This setting ensures that markdown text is always wrapped according to the printWidth
setting.
.vscode/settings.json
here's example:{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": "always"
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"prettier.requireConfig": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
Disclaimer: This documentation was written with the assistance of AI.