Eslint & Prettier
This page explains how to set up eslint and prettier for new projects.
This page is under construction.
We use Prettier (opens in a new tab) for code formatting, and ESLint (opens in a new tab) for code-quality. Read more about the difference here (opens in a new tab).
After tweaking the configuration for a while, we came up with a configuration that works well for us. We use eslint-config-auto (opens in a new tab) to automatically install (almost) all necessary eslint plugins based on the project's dependencies.
The eslint-config-auto
suggest you to install the latest versions of plugins. However, there is quite new Prettier v3
and we didn't test it yet with our setup. So, we suggest you to install the versions we worked with:
"prettier": "2.8.8"
"eslint-config-prettier": "8.10.0"
"eslint-plugin-prettier": "4.2.1"
---> only if forced to install, see sections below
"prettier-plugin-tailwindcss": "0.4.1"
---> only if using Tailwind
Installation and setup
Add the following packages to your devDependencies
:
yarn add -D prettier eslint eslint-config-auto
Create a .prettierrc.js
file in the folder where the app lives (e.g. root, next
or strapi
):
- ✅ We prefer
.js
over.json
format, because it supports comments and are easier to extend.
module.exports = {
trailingComma: 'all',
tabWidth: 2,
semi: false,
singleQuote: true,
printWidth: 100
}
Add the following scripts to your package.json
:
- 💡 List all directories you want to lint, e.g.
components
,pages
andutils
...
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint components pages utils",
"lint:fix": "yarn lint --fix",
"prettier": "prettier --write .",
"prettier:check": "prettier --check ."
}
}
Create a .eslintrc.js
file in the folder where the app lives (e.g. root, next
or strapi
):
- ✅ We prefer
.js
over.json
format, because it supports comments and are easier to extend.
module.exports = {
extends: ['auto']
}
and run
yarn lint
The eslint-config-auto
package will provide you with a list of packages to install, e.g.:
To install the missing packages, please run the following command:
npm install eslint-plugin-import@latest eslint-plugin-jsx-a11y@latest eslint-plugin-react@latest eslint-plugin-react-hooks@latest eslint-plugin-array-func@latest eslint-plugin-const-case@latest eslint-plugin-eslint-comments@latest eslint-plugin-html@latest eslint-plugin-json@latest eslint-plugin-markdown@latest eslint-plugin-no-constructor-bind@latest eslint-plugin-no-use-extend-native@latest eslint-plugin-optimize-regex@latest eslint-plugin-promise@latest eslint-plugin-simple-import-sort@latest eslint-plugin-sonarjs@latest eslint-plugin-switch-case@latest eslint-plugin-unicorn@latest eslint-plugin-no-secrets@latest eslint-plugin-no-unsanitized@latest eslint-plugin-pii@latest eslint-plugin-scanjs-rules@latest eslint-plugin-security@latest eslint-plugin-xss@latest @typescript-eslint/eslint-plugin eslint-config-airbnb@latest eslint-config-airbnb-typescript@latest @typescript-eslint/parser eslint-config-adjunct@latest --save-dev
Replace npm install --save-dev
with yarn add -D
and run the command to install all necessary plugins.
Repeat if prompted to install more plugins, such as eslint-config-prettier
.
When using VS Code and the app is in subdirectory, you need to add this extend .vscode/settings.json
, e.g. for next
app. Issue (opens in a new tab)
{
"eslint.workingDirectories": [
"./next"
]
}
Intergrating Prettier with linter
According to Prettier docs (opens in a new tab):
- ✅ install only
eslint-config-prettier
to disable all formatting-related eslint rules that might conflict with Prettier - ✅ set up your editor to run prettier on save - follow our Editor Setup guide
- ❌ do not install
eslint-plugin-prettier
to run Prettier as an eslint rule () - ❌ do not install
prettier-eslint
The eslint-config-auto
at the time of writing these docs forces us to install eslint-plugin-prettier
.
So it is installed, but if this is fixed in the future, it will be removed.
Additional setup for Frontend projects
The eslint-config-auto
is great, but it doesn't support Next.js and Tailwind out of the box.
Install the appropriate version of eslint-config-next
(it should be the same version as next
package):
yarn add -D eslint-config-next
and useful tailwind classnames order plugin:
# add version 0.4.x with -T flag to fix minor version, because 0.5.x requires prettier v3
yarn add -D -T prettier-plugin-tailwindcss@0.4.1
Add following lines to config file.
module.exports = {
trailingComma: 'all',
tabWidth: 2,
semi: false,
singleQuote: true,
printWidth: 100,
plugins: ['prettier-plugin-tailwindcss'],
tailwindFunctions: ['cx', 'classnames', 'clsx', 'cn', 'twMerge', 'tw' ]
}
(clsx (opens in a new tab), classnames (opens in a new tab), tailwind-merge (opens in a new tab), tw
from twrnc (opens in a new tab), cn
inspired by shadcn/ui (opens in a new tab) (step 7) ,
Additionally, we disable several rules, to fit our needs and code style. The full eslint config could look like this:
module.exports = {
extends: ['auto', 'plugin:@next/next/recommended'],
rules: {
/** Named export is easier to refactor automatically */
'import/prefer-default-export': 'off',
/** Too tedious to type every function return explicitly */
'@typescript-eslint/explicit-function-return-type': 'off',
/** We prefer arrow functions */
'react/function-component-definition': [2, { namedComponents: 'arrow-function' }],
/** It's annoying to refactor from one style to another */
'arrow-body-style': 'off',
/** These are exceptions that we use with "__" */
'no-underscore-dangle': [
2,
{ allow: ['__NEXT_DATA__', '__NEXT_LOADED_PAGES__', '__typename'] },
],
/** Links get confused for secrets */
'no-secrets/no-secrets': ['warn', { ignoreContent: '^http' }],
/** Too tedious */
'eslint-comments/disable-enable-pair': 'off',
/** We specify default props in props decomposition */
'react/require-default-props': 'off',
'lodash/prefer-noop': 'off',
/** Some libraries produce a lot of eslint errors with this rule */
'@typescript-eslint/no-unsafe-assignment': 'off',
'pii/no-phone-number': 'off',
'xss/no-mixed-html': 'off',
// TODO: Turned off because of some missing setup
'@typescript-eslint/no-floating-promises': 'off',
'@typescript-eslint/no-misused-promises': 'off',
// Solve warning "Promise-returning function provided to attribute where a void return was expected."
// '@typescript-eslint/no-misused-promises': [
// 2,
// {
// checksVoidReturn: {
// attributes: false,
// },
// },
// ],
},
ignorePatterns: [
'*.config.*',
'.eslintrc.js',
],
}
Expo projects
Within Expo (opens in a new tab) projects there is different eslint setup. The base is same as in .eslintrc.js
file above with these changes and additions.
module.exports = {
extends: ['auto'],
rules: {
'@typescript-eslint/no-use-before-define': ['error', { variables: false }],
/** We use this a lot with isDefined and hasAttributes */
'unicorn/no-array-callback-reference': 'off',
'@typescript-eslint/no-shadow': ['error', { allow: ['event', 'value', 'key', 'error'] }],
/** Links get confused for secrets */
/** Turned off completely because of several false positives */
'no-secrets/no-secrets': ['off', { ignoreContent: 'http' }],
/** Include Typography as allowed text component */
'react-native/no-raw-text': ['error', { skip: ['Typography', 'Button', 'FloatingButton'] }],
'eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],
'switch-case/newline-between-switch-case': 'off',
'@typescript-eslint/no-floating-promises': 'warn',
'@typescript-eslint/no-misused-promises': [
'warn',
{
checksVoidReturn: {
attributes: false,
},
},
],
/** if comparing values in cx function or creating translations, it"s overkill to create variables for that */
'sonarjs/no-duplicate-string': 'warn',
/** Solves error with imports from files with no extension */
'import/extensions': 'off',
/** Not relevant to force separation of styles, when we use nativewind */
'react-native/no-inline-styles': 'off',
'padding-line-between-statements': ['warn', { blankLine: 'always', prev: '*', next: 'return' }],
'const-case/uppercase': 'off',
},
}