之前也写过一篇类似的文章,但随着框架的更新,很多写法已经发生了改变,主要是eslint和husky,这里再重新梳理一遍。
创建项目
由于vite7对node版本选择比较高,这里我们先切换node版本nvm use 20,没有安装的先安装 nvm install 20,这里我的node版本是20.19.3。创建项目npm create vite@latest,选择vue和ts
代码规范
eslint
我们通过下面的命令可以非常简单地进行 ESLint 的初始化。
npm init @eslint/config
按需选择完配置后,选择立即安装,就可一键安装相关依赖。安装成功后 ESLint 帮我们创建了
.eslint.config.js 配置文件。
我们加点配置
import js from "@eslint/js";
import { defineConfig } from "eslint/config";
import pluginVue from "eslint-plugin-vue";
import globals from "globals";
import tseslint from "typescript-eslint";
export default defineConfig([
+ { //忽略校验文件
+ ignores: ["node_modules", "dist", "public"]
+ },
{
files: ["**/*.{js,mjs,cjs,ts,vue}"],
plugins: { js },
extends: ["js/recommended"]
},
{ files: ["**/*.{js,mjs,cjs,ts,vue}"], languageOptions: {
+ globals: {...globals.browser} //配置全局变量,如{...globals.browser, wx:true}
} },
tseslint.configs.recommended,
pluginVue.configs["flat/essential"],
{ files: ["**/*.vue"], languageOptions: { parserOptions: { parser: tseslint.parser } } },
+ {
+ rules: {} //其他校验规则
+ }
]);
在 package.json 的 script 中添加命令
"scripts": {
"lint": "eslint . --ext .js,.mjs,.cjs,.ts,.vue --fix"
},
在App.vue中添加一个未使用变量testProp
<script setup lang="ts">
import HelloWorld from "./components/HelloWorld.vue";
+ const testProp = "sss";
</script>
运行npm run lint,报错,说明eslint配置生效
Prettier
一般 ESLint 用于检测代码风格代码规范,Prettier 用于对代码进行格式化。
安装依赖
npm i prettier -D
然后再根目录创建 prettier.config.js 配置文件
export default {
printWidth: 120,
tabWidth: 2,
useTabs: false,
singleQuote: false,
semi: true,
trailingComma: "none",
bracketSpacing: true
};
测试prettier是否生效,在 package.json 的 script 中添加命令
"scripts": {
"prettier":"prettier --write ./src/App.vue"
},
修改App.vue代码
<script setup lang="ts">
- import HelloWorld from "./components/HelloWorld.vue";
+ import HelloWorld from "./components/HelloWorld.vue"
+
+
+
+
+
const testProp = "sss";
</script>
运行npm run prettier后,代码已经格式化,说明prettier配置有效,删除script 中的prettier测试命令
ESLint + Prettier
在eslint校验中加入Prettier格式化,安装依赖
npm i eslint-config-prettier eslint-plugin-prettier -D
更改 Eslint 的配置文件 eslint.config.js, 在里面加入 Prettier 相关配置
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import pluginVue from "eslint-plugin-vue";
+ import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import { defineConfig } from "eslint/config";
export default defineConfig([
{ files: ["**/*.{js,mjs,cjs,ts,vue}"], plugins: { js }, extends: ["js/recommended"] },
{ files: ["**/*.{js,mjs,cjs,ts,vue}"], languageOptions: { globals: globals.browser } },
tseslint.configs.recommended,
pluginVue.configs["flat/essential"],
{ files: ["**/*.vue"], languageOptions: { parserOptions: { parser: tseslint.parser } } },
+ eslintPluginPrettierRecommended
]);
Husky + lint-staged
Husky
在安装Husky之前,我们先初始化一下git(有git的可以不用设置),运行git init, 然后再安装依赖
npm i husky -D
初始化husky
npx husky init
完成后在package.json的scripts中会多一行命令,运行npm run prepare
运行完成后,会在项目根目录下多一个
.husky文件夹
把
pre-commit内容改成npm run lint后提交一次内容 git add . && git commit -m 'init',如果触发了lint校验,说明husky配置成功
lint-staged
每次提交都检测所有代码并不是一个好的决定,比如你只修改了文件 A 结果文件 B 报错了,但是文件 B 并不是你负责的模块,emmm改还是不改?
我们可以通过 lint-staged 只对暂存区的代码进行检验。
首先安装依赖
npm i lint-staged -D
然后在 package.json 添加相关配置。
{
...,
"lint-staged": {
"*.{ts,vue}": [
"npm run lint",
"prettier --write"
]
}
}
并在 .husky/pre-commit 中替换 npm run lint 为 npx lint-staged。现在我们每次提交代码前都会对改动的文件进行 Lint 检查和prettier格式化。
commitlint
使用 commitlint 对提交信息进行校验。先安装依赖:
npm i @commitlint/cli @commitlint/config-conventional -D
然后在根目录创建配置文件 commitlint.config.js
export default {
extends: ["@commitlint/config-conventional"]
};
然后把 commitlint 命令也添加 Husky Hook。运行命令或在.husky下新建commit-msg文件,输入--no-install commitlint -e "$HUSKY_GIT_PARAMS"
echo npx '--no-install commitlint -e "$HUSKY_GIT_PARAMS"' > .husky/commit-msg
现在,运行命令
git add . && git commit -m 'init',会发现经过eslint校验和prettier格式化后,提交信息不合法被拦截导致提交失败
commitizen
安装自动化提示工具
npm i commitizen cz-conventional-changelog -D
然后在 package.json 中添加命令 commit
{
"scripts": {
"commit": "git add . && git-cz"
},
}
初始化命令行的选项信息
npx commitizen init cz-conventional-changelog --force
执行后会在package.json生成commitizen的配置信息
运行
npm run commit,就可以快捷选择相应特性啦,按照提示一步一步下去就可以。到这一步基本就完成了.
eslint-plugin-simple-import-sort
自动修复 import 排序,墙裂推荐 墙裂推荐 墙裂推荐的插件
安装插件
npm i eslint-plugin-simple-import-sort -D
在eslint.config.js中配置
import js from "@eslint/js";
import { defineConfig } from "eslint/config";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
+import importSort from "eslint-plugin-simple-import-sort";
import pluginVue from "eslint-plugin-vue";
import globals from "globals";
import tseslint from "typescript-eslint";
export default defineConfig([
{
files: ["**/*.{js,mjs,cjs,ts,vue}"],
- plugins: { js },
+ plugins: { js, "simple-import-sort": importSort },
extends: ["js/recommended"]
},
{ files: ["**/*.{js,mjs,cjs,ts,vue}"], languageOptions: { globals: globals.browser } },
tseslint.configs.recommended,
pluginVue.configs["flat/essential"],
{ files: ["**/*.vue"], languageOptions: { parserOptions: { parser: tseslint.parser } } },
eslintPluginPrettierRecommended,
{
rules: {
+ "simple-import-sort/imports": [
+ "error",
+ {
+ groups: [
+ [
+ "^vue", // vue放在首行
+ // 以字母(或数字或下划线)或“@”后面跟着字母开头的东西,通常为nodeModules引入
+ "^@?\\w",
+ "^@(/.*|$)", // 内部导入 "@/"
+ "^\\.\\.(?!/?$)", // 父级导入. 把 `..` 放在最后.
+ "^\\.\\./?$",
+ // 同级导入. 把同一个文件夹.放在最后
+ "^\\./(?=.*/)(?!/?$)",
+ "^\\.(?!/?$)",
+ "^\\./?$",
+ "^.+\\.?(css|less|scss)$", // 样式导入.
+ "^\\u0000" // 带有副作用导入,比如import 'a.css'这种.
+ ]
+ ]
+ }
+ ]
+ }
}
]);
提交后自动修复import的排列顺序,比之前看着舒服多了,我的强迫症终于好了😏😏😏

