Vivia Preview

Theme Toggle

前端工程化: git提交规范

前言

前端工程化, 是前端开发中一个重要的话题, 它涉及到开发流程/代码规范/自动化构建/单元测试/持续集成等. 其中, git提交规范是前端工程化的一个重要组成部分, 它有助于团队成员之间的协作/代码的版本控制/代码的审计等.

通常会使用一些工具来规范git提交规范, 如husky/lint-staged/commitlint等.

以上是AI的回答, 本文的目的只是因为eslint9+之后, 配置格式发生了一些修改, 所以用来记录以备后续使用.

项目搭建

创建基本内容

这里使用pnpm作为包管理工具. 但是整个过程和npm/yarn/bun/pnpm等工具无关, 可以根据需要选择合适的工具.

创建一个项目的package.json.git文件:

bash

pnpm init
git init

移除package.jsonmain字段后如下:

package.json

json

{
  "name": "example-1",
  "version": "1.0.0",
  "description": "",
  "scripts": {},
  "keywords": [],
  "author": "",
  "license": "ISC"
}

main字段是指在引入时的默认入口文件, 我们现在不需要使用main字段, 所以将其移除.

安装依赖

bash

pnpm add -D husky lint-staged commitlint @commitlint/config-conventional @commitlint/cli
pnpm add -D eslint prettier @eslint/js @types/eslint__js typescript typescript-eslint
  1. huskygit钩子工具, 用于在git提交前执行一些命令.
  2. lint-staged是用于在git提交前执行一些命令.
  3. commitlint是用于校验git提交规范.
  4. @commitlint/clicommitlint的命令行工具, 用于校验git提交规范.
  5. @commitlint/config-conventionalcommitlint的配置文件, 用于校验git提交规范.
  6. eslintlint工具, 用于校验代码规范.
  7. prettierlint工具, 用于格式化代码.
  8. @eslint/jseslint的配置文件, 用于校验代码规范.
  9. typescriptts编译器, 用于编译ts代码.
  10. typescript-eslinteslint的插件, 用于校验ts代码规范.

配置husky

执行一下命令, 将husky的安装配置到package.json中:

bash

pnpm exec husky init

执行完成后, 项目目录下会新增一个.husky文件夹, 同时package.jsonscripts会多出一个prepare字段, 这是npm的执行hook.

husky文件夹

package.json

json

{
  "name": "example-1",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "prepare": "husky"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@commitlint/config-conventional": "^19.2.2",
    "@eslint/js": "^9.9.0",
    "@types/eslint__js": "^8.42.3",
    "commitlint": "^19.4.0",
    "eslint": "^9.9.0",
    "husky": "^9.1.4",
    "lint-staged": "^15.2.9",
    "prettier": "^3.3.3",
    "typescript": "^5.5.4",
    "typescript-eslint": "^8.1.0"
  }
}

可能会用到的一些 npm-hooks:

  1. preinstall: 在npm install之前执行
  2. postinstall: 在npm install完成后立即执行
  3. prepare: 在npm publish npm pack之前执行, 或者不携带参数的npm install时运行
  4. preuninstall: 在npm uninstall命令前执行
  5. postuninstall: 在npm uninstall命令后执行

这里husky是在prepare添加的, 所以在npm install时, 会执行husky的安装配置.

然后再在package.json中添加以下内容:

package.json

json

{
  "name": "example-1",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "prepare": "husky"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@commitlint/config-conventional": "^19.2.2",
    "@eslint/js": "^9.9.0",
    "@types/eslint__js": "^8.42.3",
    "commitlint": "^19.4.0",
    "eslint": "^9.9.0",
    "husky": "^9.1.4",
    "lint-staged": "^15.2.9",
    "prettier": "^3.3.3",
    "typescript": "^5.5.4",
    "typescript-eslint": "^8.1.0"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{ts,tsx,js}": [
      "eslint"
    ],
    "*.{ts,tsx,js,json,html,yml,css,less,scss,md}": [
      "prettier --write"
    ]
  }
}

其中, husky字段中的hooks字段是指git操作时的hook. lint-staged字段配置校验代码的方式

