DEV Community

Cover image for Setting up ESLint & Prettier With Webpack in VSCode 🧑‍💻
Camilo Rincon
Camilo Rincon

Posted on

Setting up ESLint & Prettier With Webpack in VSCode 🧑‍💻

In our third part of the series, we will be setting up the configuration for ESLint and Prettier within VSCode.

We will be setting up our ESLint and Prettier without going through either Webpack nor Babel. If you would still like to set up the project like it is in GitHub then follow the quick set-up guide. Visit the previous articles for a more in-depth explanation of what is happening behind the scenes here.

Versions Being Used:

  • React 18
  • Babel 7
  • Webpack 5
  • TypeScript 4
  • ESlint 8
  • Prettier 2

Quick Set-Up

In order to quickly initialize the project, run the following commands:

a. Create package.json file

npm init -y
Enter fullscreen mode Exit fullscreen mode

b. Install React, Babel, Webpack, TypeScript, and other needed packages

npm install --save-dev --save-exact react react-dom @babel/core @babel/preset-env @babel/preset-react babel-loader webpack webpack-cli webpack-dev-server html-webpack-plugin style-loader css-loader file-loader typescript @types/react @types/react-dom @babel/preset-typescript
Enter fullscreen mode Exit fullscreen mode

c. Create the Babel configuration file .babelrc and paste the following code:

{
  "presets": [
    "@babel/preset-env",
    [
      "@babel/preset-react",
      {
        "runtime": "automatic"
      }
    ],
    "@babel/preset-typescript"
  ]
}
Enter fullscreen mode Exit fullscreen mode

d. Create the TypeScript configuration file tsconfig.json and paste the following code:

{
  "compilerOptions": {
    // Emit Configuration
    "noEmit": true,

    // Type Checking Configuration
    "allowUnreachableCode": false,
    "allowUnusedLabels": false,
    "exactOptionalPropertyTypes": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitThis": true,
    "noPropertyAccessFromIndexSignature": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitOverride": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    // Strict Rules - v4.8
    "alwaysStrict": true,
    "strictBindCallApply": true,
    "strictFunctionTypes": true,
    "strictNullChecks": true,
    "strictPropertyInitialization": true,
    "useUnknownInCatchVariables": true,

    // Modules Configuration
    "baseUrl": "./",
    "module": "ES2022",
    "moduleResolution": "node",

    // Language and Environment Configuration
    "target": "ES2022",
    "jsx": "react-jsx",

    // JavaScript Support Configuration
    "allowJs": true,
    "checkJs": true,

    // Interop Constraints Configuration
    "esModuleInterop": true,
    "isolatedModules": true
  },
  "include": ["src/**/**/*"],
  "exclude": ["node_modules"]
}
Enter fullscreen mode Exit fullscreen mode

e. Create the webpack.config.js file and paste the following code:

const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");

module.exports = {
  entry: "./src/index.tsx",
  mode: "development",
  output: {
    filename: "bundle.[fullhash].js",
    path: path.resolve(__dirname, "dist"),
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html",
    }),
  ],
  resolve: {
    modules: [__dirname, "src", "node_modules"],
    extensions: ["*", ".js", ".jsx", ".tsx", ".ts"],
  },
  module: {
    rules: [
      {
        test: /\.(js|ts)x?$/,
        exclude: /node_modules/,
        use: ["babel-loader"]
      },
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: ["style-loader", "css-loader"]
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        exclude: /node_modules/,
        use: ["file-loader"]
      }, 
    ],
  },
};
Enter fullscreen mode Exit fullscreen mode

f. Create a folder called "src" with the following files:

  • App.tsx
const App = () => (
  <div>
    <h1>Hello, World!</h1>
  </div>
);

export default App;
Enter fullscreen mode Exit fullscreen mode
  • index.tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';

