Guide to ESLint & Prettier with Nuxt 3
Tags: nuxt, javascript, eslint, prettier
Published: 2024-01-29 15:51:26

## Introduction
In this article, you will learn:
1. How to set up a Nuxt project with ESLint and Prettier
2. How to configure ESLint and Prettier together
3. How ESLint plugins and configs work
4. The difference between `plugins` and `extends` in ESLint
5. How Prettier plugins work
6. Other important details

## Prerequisites
You should have basic knowledge of Prettier and ESLint. You'll also need **VS Code**, but if you don't have that, it's not a problem as long as you really know the basics about your particular IDE.

## Environment Preparation
If you're using a separate IDE from VSCode, you can skip this part. ESLint and Prettier follow the same script in every IDE. If you are a VSCode user, let's get started.

First of all install these **2 extensions:**
1. Prettier - Code formatter
![Prettier - Code formatter](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lu32pmnl2umxnz7y0e5o.png)
2. ESLint
![ESLint](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lx7lwe2vj4b1xr5ukuj6.png)

Now open VSCode settings using `CTRL + ,` hotkey in Windows or using the panel below:
![VSCode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbjn96nytvnfaxfpkr7g.png)

Open *settings.json*. You can find the button in the top right corner
![VSCode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xpmnzhy8v8nisq7iq7tr.png)

Then add or change the following parameters:
```js
{
  "prettier.configPath": ".prettierrc",
  "editor.formatOnPaste": false,
  "editor.formatOnType": false,
  "scss.lint.unknownAtRules": "ignore",
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "eslint.format.enable": true,
  "prettier.useEditorConfig": false
}
```
> **Useful Note.** If you want to see what each of these settings does, then go back to the convenient UI window with settings and enter the keys (from *settings.json*) into the search one by one, for example: 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4zn1dsgidban38n421c2.png)

## Project Initialization
Now go to the **terminal** and select the folder you like to create the project
![Terminal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jrdn841yr8i0fuf7ynis.png)

To initialize the nuxt project you must run the following command:
```console
npx nuxi@latest init my-project
```
> **Useful Note.** If you want to deploy the nuxt project exactly in the **current** folder, and not create a new one with the project, then run `npx nuxi@latest init ./` (as in my case)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqkjc52rvtnm2tf5453d.png)
As you can see, the project is deployed directly in the selected folder. As for me, in some cases this is a way more **convenient** than nuxt creating a new folder for the project

Now let's install the common dependencies:
```console
npm i -D prettier eslint
```

> **Useful Note.** The `-D` flag is used to add a package to devDependencies. You can read more [here](https://stackoverflow.com/questions/23177336/what-does-npm-d-flag-mean)

I think you already know how [Prettier](https://prettier.io/docs/en/) and [ESLint](https://eslint.org/docs/latest/use/getting-started) work without each other, but if not, be sure to check it out before we go any further.

## Integrate ESLint module to Nuxt
You can just follow [this guide](https://nuxt.com/modules/eslint#setup) and skip this section, but if you want, let's walk through it together.

In your nuxt application install
```console
npm add -D @nuxtjs/eslint-module
```

> **Useful Note.** `npm add` is exactly the same command as `npm i`, but it just looks nicer from a naming point of view. That is, it’s like an alias

In essence, this action simply adds a plugin to the nuxt application (in addition to ESLint, you can add any other from [here](https://nuxt.com/modules)). This setting is purely for nuxt so that it knows which modules you are using, so now you need to edit *nuxt.config.ts* and add just one line to it
```ts
modules: ["@nuxtjs/eslint-module"]
```

Now your *nuxt.config.ts* should look something like this
```ts
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: ["@nuxtjs/eslint-module"],
})
```

## Plugins and configs in ESLint
Remember one thing - plugins **do not configure** your ESLint in any way. You just sort of add a module to it, but don't connect it. This can be compared to regular projects. For example, you can add a large *jquery* folder to the project (I hope you haven’t had this experience), and connect only *jquery.min.js* to the project from the folder. And here the jquery folder is a plugin, and jquery.min.js is a config. That is, when you specify something in plugins in ESLint, you simply load some rules and you need to configure which ones work.

All plugin names begin with `eslint-plugin-`. Having any plugin installed, for example *eslint-plugin-react*, you can connect it with removed prefix, like here
```js
plugins: [
  "react", // the same as "eslint-plugin-react"
]
```

But you can use a longer way:
```js
plugins: [
  "eslint-plugin-react", // the same as "eslint-plugin-react"
]
```

I also would like to say about plugins starting with `@`. Let's introduce the child plugins `@foo/eslint-plugin` and `@foo/eslint-plugin-bar`. And you can connect these plugins in the following ways:
```js
"plugins": [
      "@foo/eslint-plugin-bar", // the same as "@foo/eslint-plugin-bar"
      "@foo/bar",        	// the same as "@foo/eslint-plugin-bar"
      "@foo/eslint-plugin",        // the same as "@foo/eslint-plugin"
      "@foo"        // the same as "@foo/eslint-plugin"
    ]
```

And here ESLint works quickly, but I wouldn’t say it’s good, because often confusion **arises** due to such moments. Therefore, carefully study the example above and make sure that everything is clear.

Well, I hope you have mastered the information above and now let's talk about `extends`. In `extends` we always specify the configuration of our plugins. You can specify the entire configuration yourself in a separate place and add just this one file to extends. But this practice is very inconvenient and generally makes no sense when there are already **ready-made configurations**. In general, with plugins you simply load a preset, and with configs you connect the necessary settings for this preset. Configs start with `eslint-config-` (similar to plugins), but configs can also be inside plugins, and to use them you must set the appropriate `plugin:` prefix. I understand that it has become more difficult now, so let’s immediately analyze everything we’ve covered using the example of our application.

In the beginning we just included ESLint in the nuxt project, but ESLint does not have any settings for nuxt at the moment and the most useful plugin for nuxt is *eslint-plugin-nuxt*. Let's install it:
```console
npm i -D eslint-plugin-nuxt
```

Now let's create a *.eslintrc.json* file in the project root

![Project Root](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uxhmegv7xyos5e7d2n87.png)

Let's add this plugin to our *.eslintrc.json*
```js
{
   "plugins": ["nuxt"] // the same as "eslint-plugin-nuxt"
}
```

Now let's add a new script to *package.json*:
```js
"lint": "eslint .",
```

Now it looks like this
![VSCode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j0vh6dgmnrad1svxf50j.png)

Let's try to run this script and we'll get the following error:
![Terminal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rom6anyqka5qdb891cwa.png)

ESLint requires us to include a config, so let's do that, but first let's have a look at the **open source** of this plugin and find the *recommended.js* file
![eslint-plugin-nuxt/recommended](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qz360w3u4tlvecem7pdr.png)

As you can see, here are the usual **ESLint** settings (as in any other config), and all because this is essentially a *.eslintrc.json* file, only encrypted in js format. and it extends *base.js*, let's look at that too
![eslint-plugin-nuxt/base](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cy8vyweecq2f8yynnbnu.png)

And here you can see the plugin connection
```js
plugins: [
    'nuxt' // the same as "eslint-plugin-nuxt"
],
```

That is, this config connects the main plugin *eslint-plugin-nuxt* and configures it by specifying various parameters (for example, connecting rules). You can literally copy this config and paste it into your *.eslintrc.json* and everything will work for you. Here's a minimalistic example of config, which just control single **rule** from the plugin
```js
{
    "plugins": [
        "nuxt"
    ],
    "rules": {
        "nuxt/rule-name": 2
    }
}
```

But again, it’s inconvenient to configure everything yourself and each plugin already has ready-made configs, like this *recommended.js*. So we can simply use them based on the plugin **documentation**. If you know OOP and programming, then you know the `extend` operation from there, and here it works similarly. Well, now let's write the config connection for the plugin
```js
{
  "extends": [
    "plugin:eslint-plugin-nuxt/recommended"
  ]
}
```

Remember what I said about the `plugin:` prefix? This is where it is used, since the config is loaded directly from the plugin. In this case, we may not add the plugin connection to plugins `"plugins": ["nuxt"]`. As mentioned above, also we can omit `eslint-plugin-` and we get
```js
{
  "extends": [
    "plugin:nuxt/recommended"
  ]
}
```

But this config is already deprecated, and we can connect **another** one that includes its own npm package. Let's install *@nuxt/eslint-config* and connect in *.prettierrc.json*
```console
npm add -D @nuxt/eslint-config 
```

And extend it in *.eslintrc.json*
```js
{
   "extends": [
     "@nuxt" // The same as @nuxt/eslint-config
   ]
}
```

Now let's write the following code in *app.vue*:
```html
<template>
  <div>
    <div class="hello"></div>
  </div>
</template>
```

And run the `npm run lint` command
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8k908s0xkwcj0niks0er.png)

As you can see ESLint works now! You can experiment with the name of the extended config
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c82tc27flpk2ys76rpcd.png)

Also let's look at the [repository](https://github.com/nuxt/eslint-config) of this config
![@nuxt/eslint-config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p765xkr2k730xr95pja0.png)

Here we are using the basic eslint-config, but as you can see there are other options, such as *eslint-config-legacy*, which works for older versions, etc. But if you try to connect it by simply writing something like this, **nothing** will work
```js
{
   "extends": [
     "@nuxtjs/eslint-config-legacy-typescript"
   ]
}
```

That's because this config only works for version 2 of nuxt, as you can verify through the code on github:
![@nuxt/eslint-config-legacy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0oyhril0nj17wwyw9pxg.png)

In general, keep in mind that each plugin has its own internal structure, and you need to delve into open source to connect everything correctly. As a result, you can notice that we installed only one plugin *eslint-plugin-nuxt*, and we can connect different configs to it (`plugin:prettier/recommended`, which comes in the box with the plugin and `@nuxt/eslint-config`, which is installed separately). So there are no restrictions here, you can customize any plugins individually and write your own configs. And if you, for example, connected a config and want to **override** some settings, then simply specify them in the root *.eslintrc.json*. But consider the order in which you extend your configs! The order of the configurations in the extends **array** matters. The configurations listed later will override conflicting rules from earlier configurations.
```js
module.exports = {
  extends: [
    'eslint:recommended', // Base configuration
    'plugin:react/recommended', // Extending a specific plugin configuration
    'airbnb', // Extending a third-party configuration
    'prettier', // Extending a configuration for code formatting
  ],
  rules: {
    // Your additional or overridden rules go here
  },
};
```

## Prettier & ESlint
There are 2 packages: *eslint-plugin-prettier* and *eslint-config-prettier*. They eliminate potential conflicts between ESLint and Prettier for your application and give ESLint the **ability** to follow the rules in Prettier. Always connect them together, otherwise conflicts will arise. They complement each other. Let's connect them
```console
npm add -D eslint-plugin-prettier eslint-config-prettier
```

And now we add the corresponding configs to `extends`
```js
{
  "extends": ["@nuxt", "plugin:prettier/recommended", "prettier"] // The same as "@nuxt/eslint-config", "plugin:eslint-plugin-prettier/recommended", "eslint-config-prettier"
}
```

In general, we are finished, but we still need to add the following parameters to *.eslintrc.json* for it to work correctly
```js
{
  "extends": ["@nuxt", "plugin:prettier/recommended", "prettier"], // The same as "@nuxt/eslint-config", "plugin:eslint-plugin-prettier/recommended", "eslint-config-prettier"
  "env": {
    "browser": true,
    "node": true,
 },
}
```
## Configure .prettierc
Now let's create just an **empty** *.prettierrc* file

![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ffy46n5a77zmtr6bxr10.png)

Open *app.vue*
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/swb1gsm0v9ijzzly8lv1.png)

In VSCode go to **command palette**:
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dqlclqcuddi072irwlvv.png)

Restart ESLint server. This procedure is needed simply to **update** ESLint in VS Code
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/038j84rhj914a86kne94.png)