详细配置: lint-staged

常用的git hook:

  1. pre-commit: 在git commit之前执行
  2. commit-msg: 在git commit时执行
  3. post-commit: 在git commit后执行
  4. pre-push: 在git push之前执行
  5. post-push: 在git push后执行
  6. pre-rebase: 在git rebase之前执行
  7. post-rebase: 在git rebase后执行

然后修改.husky/pre-commit文件的内容为:

pnpm lint-staged

git提交前执行lint-staged, lint-staged会根据package.json的配置执行eslintprettier的校验. 然后配置对应的 eslintprettier.

typescript配置

如果不需要ts可以忽略本段.

bash

pnpm tsc --init

执行以上命令, 会创建一个tsconfig.json文件.

tsconfig.json

json

{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig to read more about this file */

    /* Projects */
    // "incremental": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
    // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
    // "tsBuildInfoFile": "./.tsbuildinfo",              /* Specify the path to .tsbuildinfo incremental compilation file. */
    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */
    // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
    // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */

    /* Language and Environment */
    "target": "es2016",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
    // "lib": [],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
    // "jsx": "preserve",                                /* Specify what JSX code is generated. */
    // "experimentalDecorators": true,                   /* Enable experimental support for legacy experimental decorators. */
    // "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
    // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
    // "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
    // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
    // "reactNamespace": "",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
    // "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
    // "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */
    // "moduleDetection": "auto",                        /* Control what method is used to detect module-format JS files. */

    /* Modules */
    "module": "commonjs",                                /* Specify what module code is generated. */
    // "rootDir": "./",                                  /* Specify the root folder within your source files. */
    // "moduleResolution": "node10",                     /* Specify how TypeScript looks up a file from a given module specifier. */
    // "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
    // "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
    // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
    // "typeRoots": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */
    // "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */
    // "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
    // "moduleSuffixes": [],                             /* List of file name suffixes to search when resolving a module. */
    // "allowImportingTsExtensions": true,               /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
    // "resolvePackageJsonExports": true,                /* Use the package.json 'exports' field when resolving package imports. */
    // "resolvePackageJsonImports": true,                /* Use the package.json 'imports' field when resolving imports. */
    // "customConditions": [],                           /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
    // "resolveJsonModule": true,                        /* Enable importing .json files. */
    // "allowArbitraryExtensions": true,                 /* Enable importing files with any extension, provided a declaration file is present. */
    // "noResolve": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */

    /* JavaScript Support */
    // "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
    // "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */
    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */

    /* Emit */
    // "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
    // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
    // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
    // "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
    // "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */
    // "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
    // "outDir": "./",                                   /* Specify an output folder for all emitted files. */
    // "removeComments": true,                           /* Disable emitting comments. */
    // "noEmit": true,                                   /* Disable emitting files from a compilation. */
    // "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
    // "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
    // "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
    // "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
    // "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
    // "newLine": "crlf",                                /* Set the newline character for emitting files. */
    // "stripInternal": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
    // "noEmitHelpers": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */
    // "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
    // "preserveConstEnums": true,                       /* Disable erasing 'const enum' declarations in generated code. */
    // "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */

    /* Interop Constraints */
    // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
    // "verbatimModuleSyntax": true,                     /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
    // "isolatedDeclarations": true,                     /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
    // "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
    "esModuleInterop": true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
    // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
    "forceConsistentCasingInFileNames": true,            /* Ensure that casing is correct in imports. */

    /* Type Checking */
    "strict": true,                                      /* Enable all strict type-checking options. */
    // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */
    // "strictNullChecks": true,                         /* When type checking, take into account 'null' and 'undefined'. */
    // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
    // "strictBindCallApply": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
    // "strictPropertyInitialization": true,             /* Check for class properties that are declared but not set in the constructor. */
    // "noImplicitThis": true,                           /* Enable error reporting when 'this' is given the type 'any'. */
    // "useUnknownInCatchVariables": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */
    // "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
    // "noUnusedLocals": true,                           /* Enable error reporting when local variables aren't read. */
    // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read. */
    // "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
    // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
    // "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
    // "noUncheckedIndexedAccess": true,                 /* Add 'undefined' to a type when accessed using an index. */
    // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
    // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */
    // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
    // "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */

    /* Completeness */
    // "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
    "skipLibCheck": true                                 /* Skip type checking all .d.ts files. */
  }
}

