Dev Diary 2020.03.27 – ESLint Config - davidhorm/wavelength GitHub Wiki
Motivation
As a person sheltering at home because of COVID-19, I want to be able to play Wavelength with my friends online.
As a developer, I want to have steps to start up a React project with my favorite toolchain.
Dev Diary - React + TypeScript + ESLint + Prettier
There are a specific list of tools I want to work with when I'm building a single-page application:
- Wiki - for a Dev Diary, so I can pick up back where I left off.
- React - Because one-way data flow is easier to maintain then two-way binding.
- TypeScript - Because it'll enforce what you think you're doing in JavaScript.
- ESLint - So all my projects use the same "grammar" and enforce best practices.
- Prettier - So all my projects are formatted the same.
- Storybook - For living tech spec documentation, and component gallery.
- Jest & React Testing Library - For unit testing.
I've seen list of steps on how to integrate all of these tools together, but sometimes they're out of date, or not really applicable when integrating one with another. So here's my list of steps, but with links to the original source for you to reference in case of any updates.
Followed the installation instructions for Create React App Adding Typescript
npx create-react-app wavelength --template typescript
cd wavelength
yarn add typescript @types/node @types/react @types/react-dom @types/jest
Hm. I might've seen a message about how @types/react
and @types/react-dom
might've already been installed by CRA TS template. Will look into that later.
Next create the wavelength.wiki
project within GitHub. Clone that project alongside the wavelength
folder, add it to the wavelength.code-workspace
file.
I've seen lists try to to configure ESLint manually, but I think using its --init
feature is easiest. ESLint Installation and Usage
yarn add eslint --dev
npx eslint --init
? How would you like to use ESLint? To check syntax, find problems, and enforce code style
? What type of modules does your project use? JavaScript modules (import/export)
? Which framework does your project use? React
? Does your project use TypeScript? Yes
? Where does your code run? Browser, Node
? How would you like to define a style for your project? Use a popular style guide
? Which style guide do you want to follow? Airbnb: https://github.com/airbnb/javascript
? What format do you want your config file to be in? JavaScript
? Would you like to install them now with npm? Yes
TODO: npm audit fix
at your own risk
This creates the .eslintrc.js
which is the main thing I care about. But here's the thing: eslint-config-airbnb
isn't for TypeScript. But here's the other thing: there's an Airbnb's ESLint config with TypeScript support, eslint-config-airbnb-typescript, but don't need the other eslint-plugin-*
packages listed in that site because they were already installed with the eslint --init
.
yarn add --dev eslint-config-airbnb-typescript
I want to be able to run yarn lint
, and have all the lint rules in .eslintrc.js
.
Update the scripts
property of package.json
file.
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
- "eject": "react-scripts eject"
+ "eject": "react-scripts eject",
+ "lint": "eslint --ext .js,.jsx,.ts,.tsx ./"
},
Update the extends
and parserOptions
properties of .eslintrc.js
file with details found in eslint-config-airbnb-typescript. Note: You can remove the original extends
items because of https://github.com/typescript-eslint/typescript-eslint/blob/master/docs/getting-started/linting/README.md#eslint-configs. Also because TypeScript *.d.ts
files have triple slash comments, lets make that exception in the rules
property, using the spaced-comment rule options. NOTE: final eslint config here
extends: [
- 'plugin:react/recommended',
- 'airbnb',
+ 'airbnb-typescript',
+ 'airbnb/hooks',
],
parserOptions: {
+ project: './tsconfig.json',
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 2018,
sourceType: 'module',
},
rules: {
+ 'spaced-comment': ['error', 'always', { 'markers': ['/'] }]
},
};
You can run yarn lint
and see a bunch of errors and warnings with the CRA default install. We'll ignore these for now.
Both ESLint, and Prettier have opinions on how the code should be formatted. Rules can conflict. But luckily, there's a way to easily disable the ESLint rules that conflict with the recommended Prettier rules. Prettier integrating with linters with recommended configuration
yarn add --dev prettier eslint-config-prettier eslint-plugin-prettier
And then per the eslint-config-prettier Installation, we can extend other prettier plugins to deactivate the other conflicting ESLint plugin rules. We have to make sure these rules always stay at the bottom of the extends
property.
"extends": [
...
+ 'plugin:prettier/recommended',
+ 'prettier/@typescript-eslint',
+ 'prettier/react',
]
Then create .prettierrc.js
for Prettier configuration file at the root, and using the non-default Prettier settings I like:
module.exports = {
printWidth: 120,
singleQuote: true,
quoteProps: 'consistent',
};
Now run yarn lint --fix
to clean up some of the linting errors. Now since Prettier has a way to turn off eslint-plugin-unicorn, lets add that.
yarn add --dev eslint-plugin-unicorn
Update the extends
and rules
(to make it more React friendly rules) properties of .eslintrc.js
file with the following:
extends: [
...
+ 'plugin:unicorn/recommended',
...
],
rules: {
...
+ 'unicorn/filename-case': 0, // React has their own way of naming things
+ 'unicorn/prevent-abbreviations': [ 'error', { 'whitelist': { 'env': true } } ], // Allow react-app-env.d.ts file name
},
Checkout https://github.com/dustinspecker/awesome-eslint and install/config rules of interest.
yarn add --dev eslint-plugin-eslint-plugin eslint-plugin-eslint-comments eslint-plugin-jsdoc eslint-plugin-jest eslint-plugin-sonarjs eslint-plugin-no-loops
Hm, when I try to disable the sonarjs/cognitive-complexity
then it complains that the rule doesn't exist when I yarn start
. But here's one answer. https://github.com/SonarSource/eslint-plugin-sonarjs/issues/122. I couldn't get it to work, so I'll just leave that rule alone for now.
Create .vscode/settings.json
file with the following content:
{
"editor.codeActionsOnSave": {
"source.organizeImports": true,
"source.fixAll": true,
}
}
Note: normally I'd want settings in the wavelength.code-workspace
file, but I can't get "source.fixAll": true
to work in there.
.eslintrc.js
Added comments to .eslintrc.js
file to keep track of what rules and why.
module.exports = {
env: {
browser: true, // allow browser global variables
es6: true,
node: true, // allow Node.js global variables and Node.js scoping
jest: true, // allow Jest global variables
},
extends: [
/**
* Airbnb's ESLint config with TypeScript support
* https://github.com/iamturns/eslint-config-airbnb-typescript#i-wish-this-config-would-support-
*
* Contains and turns on the following ESLint Configs:
*
* eslint-plugin-import - ESLint plugin with rules that help validate proper imports.
* https://github.com/benmosher/eslint-plugin-import#rules
*
* eslint-plugin-jsx-a11y - Static AST checker for a11y rules on JSX elements.
* https://github.com/evcohen/eslint-plugin-jsx-a11y#supported-rules
*
* eslint-plugin-react - Recommended React specific linting rules for ESLint
* https://github.com/yannickcr/eslint-plugin-react#recommended
*
* eslint-plugin-react-hooks - This ESLint plugin enforces the Rules of Hooks.
* https://reactjs.org/docs/hooks-rules.html
*/
'airbnb-typescript',
'airbnb/hooks',
/**
* Various awesome ESLint rules.
* https://github.com/sindresorhus/eslint-plugin-unicorn#rules
*/
'plugin:unicorn/recommended',
/**
* An ESLint plugin for linting ESLint plugins
* https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin#supported-rules
*/
'plugin:eslint-plugin/recommended',
/**
* Best practices when disabling ESLint rules
* https://mysticatea.github.io/eslint-plugin-eslint-comments/rules/
*/
'plugin:eslint-comments/recommended',
/**
* JSDoc linting rules for ESLint.
* https://github.com/gajus/eslint-plugin-jsdoc#configuration
*/
'plugin:jsdoc/recommended',
/**
* 'plugin:jest/recommended' plugin exports a recommended configuration that enforces good testing practices.
* 'plugin:jest/style' adds some stylistic rules, such as `prefer-to-be-null`, which enforces usage of `toBeNull` over `toBe(null)`.
* https://github.com/jest-community/eslint-plugin-jest#rules
*/
'plugin:jest/recommended',
'plugin:jest/style',
/**
* SonarJS rules for ESLint to detect bugs and suspicious patterns in your code.
* https://github.com/SonarSource/eslint-plugin-sonarjs#eslint-plugin-sonarjs----
*/
'plugin:sonarjs/recommended',
/**
* THESE PRETTIER RULES SHOULD ALWAYS BE LAST CONFIG IN EXTENDS ARRAY!
* Turns off all ESLint rules that are unnecessary or might conflict with Prettier.
* https://github.com/prettier/eslint-config-prettier
*/
'plugin:prettier/recommended',
'prettier/@typescript-eslint',
'prettier/react',
'prettier/unicorn',
],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
},
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 2018,
sourceType: 'module',
},
plugins: [
'@typescript-eslint',
'eslint-plugin',
'jest',
'jsdoc',
'jsx-a11y',
'no-loops',
'react',
'react-hooks',
'sonarjs',
],
rules: {
'spaced-comment': ['error', 'always', { 'markers': ['/'] }], // Allow triple slash comments used in *.d.ts files
'unicorn/filename-case': 0, // React has their own way of naming things
'unicorn/prevent-abbreviations': [ 'error', { 'whitelist': { 'env': true } } ], // Allow react-app-env.d.ts file name
"no-loops/no-loops": 2, // https://github.com/buildo/eslint-plugin-no-loops#why
"eslint-comments/disable-enable-pair": ["error", {"allowWholeFile": true}], // Allow disabling for the whole file
},
settings: {
jsdoc: {
mode: 'typescript' // Allows @template. https://github.com/gajus/eslint-plugin-jsdoc#mode
}
}
};