To keep it short, Prettier is used for code formatting and ESLint is used for catching bugs!
ESLint is a tool that statically identifies and reports patterns found in JavaScript code, to make code more consistent and avoid bugs. ESlint can be configured based on the developer’s requirements.
A few examples are:
var
to declare variables.To check the various linting rules in ESLInt. Please check https://eslint.org/docs/latest/rules/
Prettier on the other hand is a code formatting tool, which helps developers to make their code clean and readable.
A few examples are:
'
over "
.To create a React project with TypeScript. Open a new terminal and run
npx create-react-app my-app --template typescript
npm install --save-dev eslint
npm install --save-dev prettier
These dependencies are required to make sure ESLint works well with various plugins like prettier
, react
and typescript-eslint
.
npm install --save-dev eslint-plugin-prettier
npm install --save-dev eslint-config-prettier
npm install --save-dev @typescript-eslint/eslint-plugin
npm install --save-dev eslint-plugin-react
npm install --save-dev eslint-config-airbnb-typescript
npm install --save-dev eslint-plugin-import
npm install --save-dev @typescript-eslint/parser
Add the ESLint configuration .eslintrc.{js,yml,json}
file to the root level of the project folder. Create .eslintrc.js
and copy and paste the below code snippet
module.exports = {
root: true, // Make sure eslint picks up the config at the root of the directory
settings: {
react: {
version: 'detect', // Automatically detect the react version
},
},
env: {
browser: true,
node: true,
es6: true,
},
extends: [
'plugin:react/recommended',
'airbnb-typescript',
'plugin:prettier/recommended', // Make this the last element so prettier config overrides other formatting rules
],
parser: '@typescript-eslint/parser',
parserOptions: {
project: ['./tsconfig.json'],
},
plugins: ['@typescript-eslint', 'react', 'import'],
rules: {
'prettier/prettier': ['error', {}, { usePrettierrc: true }], // Use our .prettierrc file as source
//eslint/react/rules
'react/jsx-props-no-spreading': 'off',
'react/require-default-props': 'off',
'react/jsx-pascal-case': 'error',
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'typeLike',
format: ['PascalCase'],
filter: { regex: '^(__String|[A-Za-z]+_[A-Za-z]+)$', match: false },
},
{
selector: 'interface',
format: ['PascalCase'],
custom: { regex: '^I[A-Z]', match: false },
filter: {
regex: '^I(Arguments|TextWriter|O([A-Z][a-z]+[A-Za-z]*)?)$',
match: false,
},
},
{
selector: 'variable',
format: ['camelCase', 'PascalCase', 'UPPER_CASE'],
leadingUnderscore: 'allow',
filter: {
regex: '^(_{1,2}filename|_{1,2}dirname|_+|[A-Za-z]+_[A-Za-z]+)$',
match: false,
},
},
{
selector: 'function',
format: ['camelCase', 'PascalCase'],
leadingUnderscore: 'allow',
filter: { regex: '^[A-Za-z]+_[A-Za-z]+$', match: false },
},
{
selector: 'parameter',
format: ['camelCase'],
leadingUnderscore: 'allow',
filter: { regex: '^(_+|[A-Za-z]+_[A-Z][a-z]+)$', match: false },
},
{
selector: 'method',
format: ['camelCase', 'PascalCase'],
leadingUnderscore: 'allow',
filter: { regex: '^[A-Za-z]+_[A-Za-z]+$', match: false },
},
{
selector: 'memberLike',
format: ['camelCase'],
leadingUnderscore: 'allow',
filter: { regex: '^[A-Za-z]+_[A-Za-z]+$', match: false },
},
{
selector: 'enumMember',
format: ['camelCase', 'PascalCase', 'UPPER_CASE'],
leadingUnderscore: 'allow',
filter: { regex: '^[A-Za-z]+_[A-Za-z]+$', match: false },
},
{ selector: 'property', format: null },
],
'@typescript-eslint/no-unused-vars': [
'off',
{ varsIgnorePattern: '^_', argsIgnorePattern: '^_' },
],
'@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
'no-duplicate-imports': 'off',
'@typescript-eslint/no-duplicate-imports': 'error',
'@typescript-eslint/no-inferrable-types': 'error',
'@typescript-eslint/no-misused-new': 'error',
'@typescript-eslint/no-this-alias': 'error',
'no-unused-expressions': 'off',
'@typescript-eslint/no-unused-expressions': ['error', { allowTernary: true }],
'@typescript-eslint/prefer-for-of': 'error',
'@typescript-eslint/prefer-function-type': 'error',
'@typescript-eslint/prefer-namespace-keyword': 'error',
'@typescript-eslint/explicit-function-return-type': 'error',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-var-requires': 'error',
'@typescript-eslint/prefer-nullish-coalescing': 'error',
'@typescript-eslint/unbound-method': 'off',
'@typescript-eslint/prefer-as-const': 'error',
// eslint
'constructor-super': 'error',
curly: ['error', 'multi-line'],
'dot-notation': 'error',
eqeqeq: 'error',
'new-parens': 'error',
'no-caller': 'error',
'no-duplicate-case': 'error',
'no-empty': 'error',
'no-eval': 'error',
'no-extra-bind': 'error',
'no-fallthrough': 'error',
'no-new-func': 'error',
'no-new-wrappers': 'error',
'no-return-await': 'error',
'no-sparse-arrays': 'error',
'no-template-curly-in-string': 'error',
'no-throw-literal': 'error',
'no-trailing-spaces': 'error',
'no-undef-init': 'error',
'no-unsafe-finally': 'error',
'no-unused-labels': 'error',
'no-var': 'error',
'object-shorthand': 'error',
'prefer-const': 'error',
'prefer-object-spread': 'error',
'space-in-parens': 'error',
'unicode-bom': ['error', 'never'],
'use-isnan': 'error',
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
},
};
Create .prettierrc
at the root level of the project folder and copy and paste the below code snippet.
{
"semi": true,
"tabWidth": 4,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "none",
"bracketSameLine": true,
"endOfLine": "auto"
}
Sometimes we don’t want the linting check to be performed on certain files for example they can be generated code like x
, build code or other configuration files.
In that case, Create a .eslintignore
file at the root level of the project folder and copy and paste the below code snippet.
node_modules
build
.github
.eslintrc.js
src/service-worker.ts
src/serviceWorkerRegistration.ts
src/setupTests.ts
src/reportWebVitals.ts
src/react-app-env.d.ts
Similar to ignoring the linting for generated code. We also want to ignore code formatting on those files as well.
In that case, Create a .prettierignore
file at the root level of the project folder and copy and paste the below code snippet.
node_modules
build
package.json
Once all the dependencies and configuration files have been added to the project. We can add scripts in package.json
to run the linter and code formatting using the terminal.
Copy and paste the below code snippet into the script
section of package.json
.
"lint": "eslint --fix .",
"lint-check": "eslint .",
"format": "prettier --write . --config ./.prettierrc",
"format-check": "prettier --check . --config ./.prettierrc"
Here lint
and format
will resolve fixable issues. On the other hand, link-check
and format-check
will only report the issues without fixing them. Below code snippet shows how to run the scripts.
npm run lint
npm run lint-check
npm run format
npm run format-check
We can integrate ESLint and Prettier with VS Code by installing the VS Code Extensions ESLint and Prettier - Code formatter.
COMMAND + SHIFT + P
on macOS or CTRL + SHIFT + P
on Windows.format
and then choose Format Document.We are going to create a Check
action which checks for linting and code formatting when the pull request is raised.
Create .github/workflows
folders in the root level of the project. Then create a Check.yml
to add the metadata to perform the GitHub Action.
name: Check
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v2
- name: Set NPM Registry for installing dependencies
run: npm config set registry https://registry.npmjs.com/
- name: Install dependencies
run: npm ci
- name: Generate build code
run: npm run build --if-present
- name: Run formatter
run: npm run format
- name: Run linter
run: npm run lint-check