解开baseUrl的注释, 并且修改lib为:

json

{
  "lib": [
    "ESNext",
    "DOM"
  ]
}

再加上includesexcludes, 移除注释的内容:

tsconfig.json

json

{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig to read more about this file */
    "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
    "lib": ["ESNext", "DOM"],

    /* Modules */
    "module": "commonjs" /* Specify what module code is generated. */,
    // "rootDir": "./",                                  /* Specify the root folder within your source files. */
    // "moduleResolution": "node10",                     /* Specify how TypeScript looks up a file from a given module specifier. */
    "baseUrl": "./" /* Specify the base directory to resolve non-relative module names. */,
    /* ... */
    "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
    // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
    "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,

    /* Type Checking */
    "strict": true /* Enable all strict type-checking options. */,
    "skipLibCheck": true /* Skip type checking all .d.ts files. */
  },
  "exclude": ["node_modules"],
  "include": ["src/**/*"]
}

配置eslint

创建eslint.config.mjs文件, 并添加以下内容:

eslint.config.mjs

javascript

import eslint from '@eslint/js';
import globals from 'globals';
import tseslint from 'typescript-eslint';

export default tseslint.config(eslint.configs.recommended, ...tseslint.configs.recommended, {
  languageOptions: {
    globals: { ...globals.node, ...globals.es5 },
  },
});

如果不需要ts:

eslint.config.mjs

javascript

import eslint from '@eslint/js';
import globals from 'globals';

export default [
  eslint.configs.recommended,
  {
    languageOptions: {
      globals: { ...globals.node, ...globals.es2025 },
    },
  },
];

这里因为eslint默认没有浏览器API或者NodejsApi, 所以需要安装globals包, 并展开在这里. 至于需要展开哪些, 就按需配置了.

并且改变package.jsontype字段为module.

package.json

json

{
  "name": "example-1",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "prepare": "husky"
  },
  "type": "module",
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@commitlint/config-conventional": "^19.2.2",
    "@eslint/js": "^9.9.0",
    "@types/eslint__js": "^8.42.3",
    "commitlint": "^19.4.0",
    "eslint": "^9.9.0",
    "husky": "^9.1.4",
    "lint-staged": "^15.2.9",
    "prettier": "^3.3.3",
    "typescript": "^5.5.4",
    "typescript-eslint": "^8.1.0"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{ts,tsx,js}": [
      "eslint"
    ],
    "*.{ts,tsx,js,json,html,yml,css,less,scss,md}": [
      "prettier --write"
    ]
  }
}

这样eslint就配置完成了, 新建一个文件测试一下.

app.js

javascript

var a = 1;
console.log(1)

运行命令:

bash

pnpm eslint

正确的提示了错误信息:

eslint-error

如果需要自定义rule, 可以添加新的规则, 比如不对未使用的变量报错, 而是输出警告:

eslint.config.mjs

javascript

import eslint from '@eslint/js';
import globals from 'globals';
import tseslint from 'typescript-eslint';

export default tseslint.config(eslint.configs.recommended, ...tseslint.configs.recommended, {
  languageOptions: {
    globals: { ...globals.node, ...globals.es5 },
  },
  rules: {
    'no-unused-vars': 'warn',
    '@typescript-eslint/no-unused-vars': 'warn',
  },
});

执行eslint命令, 会输出警告:

eslint-error

配置prettier

prettier是用来格式化代码的, 在vscode上可以按照prettier的插件, 在settings.json中配置editor.formatOnSavetrue, 这样在保存时, 会自动格式化代码. 同时设置默认格式化方式为prettier插件:

vscode-settings.json

json

{
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll": "always",
    "source.organizeImports": "always"
  },
  "editor.defaultFormatter": "esbenp.prettier-vscode"
}

然后新建.pretterrc文件用来配置prettier规则:

{ "singleQuote": true, "endOfLine": "lf", "trailingComma": "all", "printWidth": 120, "tabWidth": 2, "useTabs": false, "semi": true, "bracketSpacing": true, "jsxSingleQuote": true }

其中的内容根据需求自行配置: prettier-options

prettier可能会和eslint有冲突, 所以需要再配置一下eslint的规则. 安装eslint-config-prettiereslint-plugin-prettier:

bash

pnpm add -D eslint-config-prettier eslint-plugin-prettier

修改eslint.config.mjs文件:

eslint.config.mjs

javascript

import eslint from '@eslint/js';
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
import globals from 'globals';
import tseslint from 'typescript-eslint';

export default tseslint.config(
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  eslintPluginPrettierRecommended,
  {
    languageOptions: {
      globals: { ...globals.node, ...globals.es5 },
    },
    rules: {
      'no-unused-vars': 'warn',
      '@typescript-eslint/no-unused-vars': 'warn',
    },
  },
);

配置完成后, 执行eslint命令, 会提示错误:

eslint-error

如果有需要忽略的文件, 可以在项目中添加.prettierignore文件: prettier-ignore

配置commitlint

新建commitlint.config.mjs文件, 并添加以下内容:

commitlint.config.mjs

javascript

export default {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      ['build', 'chore', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test'],
    ],
  },
};

所有的rules: commitlint-rules rules的每一个值对应:

  1. 警告等级: 0: 关闭, 1: 警告, 2: 错误
  2. 适用: always: 始终, never: 禁止
  3. rule的值

.husky文件夹新增commit-msg文件:

pnpm commitlint --edit $1

然后测试一下.

初始化git:

bash

git init

添加文件到暂存区:

bash

git add src/test.js

test.js的内容:

test.js

javascript

var a = 1

提交:

bash

git commit -m "test"

提示错误:

commit-eslint-error

可以看到, 根据lint-staged的配置, 使用了eslint对文件进行了校验, 同时因为使用了var声明变量, 所以eslint报错了.

修改内容:

test.js

javascript

const a = 1;

再次提交:

bash

git add src/test.js
git commit -m "test"

这次是commitlint报错:

commit-error

  • 提交的内容是空的
  • 提交的类型是空的

我们修改一下提交信息:

bash

git commit -m "feat: test"

commit-success

可以看到成功提交了.

但是这样提交会有点麻烦, 毕竟一个字打错了就得重来, 所以可以使用更方便得可视化提交工具: commitizen

commitizen

安装commitizen及相关依赖:

bash

pnpm add -D @commitlint/cz-commitlint commitizen inquirer@9

@commitlint/cz-commitlintcommitlintcommitizen插件, 用来结合commitlintcommitizen.

配置package.json:

package.json

json

{
  "name": "example-1",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "commit": "git-cz",
    "prepare": "husky"
  },
  "type": "module",
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@commitlint/cli": "^19.4.0",
    "@commitlint/config-conventional": "^19.2.2",
    "@commitlint/cz-commitlint": "^19.4.0",
    "@eslint/js": "^9.9.0",
    "@types/eslint__js": "^8.42.3",
    "commitizen": "^4.3.0",
    "commitlint": "^19.4.0",
    "eslint": "^9.9.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-prettier": "^5.2.1",
    "globals": "^15.9.0",
    "husky": "^9.1.4",
    "inquirer": "9",
    "lint-staged": "^15.2.9",
    "prettier": "^3.3.3",
    "typescript": "^5.5.4",
    "typescript-eslint": "^8.1.0"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{ts,tsx,js}": [
      "eslint"
    ],
    "*.{ts,tsx,js,json,html,yml,css,less,scss,md}": [
      "prettier --write"
    ]
  },
  "config": {
    "commitizen": {
      "path": "@commitlint/cz-commitlint"
    }
  }
}

执行命令:

bash

pnpm commit

commit

可以看到, 能够通过命令行进行操作提交信息. 但是这里目前是英语, 我们可以配置commitlint来支持中文:

commitlint.config.mjs

javascript