unocss
unocss 是一个非常好用的自定义 CSS 的工具,简单方便,但是能带来很强的css定义功能,也是一个墙裂推荐 墙裂推荐 墙裂推荐的插件,你绝对会爱上的一个插件
安装插件
npm i unocss -D
修改配置vite.config.ts
import UnoCSS from 'unocss/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
UnoCSS(),
],
})
在根目录下创建 uno.config.ts 文件
/* eslint-disable */
import { defineConfig } from "unocss";
export default defineConfig({
// 配置动态规则
rules: [
[/^m-([\.\d]+)$/, ([_, num]) => ({ margin: `${num}px` })],
[/^mt-([\.\d]+)$/, ([_, num]) => ({ "margin-top": `${num}px` })],
[/^mb-([\.\d]+)$/, ([_, num]) => ({ "margin-bottom": `${num}px` })],
[/^mr-([\.\d]+)$/, ([_, num]) => ({ "margin-right": `${num}px` })],
[/^ml-([\.\d]+)$/, ([_, num]) => ({ "margin-left": `${num}px` })],
[/^p-([\.\d]+)$/, ([_, num]) => ({ padding: `${num}px` })],
[/^pt-([\.\d]+)$/, ([_, num]) => ({ "padding-top": `${num}px` })],
[/^pb-([\.\d]+)$/, ([_, num]) => ({ "padding-bottom": `${num}px` })],
[/^pr-([\.\d]+)$/, ([_, num]) => ({ "padding-right": `${num}px` })],
[/^pt-([\.\d]+)$/, ([_, num]) => ({ "padding-left": `${num}px` })],
[/^fs-([\.\d]+)$/, ([_, num]) => ({ "font-size": `${num}px` })],
[/^fw-([\.\d]+)$/, ([_, num]) => ({ "font-weight": `${num}` })],
[/^lh-([\.\d]+)$/, ([_, num]) => ({ "line-height": `${num}px` })],
[/^w-([\.\d]+)$/, ([_, num]) => ({ width: `${num}px` })],
[/^h-([\.\d]+)$/, ([_, num]) => ({ height: `${num}px` })],
[/^bg-(.+)$/, ([_, color]) => ({ "background-color": color })],
[/^c-(.+)$/, ([_, color]) => ({ color })],
[/^flex$/, () => ({ display: "flex" })],
[/^fdc$/, () => ({ "flex-direction": "column" })],
[/^fww$/, () => ({ "flex-wrap": "wrap" })],
[/^fjc-(.+)$/, ([_, value]) => ({ "justify-content": value })],
[/^fai-(.+)$/, ([_, value]) => ({ "align-items": value })],
[
/^line-([\.\d]+)$/,
([_, num]) => {
return {
overflow: "hidden",
"word-break": "break-all",
"text-overflow": "ellipsis",
"-webkit-box-orient": "vertical !important",
"-webkit-line-clamp": num,
"line-clamp": num,
display: "-webkit-box !important"
};
}
],
[
/^b([\.\d]+)$/,
([_, num]) => {
return {
border: `${num}px solid #cccccc`
};
}
]
],
//配置快捷方式,将多个规则组合成一个简写
shortcuts: {
"flex-center": "flex fjc-center fai-center",
"flex-col": "flex fdc"
}
});
将 virtual:uno.css 添加到你的主入口main.ts中:
import { createApp } from "vue";
import App from "./App.vue";
+import "virtual:uno.css";
createApp(App).mount("#app");
使用的时候,省去了麻烦的css定义,尤其是各自magin/padding等存在多种值的时候