# Setup

Setup **ESLint**, **Pritter**, **Airbnb JS Style** in **Create React App** project with **VS Code** editor

- Plugins: Prettier, Html, React Hooks

## Prerequisites

Latest **node**, **VSCode**, **npm**, **yarn**

## Install VSCode plugins

- First of all install the Vscode plugins [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)

- **NOTICE:** If you've already installed `Prettier - Code formatter`, please `DISABLE` for this project, because we will set up `prettier` as dependencies afterward. Suppose that you've used Prettier - Code formatter plugin in VSCode and your collaborator is setting up Prettier format in VSCode differ as to yours, your project will always get conflict.

## Install dependencies

- Remove yarn.lock or package.lock

```bash
rm -rf yarn.lock
```

- Install all latest dependencies in devDependencies

```bash
yarn add eslint @babel/core @babel/eslint-parser @babel/preset-env eslint-config-airbnb eslint-config-prettier eslint-plugin-html eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-prettier eslint-plugin-react eslint-plugin-react-hooks prettier -D
```

## Set up ESLint and Prettier

- Create `.babelrc` file in root project directory

```bash
touch .babelrc
```

```json
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "shippedProposals": true
      }
    ],
    "@babel/preset-react"
  ]
}
```

- Create `.eslintrc` file in root project directory

```bash
touch .eslintrc
```

Enter below setup in `.eslintrc`

```json
// TODO: Update 2021/8/4
{
  "parser": "@babel/eslint-parser",
  "parserOptions": {
    "ecmaVersion": 12,
    "sourceType": "module"
  },
  "extends": [
    "airbnb",
    "prettier",
    "prettier/react"
  ],
  "env": {
    "browser": true,
    "node": true,
    "jest": true,
    "es2021": true
  },
  "rules": {
    "no-debugger": 0,
    "no-alert": 0,
    "no-await-in-loop": 0,
    "no-return-assign": [
      "error",
      "except-parens"
    ],
    "no-restricted-syntax": [
      2,
      "ForInStatement",
      "LabeledStatement",
      "WithStatement"
    ],
    "no-unused-vars": [
      "error",
      {
        "ignoreRestSiblings": true,
        "argsIgnorePattern": "res|next|^err"
      }
    ],
    "prefer-const": [
      "error",
      {
        "destructuring": "all"
      }
    ],
    "arrow-body-style": [
      2,
      "as-needed"
    ],
    "no-unused-expressions": [
      2,
      {
        "allowTaggedTemplates": true
      }
    ],
    "no-param-reassign": [
      2,
      {
        "props": false
      }
    ],
    "no-console": 0,
    "import/prefer-default-export": 0,
    "import": 0,
    "func-names": 0,
    "space-before-function-paren": 0,
    "comma-dangle": 0,
    "max-len": 0,
    "import/extensions": 0,
    "no-underscore-dangle": 0,
    "consistent-return": 0,
    "react/display-name": 1,
    "react/no-array-index-key": 0,
    "react/react-in-jsx-scope": 0,
    "react/prefer-stateless-function": 0,
    "react/forbid-prop-types": 0,
    "react/no-unescaped-entities": 0,
    "jsx-a11y/accessible-emoji": 0,
    "jsx-a11y/label-has-associated-control": 0,
    "jsx-a11y/control-has-associated-label": 0,
    "react/require-default-props": 0,
    "react/jsx-filename-extension": [
      1,
      {
        "extensions": [
          ".js",
          ".jsx"
        ]
      }
    ],
    "radix": 0,
    "no-shadow": [
      2,
      {
        "hoist": "all",
        "allow": [
          "resolve",
          "reject",
          "done",
          "next",
          "err",
          "error"
        ]
      }
    ],
    "quotes": [
      2,
      "single",
      {
        "avoidEscape": true,
        "allowTemplateLiterals": true
      }
    ],
    "indent": "off",
    "react/jsx-indent": "off",
    "react/jsx-indent-props": "off",
    "prettier/prettier": [
      "error",
      {
        "trailingComma": "es5",
        "singleQuote": true,
        "printWidth": 80
      }
    ],
    "jsx-a11y/href-no-hash": "off",
    "jsx-a11y/anchor-is-valid": [
      "warn",
      {
        "aspects": [
          "invalidHref"
        ]
      }
    ],
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn",
    "react/jsx-props-no-spreading": 0,
    "class-methods-use-this": 0
  },
  "plugins": [
    "html",
    "prettier",
    "react-hooks"
  ],
  "settings": {
    "import/resolver": {
      "node": {
        "moduleDirectory": [
          "node_modules",
          "src/"
        ]
      }
    }
  }
}
```

## Verify Set up

```bash
npx eslint .
```

Make sure that your eslint worked, if not, verify that you installed all latest dependecies.

## Enable formatOnSave in Vscode

Open Code > Preferences > Settings

Search keyword: `formatOnSave` and check that setting

Now, when you save your code, it will format as your prettier setup in `.eslintrc`


## Optional

- If you have `jsconfig.json` in your project, 

Install `eslint-plugin-import`

```bash
yarn add eslint-plugin-import -D
```

```json
// jsconfig.json
{
  "compilerOptions": {
    "baseUrl": "src"
  }
}
```

Add this line below `plugins` config into `.eslintrc`

```json
"settings": {
    "import/resolver": {
      "node": {
        "moduleDirectory": [
          "node_modules",
          "src/"
        ]
      }
    }
  }
```

## Authors

* [Long Nguyen](http://github.com/zcmgyu)

## License

This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details

## Reference

* [eslint-config-wesbos](https://github.com/wesbos/eslint-config-wesbos)
* [Setting up ESLint to work with new or proposed JavaScript features such as private class fields.
](https://dev.to/griffadev/setting-up-eslint-to-work-with-new-or-proposed-javascript-features-such-as-private-class-fields-5fm7)