export default {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      ['build', 'chore', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test'],
    ],
  },
  prompt: {
    settings: {},
    messages: {
      skip: ':skip',
      max: 'upper %d chars',
      min: '%d chars at least',
      emptyWarning: 'can not be empty',
      upperLimitWarning: 'over limit',
      lowerLimitWarning: 'below limit'
    },
    questions: {
      type: {
        description: "Select the type of change that you're committing:",
        enum: {
          feat: {
            description: '新增功能',
            title: 'Features',
            emoji: '',
          },
          fix: {
            description: '修复bug',
            title: 'Bug Fixes',
            emoji: '🐛',
          },
          docs: {
            description: '文档',
            title: 'Documentation',
            emoji: '📚',
          },
          style: {
            description: '不影响逻辑得代码格式',
            title: 'Styles',
            emoji: '💎',
          },
          refactor: {
            description: '没有新功能或者修改',
            title: 'Code Refactoring',
            emoji: '📦',
          },
          perf: {
            description: '代码优化',
            title: 'Performance Improvements',
            emoji: '🚀',
          },
          test: {
            description: '添加或修改测试',
            title: 'Tests',
            emoji: '🚨',
          },
          build: {
            description: '影响构建得更改',
            title: 'Builds',
            emoji: '🛠',
          },
          ci: {
            description: '更改脚手架或脚本',
            title: 'Continuous Integrations',
            emoji: '⚙️',
          },
          chore: {
            description: "其他不修改src和test文件的更改",
            title: 'Chores',
            emoji: '♻️',
          },
          revert: {
            description: '恢复的commit',
            title: 'Reverts',
            emoji: '🗑',
          },
        },
      },
      subject: {
        description: 'Write a short, imperative tense description of the change',
      },
      body: {
        description: 'Provide a longer description of the change',
      },
    },
  }
};

详细配置: prompt

再次执行命令:

bash

pnpm commit

commit

可以看到提交说明成了中文的.

结语

在本文中, 我们详细探讨了如何在前端项目中实施Git提交规范, 并利用一系列工具如husky/lint-staged以及commitlint来确保每次提交都符合既定的标准.这些工具不仅提升了代码质量, 还加强了团队间的协作效率.

通过上述步骤, 我们已经成功地设置了一个能够自动检查代码风格/格式化代码并验证提交消息的环境.这不仅减少了人工审查的工作量, 还确保了每次提交都是高质量的, 从而提高了项目的整体稳定性和可维护性.

最后, 我们还引入了commitizen来简化提交过程, 使得编写符合规范的提交消息变得更加直观和便捷.无论是对于新手还是经验丰富的开发者来说, 这都是一个非常实用的功能.

随着项目的不断演进和技术栈的变化, 这些配置可能也需要随之调整.

书写本文时的环境:

  • nodejs > 18.x
  • pnpm > 8.x

依赖及其版本:

package.json

json

{
  "name": "example-1",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "commit": "git-cz",
    "prepare": "husky"
  },
  "type": "module",
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@commitlint/cli": "^19.4.0",
    "@commitlint/config-conventional": "^19.2.2",
    "@commitlint/cz-commitlint": "^19.4.0",
    "@eslint/js": "^9.9.0",
    "@types/eslint__js": "^8.42.3",
    "commitizen": "^4.3.0",
    "commitlint": "^19.4.0",
    "eslint": "^9.9.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-prettier": "^5.2.1",
    "globals": "^15.9.0",
    "husky": "^9.1.4",
    "inquirer": "9",
    "lint-staged": "^15.2.9",
    "prettier": "^3.3.3",
    "typescript": "^5.5.4",
    "typescript-eslint": "^8.1.0"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{ts,tsx,js}": [
      "eslint"
    ],
    "*.{ts,tsx,js,json,html,yml,css,less,scss,md}": [
      "prettier --write"
    ]
  },
  "config": {
    "commitizen": {
      "path": "@commitlint/cz-commitlint"
    }
  }
}

© 9999 Vivia Name

Powered by Nextjs & Theme Vivia

主题完全模仿 Vivia 主题, 有些许差异, 及使用nextjs乱写

Theme Toggle