const rootElement = document.querySelector('#root');
if (!rootElement) throw new Error('Failed to find the root element');
const root = createRoot(rootElement);
root.render(
  <StrictMode>
    <App />
  </StrictMode>
);
Enter fullscreen mode Exit fullscreen mode
  • index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>React</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

f. Creating the tscheck, build, and start scripts
In the package.json file, add these lines to your scripts section:

"tscheck": "tsc",
"build": "webpack --config webpack.config.js --mode production",
"start": "webpack serve --open"
Enter fullscreen mode Exit fullscreen mode

Now that we have all of the above set-up, the quick set-up should be able to run. If you have any questions or would like to learn more on what is happening above, visit my previous article here.

Implementing ESLint and Prettier

Background Information:

As a developer, it is always good practice to ask ourselves, why do I need to do this? What use cases would I need to implement this? Is the implementation worth the work compared to the alternative? These are the questions that we are going to be answering.

1. ESLint vs. Prettier

First things first, "ESlint vs Prettier" should really always be said: ESLint and Prettier. This is because the jobs between these two tools are meant to accomplish different tasks. ESLint will lint our code while Prettier will simply format our code.

Linting: Is the way to enforce our code to adhere to certain coding practices. Some examples would include ensuring all console.logs() and un-used variables are deleted while more specific rules would be like not allowing the use of continue statements.

Formatting: We only care about how the code visually looks, does not involve catching errors or coding rules. An example would be ensuring that all lines of code are 100 in length and then auto-formatting the code to adhere to this rule.

Now that we have a clearer definition, ESLint will be used as a linter while Prettier will be taking care of our formatting.

2. Why ESLint and Prettier?

Why would we ever need tools like ESLint and Prettier? As an individual developer, these tools would be in the "nice to haves" categories and are not "100%" necessary. This is because individual developers working on a project can adhere to their own coding rules and styles.

Though what happens when we now have a team? Maybe multiple teams of developers all working together and each developer having their own coding rules and styling? This can quickly complicate our projects as each pull request (PRs) can have a lot more "un-needed" styling changes and code rules that will then be debated. This makes reviewing PRs a bit more overwhelming than needed and takes time away from really constructively critiquing the actual needed change. This is where ESLint and Prettier come into play.

ESLint will ensure each developer is adhering to certain coding requirements that a team agrees on. Prettier will then ensure that every file will have the same "look and feel" across the project. These two tools will make sure that the team(s) will have better unity and any PRs will have have minimal changes. All of this fulfills a need in having a consistent, front-end project.

If you have any additional benefits of using ESLint and Prettier leave a comment!💬

3. Implementation Choice

Before starting our set-up, there are three different ways that I know on how we can utilize ESLint; all depending on if we want either Babel, Webpack, or NPM to be linting our code. In this article, we are going to have our ESLint not depend on any other tool other than having NPM run our linting.

My personal reason in organizing the ESLint like this is to have a separation of concerns. I believe having the ability to have our tools (and code) decoupled creates less dependencies and thus, creates less hassle for whenever things eventually break from either updates, configuration changes, or changes to the code itself.

Since we are going to implementing ESLint like with NPM, we will have to add another line in our scripting process.

1. Installing ESLint and Prettier

In order to install ESLint, we need to include the following in our dev dependencies:

npm install --save-dev --save-exact eslint eslint-plugin-react eslint-plugin-react-hooks eslint-config-prettier prettier @typescript-eslint/parser @typescript-eslint/eslint-plugin
Enter fullscreen mode Exit fullscreen mode

2. Configuring ESLint

In order to configure ESLint, we need to create the .eslintrc.json file in the root directory our current project.

Background: Within this file, we can implement different plugins and extensions for ESLint. Some of the basic fields that are in the configuration files are as follows:

  • env
    • Environments your script is designed to run in.
  • extends
    • Allows ESLint to use a pre-existing ESLint configuration and will make overrides.
  • parser
    • Converts code to an Abstract Syntax Tree (AST).
  • parserOptions
    • Tells ESLint what version of JavaScript we are targeting.
  • plugins
    • Are additional rules that can be used in order configure your ESLint.
  • settings
    • Is shared settings that specify information that should be consistent across all of its rules.
  • rules
    • Where we can configure the different rules our plugins and ESLint has to offer.

Setting up .eslintrc.json: Here is my .eslintrc.json that I use, if you have any suggestions please drop a comment!

{
  "env": {
    "browser": true,
    "es2022": true,
    "node": true
  },
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended",
    "plugin:react-hooks/recommended",
    "prettier"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    },
    "ecmaVersion": "latest",
    "sourceType": "module"
  },
  "plugins": [
    "react",
    "@typescript-eslint"
  ],
  "settings": {
    "react": {
      "version": "999.999.999"
    }
  },
  "rules": {
    "react/jsx-uses-react": "off",
    "react/react-in-jsx-scope": "off"
  }
}
Enter fullscreen mode Exit fullscreen mode

Here are some explanations over a few configurations:

  • env
    • We are going to add support for the es6 global variables by setting es2022 to true.
  • extends
    • Here we utilize the recommended ESLint and plugin rules. We need to make sure to place Prettier last in order to override any rules that would cause conflict between Prettier and the other packages.
  • parser
    • We are selecting the @typescript-eslint/parser since our project has TypeScript.
  • parserOptions
    • Since we are utilizing React, we are wanting to turn on jsx. We are also going to add support for the latest ecma syntax by setting ecmaVersion to latest.
  • plugins
    • We are needing to modify some of the rules for these plugins which is why we included them here.
  • settings
    • We are wanting to setting the react version here in order to avoid the react warning of not having a version specified. We can place an exact version of react but for now we can leave it as the value shown.
  • rules
    • Since we are using the jsx transform, we can disable the specific rules listed.

Lastly, for setting up our .eslintrc.json we need to create a file similar to .gitignore called .eslintignore. This works very much the same with the main difference of telling ESLint which files we should not check. We will be adding several files for our current project:

node_modules
dist
package-lock.json
webpack.config.js
Enter fullscreen mode Exit fullscreen mode

We do this in order to help speed up the process of linting our project. Add or take away depending on your needs!

3. Configuring Prettier

Now we can create a .prettierrc.json. This is where we will put our code formatting rules that prettier will run and adjust to!

Here is my formatting rules, leave a comment as to what rules you guys like to use!

{
  "semi": true,
  "tabWidth": 2,
  "printWidth": 100,
  "singleQuote": true,
  "trailingComma": "none",
  "jsxBracketSameLine": true
}
Enter fullscreen mode Exit fullscreen mode

4. Configuring VSCode

With the VSCode IDE, we have the following settings options available for the user to configure:

  • User Settings
    • Settings that will apply globally to any instance of VSCode on your machine.
  • Workspace Settings
    • Settings that are set inside your project that will be applied every time your specific project is open

We will be creating a workspace settings in order to be able to share, and have a coherent environment across teams when sharing our project. The following is what I have in my settings.json:

{
  "editor.defaultFormatter": "rvest.vs-code-prettier-eslint",
  "editor.formatOnPaste": false, // required
  "editor.formatOnType": false, // required
  "editor.formatOnSave": true, // optional
  "editor.formatOnSaveMode": "file", // required to format on save
  "files.autoSave": "onFocusChange" // optional but recommended
}
Enter fullscreen mode Exit fullscreen mode

With these settings, we will now be able to to use prettier everytime we save.

5. Configuring package.json

Now in the package.json file, we need to add this line to your scripts section:

"lint": "eslint .",
"lint:fix": "eslint . --fix",
Enter fullscreen mode Exit fullscreen mode

This will lint all the code. And will also try to auto-fix any of the linting errors that are brought up.

View everything together in Github.

If you found this helpful or just enjoyed reading the article, consider grabbing me a cup of coffee.

Top comments (1)

Collapse
 
maame-codes profile image
Maame Afia Fordjour

This is useful.