Here we are at the last article in the series of “Things to do before starting an Angular project”.
We have seen how to get the most out of Angular configuration and how to equip yourself before tackling a project with Angular tools. In this last part, we will talk about how to migrate from TSLint to ESLint, how to configure ESLint and Prettier on an Angular project and how to automate, through Husky, the pre-commit and pre-push linting and formatting process.
What are we waiting for? LET'S COD — er, LET'S CONFIGURE!
Migrate from TSLint to ESLint
With the release of Angular 11, it was announced that TSlint (deprecated in 2019) has been replaced by ESLint and there is a third-party solution that allows you to easily migrate from TSLint to ESLint through the use of schematics.
Before running the migration process, you need to install convert-tslint-to-eslint schematics. To do this, just run the following command within the root of the Angular project you want to migrate:
ng add @angular-eslint/schematics
Then you need to launch the migration process using the command:
ng g @angular-eslint/schematics:convert-tslint-to-eslint your_project_name
The above command will parse the tslint.json file and try to match the TSLint rules with the ESLint rules by creating a new .eslintrc.json file. The command will also take care of deleting the tslint.json file and removing the dependencies of tslint and codelyzer. Once the migration process is complete your application will be ready to use ESLint.
Configure ESLint and Prettier
The real power of ESLint lies in its customization possibilities.
Through the .eslintrc.json file it is possible to use “shared” configurations or set up custom linting rules. The rules, once set, will allow us to display warnings if the code does not respect the rules set.
Before taking a look at the configuration file that I recommend in this article, let's finish with the installation of Prettier, which will take care of formatting the code based on the rules set within the .prettierrc.json file.
npm install prettier eslint-plugin-prettier eslint-config-prettier --save-dev
This command, in addition to installing Prettier, also takes care of the installation of two packages that disable some ESLint rules to avoid conflicts with Prettier. Once the installation is finished, we are ready to configure the linting and formatting rules. Create the .prettierrc.json file inside the project root with the following configuration:
{
"singleQuote": true,
"trailingComma": "none",
"endOfLine": "auto"
}
If you wish to configure Prettier differently, please refer to the list of available options.
Once the Prettier configuration is finished, let's now configure ESLint by creating the .eslintrc.json file within the project root with the following configuration:
{
"root": true,
"ignorePatterns": [
"projects/**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"tsconfig.json",
"e2e/tsconfig.json"
],
"createDefaultProgram": true
},
"extends": [
"eslint:recommended",
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates",
"plugin:prettier/recommended"
],
"rules": {
"@angular-eslint/component-selector": [
"error",
{
"prefix": "app",
"style": "kebab-case",
"type": "element"
}
],
"@angular-eslint/directive-selector": [
"error",
{
"prefix": "app",
"style": "camelCase",
"type": "attribute"
}
],
"sort-imports": [
"error",
{
"ignoreCase": false,
"ignoreDeclarationSort": false,
"ignoreMemberSort": false,
"memberSyntaxSortOrder": ["none", "all", "multiple", "single"],
"allowSeparatedGroups": false
}
]
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {}
}
]
}
The parts I would like to pay attention to are: extends and rules.
The first declares the “shared” rules thanks to the installation of third-party packages, while the latter shows the custom rules.
The only rule I felt compelled to add to the list is sort-imports, which causes a compile-time error if the imported ES6 modules are not sorted correctly. Note that the order in which the plugins and rules are declared is important. Here is a complete list of ESLint configuration rules.
Finally, if you want to ignore the linting of some files, create the .eslintignore file inside the project root:
*package.json
package-lock.json
dist
e2e/**
karma.conf.js
commitlint.config.js*
Before concluding, let's add in the package.json the scripts to execute the linting and formatting of the code from the command line:
...
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "npx eslint 'src/**/*.{js,jsx,ts,tsx,html,css,scss}' --quiet --fix",
"format": "npx prettier 'src/**/*.{js,jsx,ts,tsx,html,css,scss}' --write",
"e2e": "ng e2e"
}
...
Et voila! We are done with the installation and configuration of ESLint and Prettier.
Configure Husky
Here we are at the last part of the article: how can we automate the linting and formatting process before sending the changes to the remote repository?
Simply using Husky, which, through Git hooks, allows you to execute commands in the pre-commit phase.
To configure the automatic pre-commit linting and formatting process, you must first install lint-staged:
npx mrm@2 lint-staged
Once the command is executed, the .husky folder will be created inside the project root. Opening this folder you will find the .pre-commit file. Open the file and edit it like this:
*#!/bin/sh*
. "$(dirname "$0")/_/husky.sh"
​
npx lint-staged -c .lintstagedrc.js
In this way, we are going to specify the configuration file to lint-staged to automate the linting and formatting process. At this point all that remains is to create the .lintstagedrc.js file within the project root:
const { ESLint } = **require**('eslint')
​
const **removeIgnoredFiles** = async (files) => {
const eslint = new ESLint()
const isIgnored = await Promise.**all**(
files.**map**((file) => {
return eslint.**isPathIgnored**(file)
})
)
const filteredFiles = files.**filter**((_, i) => !isIgnored[i])
return filteredFiles.**join**(' ')
}
​
module.exports = {
'src/**/*.{js,jsx,ts,tsx,html,css,scss}': async (files) => {
const filesToLint = await **removeIgnoredFiles**(files)
return [`npx prettier --write ${filesToLint}`, `npx eslint ${filesToLint}`]
},
}
This file is needed to instruct lint-staged to ignore the files specified within .eslintignore. Finally, we have concluded with the configurations and we can test that everything is working correctly. Opening the terminal and running commands
npm run format && npm run lint
You will have the possibility to run the formatting and linting scripts.
In addition, if you have that nasty colleague who forgets to run these commands before each commit, you have the allies Husky and Lint Staged who will promptly verify that the files are formatted and linted correctly, blocking the attempt to commit if they are not.
Conclusion
Here we are at the last part of the series “Things to do before starting an Angular project”. We have seen and learned together what are the tools and practices that I adopt before starting any Angular project.
In the next article, I will talk about a topic that in the last few weeks has allowed me to learn a lot about this framework and beyond. We will talk about Domain-driven Design and Front-end and how it is possible to use some aspects of the DDD approach also in this area.
Follow Devmy — Software Factory & Learning on Medium, Twitter, Facebook, and YouTube to contact us or keep you updated on the world of Frontend, Mobile, and DevOps development.