DEV Community

Giovanni Sarciotto
Giovanni Sarciotto

Posted on • Edited on

Migrating and configuring Eslint with Angular 11

In this post we will walk through migrating and configuring an Angular 11 project to utilize ESLint and as a bonus add the Prettier formatter.

[21/01/2021 Update]: See the Prettier session.
[05/02/2021 Update]: Fixed Prettier parser error in HTML, see the Prettier configuration.
[27/02/2021 Update]: Updated ESLint config to work with eslint-config-prettier 8.x

Introduction

With Angular 11 release it was announced that the TSlint (deprecated in 2019) linter was to be replaced by ESLint and there was a 3rd-party solution to help with the migration as well as specific Angular linting rules for ESLint.

I will use a new project generated by the Angular CLI v11.0.2 as example, though it should be very straightforward to migrate an already existing project provided it doesn't use other tools that integrates with TSlint. The team at eslint-angular made a very good job of automating the process.

Migration

To do the migration we first need to install the convert-tslint-to-eslint schematic. Run the following in the root folder of your project(s):



ng add @angular-eslint/schematics


Enter fullscreen mode Exit fullscreen mode

Now you have to choose the project you want to migrate. Then run the schematic as follows, replacing the {{}} bit for your project name:



ng g @angular-eslint/schematics:convert-tslint-to-eslint {{YOUR_PROJECT_NAME_GOES_HERE}}


Enter fullscreen mode Exit fullscreen mode

What the schematics will do is look at the chosen project's tslint.json and try to match your TSlint rules with ESLint rules in a new file .eslintrc.json, adjust your Angular configurations to use ESLint instead of TSlint as well as replace tslint:disable comments to their ESLint equivalent.
Pay attention to your terminal output, any rules that it can't match or if it needed to install any additional dependencies will be shown there.

And that's it, the migration should be over. If you are feeling brave you can delete the tslint.json file and uninstall both tslint and codelyzer from your project or test to see if it works and delete them later!

Customizing ESLint

If you already had customized your TSlint rules, then the schematics should have taken care of converting them to ESLint equivalents. However if it couldn't do it or if you don't like the current rules, you can easily modify your configurations. First let's take a look at how ESLint configurations are structured.

ESLint configuration structure

ESLint allows for heavy customization. It allows for plugins, different parsers, overrides, extending from others configurations defined elsewhere and more. I will cover the basics to allow us to understand what we are doing and if you want to learn more feel free to look at the docs.

Let's take a look at the configuration that was generated from a new CLI project:



.eslintrc.json
{
  "root": true,
  "ignorePatterns": [
    "projects/**/*"
  ],
  "overrides": [
    {
      "files": [
        "*.ts"
      ],
      "parserOptions": {
        "project": [
          "tsconfig.json",
          "e2e/tsconfig.json"
        ],
        "createDefaultProgram": true
      },
      "extends": [
        "plugin:@angular-eslint/ng-cli-compat",
        "plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
        "plugin:@angular-eslint/template/process-inline-templates"
      ],
      "rules": {
        "@angular-eslint/component-selector": [
          "error",
          {
            "type": "element",
            "prefix": "app",
            "style": "kebab-case"
          }
        ],
        "@angular-eslint/directive-selector": [
          "error",
          {
            "type": "attribute",
            "prefix": "app",
            "style": "camelCase"
          }
        ]
      }
    },
    {
      "files": [
        "*.html"
      ],
      "extends": [
        "plugin:@angular-eslint/template/recommended"
      ],
      "rules": {}
    }
  ]
}


Enter fullscreen mode Exit fullscreen mode

Notice that most of the configuration is inside the overrides field. This is because in an Angular project we have Typescript and HTML files. So each file type that we want to lint will need different parsers and plugins. To avoid conflicts, ESLint provides us with the overrides field to allows us to separate the rules for different file types (notice the *.html and *.ts in the files array of each entry of the overrides array).

