创建husky规范前端项目

创建husky规范前端项目

.husky文件是一个配置文件,用于配置Git钩子。Git钩子是在Git操作时触发的脚本,可以用于自动化一些任务,比如代码格式化、代码检查、测试等。.husky文件可以指定在Git的不同操作(如commit、push等)时,应该运行哪些脚本。这样,每次进行Git操作时,就会自动运行指定的脚本,从而保证代码质量和开发效率。

Husky使用

1、安装

bash 复制代码
npm install husky -D

2、添加husky文件

  • package.json中添加如下命令;scripts中添加
bash 复制代码
 "prepare": "husky install"
  • 执行以下命令
bash 复制代码
npm run prepare "husky install"
npm run prepare # 在这之后会生成一个husky文件夹

3、lint-staged(本地暂存代码检查工具

bash 复制代码
npm install lint-staged -D
  • 判断提交的代码是否符合规范,并使用 prettier 格式化代码
bash 复制代码
npx husky add .husky/pre-commit "npm run lint:lint-staged"

4、添加lint-staged.config.js 文件

bash 复制代码
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": ["eslint --fix", "prettier --write", "stylelint --fix"],
	"*.{scss,less,styl,html}": ["stylelint --fix", "prettier --write"],
	"*.md": ["prettier --write"]
};

5、commit 校验工具,不符合则报错

bash 复制代码
npm i @commitlint/cli @commitlint/config-conventional -D
  • 在husky文件夹下自动生成 commit-msg文件
bash 复制代码
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

6、commitizen(基于 Node.js 的 git commit 命令行工具,生成标准化的 message)

bash 复制代码
# 安装 commitizen,可以快速使用 cz 或 git cz 命令进行启动。
npm install commitizen -D

7、cz-git

bash 复制代码
npm install cz-git -D
  • 配置 package.json
bash 复制代码
"config": {
  "commitizen": {
    "path": "node_modules/cz-git"
  }
}

