Skip to content

Native conventional commit message linting #1565

@kotkoroid

Description

@kotkoroid

Description

Vite+ positions itself as a unified toolchain that consolidates JS/TS dev-tooling config into vite.config.ts. The staged block has already absorbed lint-staged, so pre-commit enforcement is a single config block + one auto-generated hook.

Conventional Commits enforcement is the symmetric missing piece. A Vite+ project that wants commit-message validation today must:

  1. Install @commitlint/cli and a config preset (typically @commitlint/config-conventional).
  2. Add a config entry in package.json or a separate commitlint.config.* file.
  3. Hand-write .vite-hooks/commit-msg to invoke commitlint --edit "$1".

Two devDeps, a second config location, and a manual hook file — for what is, in most projects, a one-line preset choice.

Use cases

  • Projects adopting Conventional Commits for changelog automation (release-please, semantic-release).
  • Monorepos already using vp staged, where the asymmetry between pre-commit (one config block) and commit-msg (three files/deps) is most visible.
  • vp create / vp migrate flows, which today can't offer a "yes, enforce conventional commits" prompt because the integration does not exist.

Motivation

Conventional Commits is the most-adopted commit message convention in the JS ecosystem and the natural complement to the existing staged integration. Absorbing it keeps Vite+'s "config in one place" promise consistent across both git hook points and eliminates a recurring scaffolding step.

I don't currently intend to submit a PR — opening this to gauge interest first.

Suggested solution

Add a commitMsg block to the Vite+ config schema, mirroring the existing staged integration:

import { defineConfig } from 'vite-plus';

export default defineConfig({
  commitMsg: {
    convention: 'conventional',
  },
});

Behavior:

  • New command vp commit-msg <path> — reads the message file at <path> and exits non-zero on violation (equivalent to commitlint --edit "$1").
  • vp config detects the commitMsg block and generates .vite-hooks/commit-msg running vp commit-msg "$1", in the same pass that generates .vite-hooks/pre-commit for staged.
  • Absence of the block = no hook generated. Symmetric with how staged works today.
  • No new user devDependencies. Conventional Commits parsing can live inside vite-plus (or be vendored from an upstream library) so the user only sees the config block.

Future extensions could accept named presets ('angular'), an extends field for shareable configs, or inline rules — but the MVP is a single boolean-or-preset toggle for the 90% case.

Alternative

  1. Status quo (current workaround): Install @commitlint/cli + @commitlint/config-conventional, drop config in package.json or commitlint.config.*, and hand-write .vite-hooks/commit-msg. Works, but it's three extra moving parts (two devDeps + a hand-rolled hook) for what is, in the common case, a single canonical preset.

  2. Generic hooks block in vite.config.ts: Expose a freeform hooks: { 'commit-msg': '...' } map that vp config materializes. More flexible than a commitMsg-specific block, but it does not reduce devDeps — the user still installs commitlint; the hook content just relocates. Could be a complementary addition, not a substitute.

  3. Scaffolding only: vp config --commit-msg writes the commitlint setup (deps, config, hook) once. Lighter to implement, but the result is unmanaged — vp can't keep the hook in sync if the preset or hook layout evolves.

Additional context

No response

Validations

  • Read the Contributing Guidelines.
  • Confirm this request is for Vite+ itself and not for Vite, Vitest, tsdown, Rolldown, or Oxc.
  • Check that there isn't already an issue requesting the same feature.

Metadata

Metadata

Assignees

Priority

None yet

Start date

None yet

Target date

None yet

Effort

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions