arrow_back All posts
Enforcing coding standards on the front-end

Enforcing coding standards on the front-end

Following coding guidelines might be hard, especially on larger projects. Let's figure out a setup that enforces code quality standards using Husky, Pre-commit, and Lint-staged.

Introduction

In this blog post, we'll explore a typical code quality setup, compare single projects and monorepos, and provide a step-by-step guide to setting up husky, pre-commit, and lint-staged. We'll also highlight the benefits of using a build system like Nx to manage code quality task execution across multiple projects.

Why enforce quality standards?

Maintaining code quality is an important task for any team working on the front-end. Whether it's a small application or a huge project, many developers prefer to have defined coding standards and automated processes to help keep things in order.

A good code quality setup helps achieve a couple of things:

  1. Consistency — enforcing styling and coding standards makes the codebase more maintainable and readable.
  2. Reliability — tests, linters, and type checkers catch errors before code is committed, reducing the chances of issues creeping into production.
  3. Developer Experience — automated formatting and linting removes the manual overhead from developers, allowing them to focus on more important things.

Code quality setup

A visualization of the most common code quality checks for a typical projectA visualization of the most common code quality checks for a typical project

Even though the setup depends on the team and project specifics, a typical setup often includes the following parts:

  • Type checking — static type checking, catching type-related errors during development. Comes out of the box with a language like typescript.
  • Linters — catching syntax errors and enforcing coding standards. Usually handled by eslint and stylelint.
  • Tests — ensuring code behaves as expected. jest is a popular testing framework for most kind of projects.
  • Code formatters — ensuring code is consistently styled. prettier is an opinionated code formatter that is considered the default when it comes to front-end development.

In smaller projects, ensuring code quality is relatively straightforward - all tools and configurations are contained within a single project. The setup is different though for monorepos, which house multiple projects or packages in a single repository. Each package usually has its own dependencies and configurations, so ensuring code quality across the entire monorepo requires additional efforts and a custom setup:

A visualization of a monorepo setup with multiple applications and separate code quality checksA visualization of a monorepo setup with multiple applications and separate code quality checks

What tools to use?

husky

This tool allows you to easily manage Git hooks within a project. Git hooks are scripts that run automatically on specific events in your Git workflow, such as before a commit or a push. husky simplifies the process of setting up and maintaining these hooks, making sure that certain tasks (like running linters or tests) are executed automatically.

Link to docs

pre-commit

This tool helps manage and maintain multi-language hooks. It allows you to specify a set of hooks that should run before a commit is made, ensuring that the process is aborted if certain checks are not successful. pre-commit works and integrates with many languages and tools, making it super useful in a code quality setup.

Link to docs

lint-staged

This tool allows you to run linters on staged files in Git. This means that only the files that are about to be committed are checked, which can help developers avoid unchecked code being merged accidentally. lint-staged works well with husky and pre-commit, allowing you to create a complete quality check workflow.

Link to docs

How to configure the setup?

👉 Install the dependencies

First, we need to add husky and lint-staged to our development dependencies:

$ npm install husky lint-staged --save-dev
👉 Initialize husky

Next, we need to execute the install command for husky. This command automatically adds some relevant changes and configs to your project:

$ npx husky install

Once done, we can execute the automatically generated prepare script that was added to package.json:

$ npm run prepare

This command will create a couple of files in your project. To make things work, we need to manually modify .husky/pre-commit to run lint-staged:

. "$(dirname -- "$0")/_/husky.sh"

npm lint-staged
👉 Add a custom lint-staged config

To configure lint-staged, we need to add a .lintstagedrc file for each application. This file will make sure that we execute various checks depending on the type of file being committed:

{
  "**/*.js": "eslint",
  "**/*.{css,scss}": "stylelint",
  "**/*.{js,ts,jsx,tsx,json,css,scss,md}": "prettier --write"
}
👉 All done!

Once complete, the code quality setup for our project will look somewhat similar to this one:

A visualization of a code quality system built with husky, pre-commit, and separate lint-staged configurations per applicationA visualization of a code quality system built with husky, pre-commit, and separate lint-staged configurations per application

Introducing a build system

A visualization of how the Nx build system can be used to run code quality tasks across projects in a monorepoA visualization of how the Nx build system can be used to run code quality tasks across projects in a monorepo

Nx is a build system that offers many helpful tools for working with monorepos. It handles managing dependencies between applications, running tasks in parallel, and ensuring consistent configurations across multiple projects.

By integrating husky, pre-commit, and lint-staged with a powerful build system like Nx, you can execute commands across multiple applications and cache the outputs. This can significantly reduce the development time, as redundant tasks are not re-calculated, but fetched directly from the cache.

A build system like Nx can help scale task execution and maintain consistency across multiple applications, making it a great tool for managing large-scale monorepos.

Link to docs

Conclusion

Using husky, pre-commit, and lint-staged to (gently) enforce coding standards can help developers keep track of code quality and ensure code is merged only if the quality checks pass.

For individual projects and monorepos, automating repetitive tasks and ensuring coding standards can help prevent errors, reduce technical debt, and significantly improve the developer experience.

NxHuskyPre-commitLint-staged