8、新建commitlint.config.js文件:(对提交信息做格式检验的

bash 复制代码
// @see: https://cz-git.qbenben.com/zh/guide
/** @type {import('cz-git').UserConfig} */

module.exports = {
	ignores: [commit => commit === 'init'],
	extends: ['@commitlint/config-conventional'],
	rules: {
		// @see: https://commitlint.js.org/#/reference-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],
		'type-enum': [
			2,
			'always',
			[
				'init',
				'feat',
				'page',
				'completepage',
				'fix',
				'fixbug',
				'docs',
				'style',
				'refactor',
				'perf',
				'test',
				'build',
				'ci',
				'chore',
				'revert',
				'wip',
				'workflow',
				'types',
				'release',
			],
		],
	},
	prompt: {
		messages: {
			type: '选择你要提交的类型 :',
			scope: '选择一个提交范围(可选):',
			customScope: '请输入自定义的提交范围 :',
			subject: '填写简短精炼的变更描述 :\n',
			body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
			breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
			footerPrefixsSelect: '选择关联issue前缀(可选):',
			customFooterPrefixs: '输入自定义issue前缀 :',
			footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
			confirmCommit: '是否提交或修改commit ?',
		},
		types: [
			{ value: 'init: 初始化', name: '初始化:   ⏳  初始化项目', emoji: '⏳' },
			{ value: 'feat: 新增功能', name: '新增:   🚀  新增功能', emoji: '🚀' },
			{ value: 'page: 新增页面', name: '页面:   📄  新增页面', emoji: '📄' },
			{ value: 'completepage: 完成页面', name: '完成页面:   🍻  完成页面', emoji: '🍻' },
			{ value: 'fixbug: 修改bug', name: 'bug:   🐛  修改bug', emoji: '🐛' },
			{ value: 'fix: 修复', name: '修复:   🧩  修复缺陷', emoji: '🧩' },
			{ value: 'docs: 文档', name: '文档:   📚  文档变更', emoji: '📚' },
			{ value: 'style: 格式', name: '格式:   🎨  代码格式(不影响功能,例如空格、分号等格式修正)', emoji: '🎨' },
			{ value: 'refactor: 重构', name: '重构:   ♻️  代码重构(不包括 bug 修复、功能新增)', emoji: '♻️' },
			{ value: 'perf: 性能', name: '性能:   ⚡️  性能优化', emoji: '⚡️' },
			{ value: 'test: 测试', name: '测试:   ✅  添加疏漏测试或已有测试改动', emoji: '✅' },
			{
				value: 'chore: 构建',
				name: '构建:   📦️  构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)',
				emoji: '📦️',
			},
			{ value: 'ci: 集成', name: '集成:   🎡  修改 CI 配置、脚本', emoji: '🎡' },
			{ value: 'revert: 回退', name: '回退:   ⏪️  回滚 commit', emoji: '⏪️' },
			{ value: 'build: 打包', name: '打包:   🔨  项目打包发布', emoji: '🔨' },
		],
		useEmoji: true,
		themeColorCode: '',
		scopes: [],
		allowCustomScopes: true,
		allowEmptyScopes: true,
		customScopesAlign: 'bottom',
		customScopesAlias: 'custom',
		emptyScopesAlias: 'empty',
		upperCaseSubject: false,
		allowBreakingChanges: ['feat', 'fix'],
		breaklineNumber: 100,
		breaklineChar: '|',
		skipQuestions: [],
		issuePrefixs: [{ value: 'closed', name: 'closed:   ISSUES has been processed' }],
		customIssuePrefixsAlign: 'top',
		emptyIssuePrefixsAlias: 'skip',
		customIssuePrefixsAlias: 'custom',
		allowCustomIssuePrefixs: true,
		allowEmptyIssuePrefixs: true,
		confirmColorize: true,
		maxHeaderLength: Infinity,
		maxSubjectLength: Infinity,
		minSubjectLength: 0,
		scopeOverrides: undefined,
		defaultBody: '',
		defaultIssues: '',
		defaultScope: '',
		defaultSubject: '',
	},
};

9、配置 package.json 命令

json 复制代码
{
	"scripts": {
		// 以下为必配置
		"lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src",
		"lint:prettier": "prettier --write --loglevel warn \"src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}\"",
		"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
		"lint:lint-staged": "lint-staged",
		"prepare": "husky install",
		"release": "standard-version",
		"commit": "git status && git add -A && git-cz"
	}
}

10、配置完成,提交代码

相当于将代码放到暂存区,最后需要git push才能上传

bash 复制代码
npm run commit 
# 如果使用yarn
yarn commit

EditorConfig 配置

需要安装插件EditorConfig

根目录下创建.editorconfig

配置 EditorConfig

properties 复制代码
# http://editorconfig.org
root = true

[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
end_of_line = lf # 控制换行类型(lf | cr | crlf)
insert_final_newline = true # 始终在文件末尾插入一个新行
indent_style = tab # 缩进风格(tab | space)
indent_size = 2 # 缩进大小
max_line_length = 130 # 最大行长度

[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off # 关闭最大行长度限制
trim_trailing_whitespace = false # 关闭末尾空格修剪

配置 StyleLint

根据需求下载安装

1、下载 StyleLint 相关依赖

bash 复制代码
npm i stylelint stylelint-config-html stylelint-config-recommended-scss stylelint-config-recommended-vue stylelint-config-standard stylelint-config-standard-scss stylelint-config-recess-order postcss postcss-html stylelint-config-prettier -D

2、安装 Vscode 插件

3、在目录的 .vscode 文件夹下新建 settings.json

json 复制代码
{
	"editor.formatOnSave": true,
	"stylelint.enable": true,
	"editor.codeActionsOnSave": {
		"source.fixAll.stylelint": true
	},
	"stylelint.validate": [
		"css",
		"less",
		"postcss",
		"scss",
		"vue",
		"sass",
		"html"
	],
	"files.eol": "\n"
}

4、配置.stylelintrc.js

js 复制代码
// @see: https://stylelint.io

module.exports = {
	/* 继承某些已有的规则 */
	extends: [
		"stylelint-config-standard", // 配置stylelint拓展插件
		"stylelint-config-html/vue", // 配置 vue 中 template 样式格式化
		"stylelint-config-standard-scss", // 配置stylelint scss插件
		"stylelint-config-recommended-vue/scss", // 配置 vue 中 scss 样式格式化
		"stylelint-config-recess-order", // 配置stylelint css属性书写顺序插件,
		"stylelint-config-prettier", // 配置stylelint和prettier兼容
	],
	overrides: [
		// 扫描 .vue/html 文件中的<style>标签内的样式
		{
			files: ["**/*.{vue,html}"],
			customSyntax: "postcss-html",
		},
	],
	/**
	 * null  => 关闭该规则
	 */
	rules: {
		"value-keyword-case": null, // 在 css 中使用 v-bind,不报错
		"no-descending-specificity": null, // 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器
		"function-url-quotes": "always", // 要求或禁止 URL 的引号 "always(必须加上引号)"|"never(没有引号)"
		"string-quotes": "double", // 指定字符串使用单引号或双引号
		"unit-case": null, // 指定单位的大小写 "lower(全小写)"|"upper(全大写)"
		"color-hex-case": "lower", // 指定 16 进制颜色的大小写 "lower(全小写)"|"upper(全大写)"
		"color-hex-length": "long", // 指定 16 进制颜色的简写或扩写 "short(16进制简写)"|"long(16进制扩写)"
		"rule-empty-line-before": "never", // 要求或禁止在规则之前的空行 "always(规则之前必须始终有一个空行)"|"never(规则前绝不能有空行)"|"always-multi-line(多行规则之前必须始终有一个空行)"|"never-multi-line(多行规则之前绝不能有空行。)"
		"font-family-no-missing-generic-family-keyword": null, // 禁止在字体族名称列表中缺少通用字体族关键字
		"block-opening-brace-space-before": "always", // 要求在块的开大括号之前必须有一个空格或不能有空白符 "always(大括号前必须始终有一个空格)"|"never(左大括号之前绝不能有空格)"|"always-single-line(在单行块中的左大括号之前必须始终有一个空格)"|"never-single-line(在单行块中的左大括号之前绝不能有空格)"|"always-multi-line(在多行块中,左大括号之前必须始终有一个空格)"|"never-multi-line(多行块中的左大括号之前绝不能有空格)"
		"property-no-unknown": null, // 禁止未知的属性(true 为不允许)
		"no-empty-source": null, // 禁止空源码
		"declaration-block-trailing-semicolon": null, // 要求或不允许在声明块中使用尾随分号 string:"always(必须始终有一个尾随分号)"|"never(不得有尾随分号)"
		"selector-class-pattern": null, // 强制选择器类名的格式
		"scss/at-import-partial-extension": null, // 解决不能引入scss文件
		"value-no-vendor-prefix": null, // 关闭 vendor-prefix(为了解决多行省略 -webkit-box)
		"selector-pseudo-class-no-unknown": [
			true,
			{
				ignorePseudoClasses: ["global", "v-deep", "deep"],
			},
		],
	},
};

代码格式化工具Prettier

1、安装

bash 复制代码
npm install prettier -D

2、安装 Vscode 插件(Prettier)

3、配置.prettierrc.js

js 复制代码
// @see: https://www.prettier.cn

module.exports = {
	// 超过最大值换行
	printWidth: 130,
	// 缩进字节数
	tabWidth: 2,
	// 使用制表符而不是空格缩进行
	useTabs: true,
	// 结尾不用分号(true有,false没有)
	semi: true,
	// 使用单引号(true单引号,false双引号)
	singleQuote: true,
	// 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>"
	quoteProps: 'as-needed',
	// 在对象,数组括号与文字之间加空格 "{ foo: bar }"
	bracketSpacing: true,
	// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none
	trailingComma: 'all',
	// 在JSX中使用单引号而不是双引号
	jsxSingleQuote: true,
	//  (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid:省略括号 ,always:不省略括号
	arrowParens: 'avoid',
	// 如果文件顶部已经有一个 doclock,这个选项将新建一行注释,并打上@format标记。
	insertPragma: false,
	// 指定要使用的解析器,不需要写文件开头的 @prettier
	requirePragma: false,
	// 默认值。因为使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本样式进行折行
	proseWrap: 'preserve',
	// 在html中空格是否是敏感的 "css" - 遵守CSS显示属性的默认值, "strict" - 空格被认为是敏感的 ,"ignore" - 空格被认为是不敏感的
	htmlWhitespaceSensitivity: 'css',
	// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>"
	endOfLine: 'auto',
	// 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码
	rangeStart: 0,
	rangeEnd: Infinity,

	vueIndentScriptAndStyle: false, // Vue文件脚本和样式标签缩进
};

代码规范工具(ESLint)

1、安装

bash 复制代码
npm install eslint eslint-config-prettier eslint-plugin-prettier eslint-plugin-vue @typescript-eslint/eslint-plugin @typescript-eslint/parser -D

2、安装 Vscode 插件(ESLint)

3、配置.eslintrc.js

js 复制代码
// @see: http://eslint.cn

module.exports = {
	root: true,
	env: {
		browser: true,
		node: true,
		es6: true,
	},
	/* 指定如何解析语法 */
	parser: "vue-eslint-parser",
	/* 优先级低于 parse 的语法解析配置 */
	parserOptions: {
		parser: "@typescript-eslint/parser",
		ecmaVersion: 2020,
		sourceType: "module",
		jsxPragma: "React",
		ecmaFeatures: {
			jsx: true,
		},
	},
	/* 继承某些已有的规则 */
	extends: [
		"plugin:vue/vue3-recommended",
		"plugin:@typescript-eslint/recommended",
		"prettier",
		"plugin:prettier/recommended",
	],
	/*
	 * "off" 或 0    ==>  关闭规则
	 * "warn" 或 1   ==>  打开的规则作为警告(不影响代码执行)
	 * "error" 或 2  ==>  规则作为一个错误(代码不能执行,界面报错)
	 */
	rules: {
		// eslint (http://eslint.cn/docs/rules)
		"no-var": "error", // 要求使用 let 或 const 而不是 var
		"no-multiple-empty-lines": ["error", { max: 1 }], // 不允许多个空行
		"no-use-before-define": "off", // 禁止在 函数/类/变量 定义之前使用它们
		"prefer-const": "off", // 此规则旨在标记使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const
		"no-irregular-whitespace": "off", // 禁止不规则的空白

		// typeScript (https://typescript-eslint.io/rules)
		"@typescript-eslint/no-unused-vars": "error", // 禁止定义未使用的变量
		"@typescript-eslint/prefer-ts-expect-error": "error", // 禁止使用 @ts-ignore
		"@typescript-eslint/no-inferrable-types": "off", // 可以轻松推断的显式类型可能会增加不必要的冗长
		"@typescript-eslint/no-namespace": "off", // 禁止使用自定义 TypeScript 模块和命名空间。
		"@typescript-eslint/no-explicit-any": "off", // 禁止使用 any 类型
		"@typescript-eslint/ban-types": "off", // 禁止使用特定类型
		"@typescript-eslint/explicit-function-return-type": "off", // 不允许对初始化为数字、字符串或布尔值的变量或参数进行显式类型声明
		"@typescript-eslint/no-var-requires": "off", // 不允许在 import 语句中使用 require 语句
		"@typescript-eslint/no-empty-function": "off", // 禁止空函数
		"@typescript-eslint/no-use-before-define": "off", // 禁止在变量定义之前使用它们
		"@typescript-eslint/ban-ts-comment": "off", // 禁止 @ts-<directive> 使用注释或要求在指令后进行描述
		"@typescript-eslint/no-non-null-assertion": "off", // 不允许使用后缀运算符的非空断言(!)
		"@typescript-eslint/explicit-module-boundary-types": "off", // 要求导出函数和类的公共类方法的显式返回和参数类型

		// vue (https://eslint.vuejs.org/rules)
		"vue/no-v-html": "off", // 禁止使用 v-html
		"vue/script-setup-uses-vars": "error", // 防止<script setup>使用的变量<template>被标记为未使用,此规则仅在启用该no-unused-vars规则时有效。
		"vue/v-slot-style": "error", // 强制执行 v-slot 指令样式
		"vue/no-mutating-props": "off", // 不允许组件 prop的改变
		"vue/custom-event-name-casing": "off", // 为自定义事件名称强制使用特定大小写
		"vue/attributes-order": "off", // vue api使用顺序,强制执行属性顺序
		"vue/one-component-per-file": "off", // 强制每个组件都应该在自己的文件中
		"vue/html-closing-bracket-newline": "off", // 在标签的右括号之前要求或禁止换行
		"vue/max-attributes-per-line": "off", // 强制每行的最大属性数
		"vue/multiline-html-element-content-newline": "off", // 在多行元素的内容之前和之后需要换行符
		"vue/singleline-html-element-content-newline": "off", // 在单行元素的内容之前和之后需要换行符
		"vue/attribute-hyphenation": "off", // 对模板中的自定义组件强制执行属性命名样式
		"vue/require-default-prop": "off", // 此规则要求为每个 prop 为必填时,必须提供默认值
		"vue/multi-word-component-names": "off", // 要求组件名称始终为 "-" 链接的单词
	},
};
相关推荐
z千鑫2 分钟前
【前端】详解前端三大主流框架:React、Vue与Angular的比较与选择
前端·vue.js·react.js
m0_7482561434 分钟前
前端 MYTED单篇TED词汇学习功能优化
前端·学习
小白学前端6662 小时前
React Router 深入指南:从入门到进阶
前端·react.js·react
web130933203982 小时前
前端下载后端文件流,文件可以下载,但是打不开,显示“文件已损坏”的问题分析与解决方案
前端
outstanding木槿2 小时前
react+antd的Table组件编辑单元格
前端·javascript·react.js·前端框架
好名字08213 小时前
前端取Content-Disposition中的filename字段与解码(vue)
前端·javascript·vue.js·前端框架
隐形喷火龙3 小时前
element ui--下拉根据拼音首字母过滤
前端·vue.js·ui
m0_748241123 小时前
Selenium之Web元素定位
前端·selenium·测试工具
风无雨3 小时前
react杂乱笔记(一)
前端·笔记·react.js
前端小魔女3 小时前
2024-我赚到自媒体第一桶金
前端·rust