Add a linting and formatting workflow to your CI/CD pipeline using Eslint and Prettier

Front-end Developer

Linters and formatters offer developers a way to address misaligned brackets, inconsistent naming conventions, or buggy code being committed. Using these tools, developers can focus their efforts on building highly maintainable and scalable projects.
Eslint and Prettier are two powerful tools for linting and formatting. Eslint is a static code analysis tool that checks JavaScript code for irregular patterns and problems while enforcing coding conventions. Prettier is an opinionated multi-language code formatter that ensures consistent styling while improving overall code readability. Adding both tools to your project workflows eliminates inconsistent styles and coding issues.
In this tutorial, you will learn how to set up Eslint and Prettier in your project. You’ll then learn to automate code quality enforcement with CircleCI, ensuring consistent coding conventions and styling across your team.
Prerequisites
To successfully follow along with this tutorial, you will need:
Setting up the project and version control
To set up a complete linting and formatting workflow with Eslint and Prettier, your project must first be version-controlled with Git and pushed to a GitHub repository.
Note: This tutorial uses a weather app built with vanilla JavaScript as its example project. You can either follow along with this project or use another project. The steps in this tutorial can also work for frameworks and libraries.
To get started, clone the weather application from the GitHub repository:
git clone https://github.com/CIRCLECI-GWP/linting-and-formatting-workflow-circleci
cd Weather-application
git checkout starter-branch
Next, follow the steps outlined in the linked blog post to initialize Git and push your project to a GitHub repository.
Installing and configuring Eslint and Prettier
With your project version controlled with Git and pushed to a GitHub repository, it is time to install and configure Eslint and Prettier.
To get started, install Eslint by running the following command in your terminal:
npm init @eslint/config@latest
This will prompt you to select what you want to use Eslint for. Since our focus is to search for syntax issues and potential problems, select the To check syntax and find problems option.
The installation process will take a couple of minutes. Once completed, an eslint.config.mjs
file will be added to your project directory.
Open the eslint.config.mjs
file and replace its content with this:
import { defineConfig } from 'eslint/config'
import globals from 'globals'
export default defineConfig([
{
files: ['**/*.{js,mjs,cjs}'],
languageOptions: {
globals: globals.browser,
},
rules: {
eqeqeq: 'error',
'no-var': 'error',
'prefer-const': 'warn',
'no-global-assign': 'error',
'no-param-reassign': 'warn',
complexity: ['warn', { max: 16 }],
curly: 'error',
'no-debugger': 'error',
},
},
])
This configuration sets up basic linting rules to help maintain clean and consistent JavaScript code.
- The
eqeqeq
rule enforces the use of type safe equality operators(=== and !==)
rather than their regular counterparts(== and !=)
. - The
no-var
rule enforces the use ofconst
orlet
instead ofvar
. - The
prefer-const
rule enforces the use ofconst
declarations for variables that were never reassigned. - The
no-global-assign
rule disallows assigning a value to a global variable. - The
no-parameter-reassign
rule disallows the reassignment of function parameters. - The
complexity
rule enforces code complexity reduction by cutting the amount of cyclomatic complexity allowed in your code. - The
curly
rule enforces the use of curly braces around code blocks even when their use is optional. - The
no-debugger
rule strictly disallows the use of debuggers.
Note: This tutorial uses only basic rules. You can customize them if your project requires it.
With Eslint successfully configured, your next step is to install Prettier. In your terminal, run:
npm install --save-dev --save-exact prettier
Next, create a .prettierrc
file in your project directory. You can either do this manually or by running:
node --eval "fs.writeFileSync('.prettierrc','{}\n')"
Update your .prettierrc
file with this configuration:
{
"trailingComma": "es5",
"tabWidth": 4,
"semi": false,
"singleQuote": true,
"printWidth": 50,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf"
}
This code shows a Prettier configuration setup with basic rules:
- The
trailingComma
rule adds trailing commas where valid, such as in objects and arrays. - The
tabWidth
rule specifies the number of spaces per indentation level. - The
semi
rule disables semicolons at the end of statements - The
singleQuote
rule enforces the use of single quotes instead of double quotes for strings. - The
printWidth
rule sets the maximum line length before Prettier wraps the code. - The
bracketSpacing
rule adds spaces between brackets in object literals. - The
arrowParens
rule includes parentheses around a sole arrow function parameter. TheendOfLine
rule enforces the use of Line Feed (LF) for line breaks.
Next, create a .prettierignore
in your project directory to ignore files you do not want Prettier to format. You can either do this manually or by using the following command:
node --eval "fs.writeFileSync('.prettierignore','# Ignore artifacts:\nbuild\ncoverage\n')"
Update your .prettierignore
file, with the following paths to ignore:
# Ignore artifacts:
build
coverage
node_modules
package-lock.json
package.json
Finally, to make Eslint run alongside Prettier without conflicts, install the necessary packages by running the following command in your terminal:
npm install --save-dev eslint-plugin-prettier eslint-config-prettier
Upon successful installation, update your eslint.config.mjs
file with the following code:
import prettierPlugin from 'eslint-plugin-prettier'
plugins: {
prettier: prettierPlugin,
},
Running Eslint and Prettier locally
Having Eslint and Prettier installed and configured in your project, you can now run both tools to check and fix linting and formatting issues.
To do this, start by running Eslint locally using the following command:
npx eslint .
The above command will run checks on all files in your project and report any issues that go against the rules set in your eslint.config.mjs
file.
To fix all issues highlighted in your Eslint run, enter the following command in your terminal:
npx eslint . --fix
Once issues are successfully fixed, you will get no report in your terminal.
Next, check if your files are correctly formatted. You can do this using the following command:
npx prettier --check .
This will check your project files that have formatting issues.
To automatically fix all issues detected by Prettier, enter the following command in your terminal:
npx prettier --write .
There you have it! You have successfully run Eslint and Prettier to check for linting and formatting issues, and also successfully fixed detected issues.
You can take the entire process further by ensuring linting and formatting rules are strictly adhered to before your code is committed to a GitHub repository. A perfect tool for this purpose is Husky.
To setup Husky in your project, start by installing it using the following command:
npm install --save-dev husky
Next, initialize Husky for your project using the command:
npx husky init
This command will create a .husky
folder at the root of your project. Inside this folder, there will be a pre-commit
file.
To enable your project to adhere to your specified Eslint and Prettier rules before each commit, navigate to your pre-commit
file inside your .husky
folder and replace its contents with the following code:
npx eslint . --fix && npx prettier --write .
Finally, commit and push your project to GitHub. If linting and formatting errors are detected, Husky will ensure they are fixed before committing your code.
Note: In situations where Eslint and Prettier encounter errors they can’t fix, the commits will be blocked. To bypass these errors and allow successful commits, you can use the “git commit –no-verify” command.
Automating Eslint and Prettier in CircleCI
Automating linting and formatting process ensures that your code adheres to your linting and formatting rules every time you push changes to GitHub or create a pull request. You can achieve this by integrating a CI/CD pipeline, with CircleCI automating these tasks in your project.
To integrate CircleCI, start by creating a .circleci
folder at the root of your project. Within this folder, create a config.yml
file where you will write your configurations.
In your config.yml
file, add the following scripts:
versions: 2.1
jobs:
lint:
docker:
- image: cimg/node:18.20.0
steps:
- checkout
- run:
name: Install dependencies
command: npm ci
- run:
name: Run Eslint
command: npx eslint .
- run:
name: Check Prettier Formatting
command: npx prettier --check .
workflows:
version: 2
lint-workflow:
jobs:
- lint
The above configuration runs inside a Docker container using the cimg/node: 18.17
image to ensure a consistent Node.js environment. It then installs the necessary dependencies using npm ci
, and runs Eslint and Prettier checks with npx eslint .
and npx prettier —check .
, respectively.
The lint
job defined within the workflow section, automates the entire process and triggers a pipeline build whenever changes are pushed to GitHub.
Commit and push the changes to GitHub.
Next, go to CircleCI and log into your account.
Navigate to your project’s dashboard, search for your project repository, and click Set Up Project.
Enter the name of the branch that contains your .circleci
folder (this is your main branch), and click Set Up Project to trigger a pipeline build.
With everything properly configured, your pipeline should run successfully on CircleCI.
You can click on the lint
job to view pipeline details.
Ensuring code quality in pull request
Ensuring code quality and consistent formatting should not be the responsibility of individual developers alone, but rather a shared goal across entire software development teams. For this reason, repository administrators can enforce specific linting and formatting conditions that must be met before changes are merged into key branches, such as main.
One effective way to do this is by enabling GitHub branch protection rules. These rules will mandate CircleCI workflows like your lint job to pass before pull requests can be merged.
To begin enforcing code quality and formatting in pull requests, log into your GitHub account.
Next, navigate to your repository, select your project repository (which in this tutorial is weather-application), and click on the Settings tab.
Next, scroll to the code and automation section and click Branches.
This will open up Branch protection rules. Click on Add branch ruleset.
Next, you will be asked to enter a Ruleset name, choose any name of your choice. Also, set Enforcement status to active.
Scroll to the Target section, click on Add target > Include by pattern, followed by the name of your target branch (which in this case is your main branch). Then, click Add Inclusion pattern.
Once done, scroll down to the Branch rules section. Select Require status check to pass > Add checks. In Add checks, search for your CircleCI
lint job/workflow
and select it.
Finally, scroll down and click on the Create button to create your ruleset.
There you have it! You just succeeded in setting GitHub branch protection for your project.
Testing Github branch protection
Now that you have successfully setup Github branch protection on your project, you can test to see its effectiveness by creating a branch and deliberately violating linting and formatting rules to see what happens upon merging.
To do this, start by creating a new Github branch from your terminal:
git checkout -b test-lint-check
Next, introduce intentional changes that violate Prettier rules in your weather.css file:
body {
background: linear-gradient(rgba(10, 10, 10, 0.7), rgba(10, 10, 10, 0.7)),url(./image/malik-noman-GYKl2HLVTlQ-unsplash.jpg);
background-position: center;
background-size: cover;
background-repeat: no-repeat;
width: 100%;
height: 100%;
font-family:
-apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, Oxygen, Ubuntu,
Cantarell, 'Open Sans', 'Helvetica Neue',
sans-serif;
}
The line background: linear-gradient(rgba(10, 10, 10, 0.7), rgba(10, 10, 10, 0.7)),url(./image/malik-noman-GYKl2HLVTlQ-unsplash.jpg);
from our above code breaks the Prettier printWidth
rule by exceeding the default maximum line length before wrap.
Commit and push the changes to your test-link-check
branch by entering the following into your terminal:
git add .
git commit -m "Test: Lint check"
git push origin test-lint-check
Note: Pushing code that violates your Prettier formatting rules will trigger a CircleCI build where the lint job will fail. This behavior shows that CircleCI is actively checking code quality for all branches.
Next, head over to GitHub and open a Pull Request from your test-lint-check
branch into your main branch.
Since GitHub branch protection is active, merging your test-lint-check
branch into main will fail.
To successfully merge the branch with main, revert the changes that violated your linting and formatting rules.
Conclusion
In this tutorial, you learned how to set up and configure Eslint and Prettier, running both tools to check for linting and formatting errors. You also learned how to set up Husky to enforce code quality before commits are made. You finished by automating the entire process using CircleCI and ensuring code quality on Pull Requests.
Moving on, endeavor to integrate all you have learned on both new and existing projects. You can view the complete code for this tutorial on GitHub.