And now if you remove the space, ESLint will start displaying an **error** related to prettier
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rha8szt0x3pzpvdf6y06.png)

Now go back to the command palette and select **format document**
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pgxrtp4m46729tz0g4r1.png)
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m1dziclw2ih1n3yndek5.png)

The document is formatted and there are no errors. Now let's try to add a parameter to the prettier config
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qct9w71x98a09tusd3ka.png)

Let's go back to *app.vue* and **restart** ESLint server
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vjuwo5bazi0xn83f6v0b.png)
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1tbt675zhp6aqkc1incm.png)

And we get ESLint errors
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2xqgv9f030p54njilx5d.png)

Also if you write `npm run lint` in the console, then errors will be displayed there too
![Terminal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hfjibzortaimp0ml6c0o.png)

Now let's **format** the document again:
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0gq91vsq35dei7blenfz.png)
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9lub9pyzceuusnkapssb.png)
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdrfscf06qrp2wep8t3u.png)

## Plugins in prettier
Only ESLint can be configured to adapt to prettier. The opposite is **not possible**. Keep in mind that prettier plugins are not related to ESLint in any way, and only ESLint can change depending on prettier. Plugins in prettier also start with `prettier-plugin-`, but the prefix cannot be omitted! Let's install the plugin - `npm add -D prettier-plugin-tailwindcss`. And connect it to prettierrc
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6yom9bd4mkmwbi2mutqk.png)

For this plugin to work we need to install tailwindcss in the project. Do it according to the [guide](https://tailwindcss.com/docs/guides/nuxtjs). I already have another application where all this is connected, so don’t be alarmed that the name of the project has changed. Let's try to write the classes in the following order and run them through the **linter**
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ft8kyrpikildsrmsdolx.png)

As you can see, an error has arisen that we need to change the **order** of the classes and let's take advantage of the linter's hint and use the `--fix` flag
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9at0p5pnhtpf7y95oobb.png)

And everything worked exactly the same as if we formatted using prettier, but it’s just more **convenient** to use in VSCode, and it will be more correct. But just know that you can format your files this way too. That is, here, using the *eslint-plugin-prettier* plugin and the *eslint-config-prettier* config, ESLint adapts to prettier and causes errors that come from it.

## About prettier/prettier
`prettier/prettier` is exactly the rule that is defined in ESLint through prettier. For example, if you specified `tabWidth: 5` in the *.prettierrc.json* file, then the ESLint configuration will throw a `prettier/prettier` error. And the most interesting thing is that it can also be **configured**, for example, replacing error with warn
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ayq7mu2oavcizo745t6.png)
![VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kfts71tnellrz3lxn9rv.png)

## Conclusion
Prettier and ESLint are very powerful tools that require at least a basic understanding to perform to their full potential. I also plan to write identical articles about these tools, since there is really very little information and even on native js it is difficult to intuitively deploy them. I hope this article helped you!