Frontend Development 24 min read

Setting Up Stylelint, LS‑Lint, Husky, Lint‑Staged, and Commitlint for a Robust Frontend Workflow

This tutorial walks through configuring Stylelint, LS‑Lint, Husky Git hooks, Lint‑Staged, and Commitlint to enforce code style, file‑naming conventions, pre‑commit checks, and conventional commit messages, providing a comprehensive engineering setup for modern frontend projects.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Setting Up Stylelint, LS‑Lint, Husky, Lint‑Staged, and Commitlint for a Robust Frontend Workflow

This article, originally published on the Rare Earth Juejin tech community, explains how to extend a frontend project's engineering configuration beyond ESLint and Prettier by adding Stylelint and its underlying principles.

Stylelint configuration : Install Stylelint with pnpm i stylelint -D , then create a stylelint.config.js file that defines plugins , extends (e.g., stylelint-config-standard or stylelint-config-airbnb ), syntax for SCSS, and custom rules . To avoid conflicts with Prettier, add stylelint-config-prettier . For SCSS support, install stylelint-scss ( pnpm i stylelint-scss -D ) and include it in plugins . Example configuration:

/* https://stylelint.io/user-guide/rules/selector-class-pattern/ */
module.exports = {
  root: true,
  plugins: ['stylelint-scss'],
  extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
  syntax: 'scss',
  rules: {},
  ignoreFiles: ['**/*.js', '**/*.ts', '**/*.tsx', '**/*.jsx', '**/*.vue']
};

Place a .stylelintignore file to exclude patterns, then add a lint script in package.json such as:

"lint:css": "stylelint 'packages/theme-chalk/src/**/*.scss' --fix --custom-syntax postcss-scss"

Running the script shows errors, which can be fixed automatically. To get real‑time feedback in VS Code, add the following to .vscode/settings.json :

{
  "eslint.validate": ["html", "vue", "javascript", "jsx"],
  "stylelint.validate": ["css", "less", "postcss", "scss", "vue", "sass"],
  "stylelint.customSyntax": "postcss-scss",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
    "source.fixAll": true,
    "source.fixAll.stylelint": true
  }
}

File‑naming lint (LS‑Lint) : Install the package with pnpm i @ls-lint/ls-lint -D and create a .ls-lint.yml file that enforces kebab-case for directories and files under packages/components/** . Example:

ls:
  packages/components/**:
    .dir: kebab-case
    .vue: kebab-case
    .js: kebab-case
    .ts: kebab-case
    .json: kebab-case
    .d.ts: kebab-case
    .tsx: kebab-case

ignore:
  - .git
  - .vscode
  - node_modules

Add a script "lint:ls-lint": "ls-lint" to package.json and run it to catch naming violations such as camel‑cased file names.

Husky static restrictions : Husky runs custom commands before or after Git actions. Initialize Husky with npm pkg set scripts.prepare="husky install" and npm run prepare . Add a pre‑commit hook using npx husky add .husky/pre-commit "npm test" (or any lint command). The hook file starts with #!/usr/bin/env sh and executes the specified script.

Lint‑Staged for efficiency : Install pnpm i lint-staged -D and create a .lintstagedrc that runs linters only on staged files. Example configuration:

module.exports = {
  "*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
  "{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": ["prettier --write --parser json"],
  "package.json": ["prettier --write"],
  "*.vue": ["prettier --write", "eslint --fix"],
  "packages/theme-chalk/src/**/*.{scss,css}": ["stylelint --fix --custom-syntax postcss-scss", "prettier --write"],
  "*.md": ["prettier --write"]
};

Replace the original pre‑commit hook command with npm run lint:staged so only changed files are checked, dramatically reducing verification time.

Commit message linting with Commitlint : Install pnpm i @commitlint/cli -D and the conventional config pnpm i @commitlint/config-conventional -D . Create commitlint.config.js :

module.exports = {
  ignores: [commit => commit.includes('init')],
  extends: ['@commitlint/config-conventional'],
  rules: {
    'body-leading-blank': [2, 'always'],
    'footer-leading-blank': [1, 'always'],
    'header-max-length': [2, 'always', 108],
    'subject-empty': [2, 'never'],
    'type-empty': [2, 'never'],
    'subject-case': [0]
  }
};

Add a commit‑msg hook via Husky: npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"' . This enforces conventional commit messages before a commit is accepted.

Assisting commits with Commitizen : Install pnpm i cz-conventional-changelog -D , then configure package.json :

"config": {
  "commitizen": {
    "path": "cz-conventional-changelog"
  }
},
"commit": "git-cz"

Running npm run commit (or git cz ) launches an interactive prompt that generates a properly formatted commit message, which is then validated by the Commitlint hook.

In summary, the project now has a complete linting pipeline for CSS/SCSS (Stylelint), file naming (LS‑Lint), staged file checks (lint‑staged), Git‑hook enforcement (Husky), and conventional commit validation (Commitlint), all integrated with developer‑friendly tools like Commitizen, greatly improving code quality and developer experience.

frontendESLintgit hooksstylelintcommitlinthuskylint-stagedls-lint
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.