Linting, Formatting, and CI/CD Integration in NestJS

In modern development workflows, maintaining clean, readable, and consistent code is essential for collaboration and long-term project sustainability. Linting and code formatting help ensure that your codebase follows consistent styles, reduces errors, and improves the overall quality of the code. Additionally, automating these processes through CI/CD (Continuous Integration/Continuous Deployment) ensures that quality checks are run on every commit, promoting efficient collaboration and reducing the chances of bugs being introduced.

In this module, we will focus on setting up linting, code formatting, and CI/CD integration in a NestJS project to streamline development and maintain code quality.


Table of Contents

  1. Introduction to Linting, Formatting, and CI/CD
  2. Setting Up Linting with ESLint
  3. Setting Up Prettier for Code Formatting
  4. Integrating Linting and Formatting into CI/CD
  5. Running Linting and Formatting in Pre-Commit Hooks
  6. Setting Up Continuous Integration (CI) with GitHub Actions
  7. Best Practices for Linting, Formatting, and CI/CD
  8. Conclusion

Introduction to Linting, Formatting, and CI/CD

Before diving into the specifics, let’s first understand the importance of linting, code formatting, and CI/CD integration:

  1. Linting: The process of checking the code for potential errors, coding style violations, or problematic patterns. Linting helps catch errors early in the development process and ensures that the code adheres to a consistent style.
  2. Code Formatting: Consistent formatting across the entire codebase helps make the code more readable and easier to maintain. It automatically enforces rules such as indentation, spacing, and line breaks.
  3. CI/CD Integration: Automating the testing, linting, and formatting checks in a CI/CD pipeline ensures that every change is validated before it is merged into the main branch. This helps maintain code quality and accelerates the development process by detecting issues early.

Setting Up Linting with ESLint

To enforce consistent code quality, we use ESLint in NestJS. ESLint is a static analysis tool for identifying problematic patterns in JavaScript and TypeScript code.

Step 1: Install ESLint and Related Plugins

First, you need to install the necessary ESLint packages for your NestJS project:

bashCopyEditnpm install --save-dev eslint @nestjs/eslint-plugin @typescript-eslint/eslint-plugin @typescript-eslint/parser

Step 2: Initialize ESLint Configuration

Create a .eslintrc.js file in the root of your project:

bashCopyEdittouch .eslintrc.js

Now, configure the ESLint settings. Below is an example configuration:

jsCopyEditmodule.exports = {
  root: true,
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: './tsconfig.json',
  },
  plugins: ['@nestjs', '@typescript-eslint'],
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:@nestjs/eslint-plugin',
  ],
  rules: {
    '@typescript-eslint/no-unused-vars': 'warn',
    'no-console': 'off',
    '@nestjs/no-missing-dependencies': 'warn',
  },
};

In this configuration:

  • We are using the TypeScript parser for TypeScript files.
  • We are extending some recommended ESLint rules, as well as NestJS-specific rules.
  • Custom rules like no-console and no-unused-vars can be tailored to fit the needs of your project.

Step 3: Add ESLint Script to package.json

In your package.json, add a script to run ESLint:

jsonCopyEdit"scripts": {
  "lint": "eslint 'src/**/*.ts' --fix"
}

You can now run the linting script with:

bashCopyEditnpm run lint

Setting Up Prettier for Code Formatting

While ESLint helps with code quality, Prettier focuses on formatting. Prettier automatically formats your code to make sure it follows a consistent style.

Step 1: Install Prettier

bashCopyEditnpm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier

Step 2: Create Prettier Configuration

Create a .prettierrc file to define formatting options. Here’s an example configuration:

jsonCopyEdit{
  "semi": true,
  "singleQuote": true,
  "trailingComma": "all",
  "printWidth": 80
}

Step 3: Integrate Prettier with ESLint

In the .eslintrc.js file, add Prettier as an extension:

jsCopyEditmodule.exports = {
  root: true,
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: './tsconfig.json',
  },
  plugins: ['@nestjs', '@typescript-eslint', 'prettier'],
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:@nestjs/eslint-plugin',
    'plugin:prettier/recommended',
  ],
  rules: {
    '@typescript-eslint/no-unused-vars': 'warn',
    'no-console': 'off',
    '@nestjs/no-missing-dependencies': 'warn',
    'prettier/prettier': 'error',
  },
};

Step 4: Add Prettier Script to package.json

Add the following script to your package.json:

jsonCopyEdit"scripts": {
  "format": "prettier --write 'src/**/*.{ts,js}'"
}

Now, you can format your code with:

bashCopyEditnpm run format

Integrating Linting and Formatting into CI/CD

Incorporating linting and code formatting checks into your CI/CD pipeline ensures that any code pushed to your repository adheres to the set rules.

Step 1: Setting Up GitHub Actions (CI)

Create a .github/workflows/ci.yml file in the root of your project. This file will define the GitHub Actions workflow for continuous integration.

Here’s an example configuration for linting, formatting, and testing:

yamlCopyEditname: CI Workflow

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '14'

      - name: Install dependencies
        run: npm install

      - name: Run linting
        run: npm run lint

      - name: Run Prettier formatting check
        run: npm run format -- --check

  test:
    runs-on: ubuntu-latest
    needs: lint
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '14'

      - name: Install dependencies
        run: npm install

      - name: Run tests
        run: npm run test

This configuration ensures that:

  • Linting is run on every push and pull request to the main branch.
  • Prettier is used to check formatting.
  • Tests are executed after linting passes.

Running Linting and Formatting in Pre-Commit Hooks

To ensure that linting and formatting checks are always run before commits, you can use Husky and lint-staged to run these checks in a pre-commit hook.

Step 1: Install Husky and lint-staged

bashCopyEditnpm install --save-dev husky lint-staged

Step 2: Set Up Husky

Enable Husky by running:

bashCopyEditnpx husky install

Then, add the following script to your package.json:

jsonCopyEdit"scripts": {
  "prepare": "husky install"
}

Step 3: Configure lint-staged

Add the following lint-staged configuration to your package.json:

jsonCopyEdit"lint-staged": {
  "*.ts": [
    "eslint --fix",
    "prettier --write"
  ]
}

Now, every time you commit, Husky will run the configured linting and formatting checks.


Best Practices for Linting, Formatting, and CI/CD

  • Enforce Linting and Formatting Locally and Remotely: Set up Husky pre-commit hooks and CI/CD pipelines to enforce linting and formatting both locally and on remote branches.
  • Automate Testing in CI: Integrate automated tests into your CI pipeline to run with every commit or pull request.
  • Use Strict Rules: Use stricter linting and formatting rules to catch issues early and maintain consistency across the codebase.
  • Keep the CI Configuration Simple: Focus on the essential tasks like linting, formatting, and testing in your CI pipeline to ensure fast feedback.

Conclusion

In this module, we have explored how to set up linting and code formatting in a NestJS project using ESLint and Prettier. We also integrated these tools into a CI/CD pipeline with GitHub Actions to automate quality checks on every commit or pull request. Finally, we explored how to run linting and formatting checks using Husky and lint-staged in pre-commit hooks to enforce code quality locally.

By automating these processes, you ensure that your project maintains high standards of code quality, improving collaboration and reducing errors in production.