Another important field to look at is the extends field. It allows us to utilize configurations defined elsewhere inside this file. These other configuration files can be created by us or installed via npm or from the internet in general. A very popular configuration is the AirBnB's one.

In my configuration above, we see configurations that come with the @angular-eslint plugin: "plugin:@angular-eslint/ng-cli-compat" and "plugin:@angular-eslint/ng-cli-compat--formatting-add-on". These two configurations were created to make it easy for the @angular-eslint team to do the automatic matching of TSlint rules and ESLint ones. I find them weak, for example: it won't warn or show as error unused variables. If we only want to change a few rules, then we can just use the rules field. I want a more drastic change so I will utilize other configurations such as @angular-eslint/recommended, which @angular-eslint team recommends.

Changing the configurations

First I will remove both "plugin:@angular-eslint/ng-cli-compat" and "plugin:@angular-eslint/ng-cli-compat--formatting-add-on" from the "extends" field and add the "plugin:@angular-eslint/recommended". Make sure you are making the modifications in the Typescript entry of overrides.

For now, our configuration looks like this:



"extends": [
        "plugin:@angular-eslint/recommended",
        "plugin:@angular-eslint/template/process-inline-templates"
      ],


Enter fullscreen mode Exit fullscreen mode

The standard Typescript rules, parser and configurations for ESLint with Typescript comes from typescript-eslint. The migration schematics already installed it for us, since @angular-eslint uses it under the hood. I will then extends the following configurations: eslint:recommended, plugin:@typescript-eslint/recommended and plugin:@typescript-eslint/recommended-requiring-type-checking. You can see what these configs rules are in these links: eslint:recommended, typescript-eslint/recommended and typescript-eslint/recommended-requiring-type-checking, but a brief explanation is that eslint:recommended adds some basic rules such as no unused variables, typescript-eslint/recommended disables some conflicting rules from eslint:recommended for usage with Typescript and adds some general Typescript rules, at last typescript-eslint/recommended-requiring-type-checking adds some types rules. The configuration looks like this:



"extends": [
        "plugin:@angular-eslint/recommended",
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:@typescript-eslint/recommended-requiring-type-checking",
        "plugin:@angular-eslint/template/process-inline-templates"
      ],


Enter fullscreen mode Exit fullscreen mode

The order matters. If we had included typescript-recommended before eslint:recommended, then the conflicting rules would be enabled.

Test the configuration

Check to see if everything is working. For example, in your configuration above, the no unused variables is enabled, so open a Typescript file and create a new variable and check if the linting works.

linting test

In the image above, I'm using VSCode editor, you can install an extension on it so that it runs the linter inside the editor and show errors while you type.

If you would like to change specific rules, you can do so at the "rule" entry.

Bonus: Adding Prettier

[21/01/2021 Update]: There are problems with the inline-templates plugin and prettier, see this issue. If you use inline-templates, then I would recommend changing to external templates or don't do the prettier integration for now.

First of all, what is Prettier? It is an opinionated code formatter. And the best of all is that you can enable it to run when ESLint lints your code or in your CI pipeline! No more declined PRs because of bad formatting, just agree on a set of rules with your team and let it do the formatting for you.

Installing dependencies

We will need to add 3 dependencies (as dev dependencies) to our project: prettier, eslint-config-prettier and eslint-plugin-prettier.



npm install -D prettier eslint-config-prettier eslint-plugin-prettier


Enter fullscreen mode Exit fullscreen mode

They are needed for doing the formatting but also disabling some formatting rules of ESLint so that there are no conflicts between Prettier and ESLint.

Integrating Prettier and ESLint

[27/02/2021 Update]: In eslint-config-prettier version 8, there is no need to extend prettier/@typescript-eslint anymore. If you are in a version below 8, just add the entry before plugin:prettier/recommended.

Now on the .eslintrc.json file, we just need to add the plugins to our "extends" field:



"extends": [
        "plugin:@angular-eslint/recommended",
        "plugin:@angular-eslint/template/process-inline-templates",
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:@typescript-eslint/recommended-requiring-type-checking",
        "plugin:prettier/recommended"
      ],


Enter fullscreen mode Exit fullscreen mode

If you want to enable the formatting in your .html files, then you need to add these two new lines in the HTML entry of the "overrides" field.



"extends": [
        "plugin:@angular-eslint/template/recommended",
        "plugin:prettier/recommended"
      ],


Enter fullscreen mode Exit fullscreen mode

IMPORTANT: The prettier entries should be at the end of the "extends" array and in the order above. This is so that the prettier config disables ESLint rules that conflicts with its own rules.

Optional: Customizing Prettier

Although Prettier is opinionated and comes with defaults, you can do some customizations. For that we need to create a .prettierrc file (you can also create the file as .js or .json) in the root folder and put the configurations that we want. You can see the options here.

My current options are:



{
    "tabWidth": 4,
    "useTabs": true,
    "semi": true,
    "singleQuote": false,
    "quoteProps": "as-needed",
    "trailingComma": "none",
    "bracketSpacing": true,
    "arrowParens": "always",
    "overrides": [
        {
            "files": "*.component.html",
            "options": {
                "parser": "angular"
            }
        },
        {
            "files": "*.html",
            "options": {
                "parser": "html"
            }
        }
    ]
}


Enter fullscreen mode Exit fullscreen mode

[05/02/2021 Update]: For some reason, Prettier wasn't able to decide a parser for *.component.html files. To solve this the overrides section above was added to the .prettierrc to force it to use a parser. Thanks @singhshubham97 for pointing this out.

Final configuration



{
"root": true,
"ignorePatterns": [
"projects/*/"
],
"overrides": [
{
"files": [
".ts"
],
"parserOptions": {
"project": [
"tsconfig.json",
"e2e/tsconfig.json"
],
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates",
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:prettier/recommended"
],
"rules": {
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "app",
"style": "kebab-case"
}
],
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "app",
"style": "camelCase"
}
]
}
},
{
"files": [
".html"
],
"extends": [
"plugin:@angular-eslint/template/recommended",
"plugin:prettier/recommended"
],
"rules": {}
}
]
}
Enter fullscreen mode Exit fullscreen mode




Conclusion

In this article we saw how to migrate a TSlint Angular project to an ESLint one. We did just some basic customization, we could have added linting for .css or .scss files or specific linting for your .spec.ts files. I recommend you taking a look at the ESLint ecosystem and configuring it to your liking!

Oldest comments (51)

Collapse
 
jwuliger profile image
Jared

Thanks for this article. It was beneficial and needed.

Collapse
 
gsarciotto profile image
Giovanni Sarciotto

Thanks! Glad I could help :)

Collapse
 
fabio984 profile image
fabio984

Hi, after eslint setup should we delete the lint
@angular-eslint/schematics": "1.0.0",
from package.json? Otherwise when npm install it warns that TSLINT is deprecated.

Finding which package depends on it:

npm ls tslint
-- @angular-eslint/schematics@1.0.0
-- tslint-to-eslint-config@2.0.1
`-- tslint@6.1.3

tkx

Collapse
 
gsarciotto profile image
Giovanni Sarciotto

I don't think it would cause any problems to uninstall the schematics after the transition.

Collapse
 
fabio984 profile image
fabio984 • Edited

I don't know what I did wrong but I'm only getting ts warns (not eslint).
see (open in new tab) :
dev-to-uploads.s3.amazonaws.com/i/...

Collapse
 
gsarciotto profile image
Giovanni Sarciotto

Did you integrated VSCode to lint on save? (see this extension)

If you did, are you using the same rules as in the article?

Collapse
 
pmo1948 profile image
pmo1948

Hi,
Once everything has been configured, is there a way to run it, or add it to a github hook?
Before, I could run npm lint, where that would run ng lint and I could use that as needed. I tried running eslint from the terminal, but it did not give me any errors. (I know I have errors though, bc Webstorm is letting me know)

Collapse
 
pmo1948 profile image
pmo1948

solution - in angular.json, change "builder" : "@angular-devkit/build-angular:tslint" to "builder": "@angular-eslint/builder:lint"

Collapse
 
nelisbijl profile image
nelisbijl

Great article. However...

"plugin:@angular-eslint/template/process-inline-templates"
seems to extract an inline template and feed it to the html linter
The prettier extension for *.html ("plugin:prettier/recommended") produces errors regarding the code formatting. The indicated error position is wrong and you won't be able to resolve this anyhow inside your inline template.

Either use external templates or stop using the process-inline-templates extension. It does not seem to kill all linting as I still noticed a warning for a missing closing tag. What exactly you do loose, I don't know.

This issue seems related:
github.com/angular-eslint/angular-...

Collapse
 
gsarciotto profile image
Giovanni Sarciotto

Yeah, I don't use inline templates so I didn't notice anything related to that, I will link this issue in the article. Thanks for the head up

Collapse
 
singhshubham97 profile image
singhshubham97

I have two questions:
1)The Html plugins mentioned here (those prettier ones) are giving parse errors.
2)Do we have other plugins for using ESLINT for HTML templates in angular

Collapse
 
gsarciotto profile image
Giovanni Sarciotto

1) What does the error says?

2) There are pure HTML plugins for eslint, however I dont think they would play nice with the features of angular (template binding, etc)

Collapse
 
singhshubham97 profile image
singhshubham97 • Edited

The parse error in index.html
dev-to-uploads.s3.amazonaws.com/i/...

Thread Thread
 
gsarciotto profile image
Giovanni Sarciotto

Alright, I managed to solve the problem in my machine. It seems like prettier isn't able to decide which parser to use for some reason. Add the following in your .prettierrc:

"overrides": [
        {
            "files": "*.component.html",
            "options": {
                "parser": "angular"
            }
        },
        {
            "files": "*.html",
            "options": {
                "parser": "html"
            }
        }
    ]
Enter fullscreen mode Exit fullscreen mode

If this fixes your problem, please tell me so that I can update the article!

Thread Thread
 
singhshubham97 profile image
singhshubham97

Thanks Giovanni for the help!! Its working in my machine

Collapse
 
julienb37 profile image
Julien BONNET

Thanks for this, it was interesting. But but i don't understand a thing : what is the advantage using Prettier when every options are present in ESlint ??

Collapse
 
gsarciotto profile image
Giovanni Sarciotto

Yes, ESLint has a lot of styling options, however I prefer to use Prettier for 2 reasons:

  1. ESLint is a linter, therefore its main job is to analyze code to find errors, potential bugs and code structure (not style, i.e big functions/classes) not conforming to some standard. Prettier is a formatter, therefore its only job is to format the code. I prefer this logic separation. If you have extremely customized linting rules, it can be hard to find the styles rules if they are in the same logic unit (in the .eslintrc), you can workaround this by using a separate .eslintrc file just for your style rules but I don't like it.

  2. The main reason though is because Prettier is opinionated and have some pretty strong defaults, you don't actually need to configure Prettier if you don't want to and it will work just fine.

Collapse
 
julienb37 profile image
Julien BONNET

hmm ... i understand. Thank you

Collapse
 
gingi profile image
Shiran Pasternak

Is it possible to run this migration without ng? I have an existing Angular project without ng. Retrofitting an ng workspace seems like a science project.

Collapse
 
gsarciotto profile image
Giovanni Sarciotto

Automatically I dont think so because of the schematics. You can however do the migration full manual, see the repo

Collapse
 
bogac profile image
Bogac Guven • Edited

Thanks for putting this together.

Collapse
 
ryandmello1198 profile image
Ryan

Very beginner friendly explanation ! Got me started. Thanks.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.