【🔥开箱即用】vite+vue3.2+ts工程化脚手架搭建
背景介绍🏗️
什么是🏗️前端工程化? 本质上就是将前端开发流程,标准化、规范化、工具化、自动化、简单化。通过规范和工具来提高前端应用质量及开发效率,本文我们可以使用如下框架和工具,来尝试一下吧! vite+vue3.2+ts+eslint+prettier+stylelint+lint_staged+husky+commitizen(cz-customizable)+conventional-changelog-cli
github: mcmcCat工程化脚手架 喜欢的话可以支持一下,点个star哟~
(1)📝格式规范
- eslint:检查代码中的语法错误和潜在问题,避免因语法错误带来的调试成本,提高代码的质量和稳定性。
- prettier:根据一些预先定义的规则和约定调整和统一代码的格式,避免因代码风格不一致和不规范带来的一些问题,提高代码可读性和维护性。
- stylelint:可以检查 CSS 代码中的语法错误和风格问题,可以避免因 CSS 代码风格和规范不一致带来的布局和样式问题,提高页面的稳定性和可维护性。
(2)💸提交规范
- lint-staged:在代码提交前,自动对指定类型的文件进行代码风格检查和格式化,以确保代码风格和质量的一致性。
- husky:可以在 Git 提交前和提交时触发命令,来检查和规范代码的格式。
- pre-commit:git hooks的钩子,在代码提交前检查代码是否符合规范,不符合规范将不可被提交
- commit-msg:git hooks的钩子,在代码提交前检查commit信息是否符合规范,commitlint(配置规范文件)
- commitizen:git的规范化提交工具,帮助你填写commit信息,适配器cz-customizable可自定义交互信息,符合约定式提交要求
- conventional-changelog-cli:自动生成日志
工程化整体流程图示📸
git到远程仓库的流程逻辑(工程规范化)🔥仅仅只需执行三步!!
npm run commit
、npm run changelog
和git push
!!
此时你们的内心应该是:“这什么鬼图谁看的懂啊啊啊!😱😱”
相信我,跟着下面的步骤一步步进行,回过头来会发现逻辑很清晰!😘
拆分步骤🔧
Vite 创建 vue + ts 项目
npm create vite@latest
{
"name": "maimaicat-vue3-template",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.2.47"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.1.0",
"typescript": "^5.0.2",
"vite": "^4.3.2",
"vue-tsc": "^1.4.2"
}
}
Eslint 相关依赖
初始化eslint,配置
.eslintrc.js
和.eslintignore
(见完整配置章节🚀)
npx eslint --init
(1) How would you like to use ESLint?
选择:To check syntax and find problems
(2) What type of modules does your project use?
选择:JavaScript modules (import/export)
(3) Which framework does your project use?
选择:Vue.js
(4) Does your project use TypeScript?
选择:Yes
(5) Where does your code run?
选择:Browser
(6) What format do you want your config file to be in?
选择:JavaScript
(7) Would you like to install them now?
选择:Yes
(8) Which package manager do you want to use?
选择:npm
{
"devDependencies": {
"@vitejs/plugin-vue": "^4.1.0",
"typescript": "^5.0.2",
"vite": "^4.3.2",
"vue-tsc": "^1.4.2"
+
"@typescript-eslint/eslint-plugin": "^5.59.5",
"eslint": "^8.40.0",
"eslint-config-standard-with-typescript": "^34.0.1",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.7.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.12.0",
// "typescript": "^5.0.4" eslint又装了一遍
+
}
}
Prettier 相关依赖
配置
.prettierrc.js
和.prettierignore
(见完整配置章节🚀)
npm i prettier eslint-config-prettier eslint-plugin-prettier -D
{
"devDependencies": {
"@vitejs/plugin-vue": "^4.1.0",
"@typescript-eslint/eslint-plugin": "^5.59.5",
"eslint": "^8.40.0",
"eslint-config-standard-with-typescript": "^34.0.1",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.7.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.12.0",
+
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"prettier": "^2.8.8",
+
"typescript": "^5.0.2",
"vite": "^4.3.2",
"vue-tsc": "^1.4.2"
}
}
Eslint 和 Prettier冲突问题👥
如果修改了.prettierrc的配置选项,会发现 eslint 和 prettier还是冲突了,这是因为vscode插件缓存没有及时更新,重启下vscode即可。
Stylelint 相关依赖
配置
.stylelintrc.js
和.stylelintignore
(见完整配置章节🚀) 不要直接安装,因为有版本问题 !按照指定版本安装 !
npm i stylelint postcss postcss-html postcss-scss stylelint-config-prettier stylelint-config-recommended-scss stylelint-config-standard stylelint-config-standard-vue stylelint-scss stylelint-order -D
{
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview",
+
"lint": "eslint . --ext .ts,.vue --fix && stylelint **/*.css **/*.vue --fix"
+
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.1.0",
"@typescript-eslint/eslint-plugin": "^5.59.5",
"eslint": "^8.40.0",
"eslint-config-standard-with-typescript": "^34.0.1",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.7.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.12.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"prettier": "^2.8.8",
+
"postcss": "^8.4.23",
"postcss-html": "^1.5.0",
"postcss-scss": "^4.0.6",
"stylelint": "^14.6.1",
"stylelint-config-html": "^1.0.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-recommended-scss": "^6.0.0",
"stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-standard": "^25.0.0",
"stylelint-config-standard-scss": "^3.0.0",
"stylelint-order": "^5.0.0",
+
"typescript": "^5.0.2",
"vite": "^4.3.2",
"vue-tsc": "^1.4.2"
}
}
- stylelint: css样式lint工具
- postcss: 转换css代码工具
- postcss-scss: 识别scss语法
- postcss-html: 识别html/vue 中的标签中的样式
- stylelint-config-standard: Stylelint的标准可共享配置规则,详细可查看官方文档
- stylelint-config-prettier: 关闭所有不必要或可能与Prettier冲突的规则
- stylelint-config-recommended-scss: scss的推荐可共享配置规则,详细可查看官方文档
- stylelint-config-standard-vue: lint.vue文件的样式配置
- stylelint-scss: stylelint-config-recommended-scss的依赖,scss的stylelint规则集合
- stylelint-order:指定样式书写的顺序,在.stylelintrc.js中order/properties-order指定顺序
狠狠的踩坑 😭
在 npm run lint
后报错的 🚨Debug
tsconfig.json
初始时注意这个moduleResolution
配置
//默认是 "moduleResolution": "bundler",注意一下可能会引起报错“import...”
"moduleResolution": "node",
src/vite-env.d.ts
中使用到三斜杠ts语法,eslint会报错,我们采用eslint的注释法让下一行忽略检测
// 通过注释让eslint不报错三斜杠
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference types="vite/client" />
Error while loading rule '@typescript-eslint/dot-notation': You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions. project" property for @typescript-eslint/parser
原因:没有配置让eslint去解析ts,eslint识别不了ts在.eslintrc.js
中添加下面的配置
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
parser: "@typescript-eslint/parser", //指定ts解析器,解决报错
project: ["./tsconfig.json"], //添加jsconfig.json路径
},
Parsing error: Debug Failure. Expected c:/users/52600/desktop/mmcat-vue3-template/vite.config.ts === c:\users\52600\desktop\mmcat-vue3-template\vite.config.ts
原因:没有在tsconfig.json中包含vite.config.ts,ts识别不了该文件在tsconfig.json
中添加下面的配置
{
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue",
"vite.config.ts" // 注意添加!!!
],
}
lint-staged 相关依赖
npm install lint-staged --save-dev
我们可以不需要change1,因为我们在后面的husky中配置pre-commit钩子中再来配置自动执行lint-stage
的脚本,在package.json中添加
// change 1: 配置lint-staged指令
// "scripts": {
// // 新增这一行
// "lint-staged": "lint-staged",
// ...
// },
// change 2: 配置lint-staged的具体任务
"lint-staged": {
"*.{ts,vue}": [ // 对ts和vue文件
"npm run lint", // 执行"lint"脚本
"prettier --write",// 对代码进行格式化
"eslint --cache --fix" // 对代码进行语法检查并尝试自动修复
],
"*.css": "stylelint --fix"// 对 CSS 代码进行检查并尝试自动修复。
},
husky 相关依赖
npm install husky --save-dev
npx husky install
npm set-script prepare "husky install"
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview",
+
"prepare": "husky install",
+
},
"devDependencies": {
+
"husky": "^8.0.3"
+
}
设置prepare命令的目的是:在其他用户安装项目依赖时会自动执行husky install;配置完成后,在项目中执行npm run prepare
(也就是执行了husky install);执行完成后,会在项目根目录生成一个.husky
文件夹
添加 pre-commit 钩子
npx husky add .husky/pre-commit 'npx lint-staged';
执行完后,自动生成.husky/pre-commit
文件,其中npx lint-staged
就可以执行上一部分所说的lint-staged
脚本啦!
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
添加 commit-msg 钩子
配合commitlint的配置文件,可以制定规则,添加前需要安装两个依赖
npm i @commitlint/cli -D
npm i @commitlint/config-conventional -D
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
自动生成.husky/commit-msg
文件,可以看到会去执行commitlint
脚本,这就是为什么添加前需要安装另外依赖的原因
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install commitlint --edit $1
关于
commitlint
脚本的配置文件commitlint.config.js
,放在了下面 (见完整配置章节🚀)
有了commitlint
后这样在提交代码的时候,commit信息就必须遵循该配置文件规范才能够提交,不然就报错!
钩子添加完毕,配置husky钩子脚本
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E $HUSKY_GIT_PARAMS"
}
},
commitizen 相关依赖和配置
- 适配器 cz-customizable
npm install commitizen -D
npm install cz-customizable --save-dev
package.json
添加配置
"scripts": { "commit": "git add . && git-cz" }
"config": {
"commitizen": {
"path": "./node_modules/cz-customizable"
}
},
在根目录创建 .cz-config.js
自定义commit提示文件 (见完整配置章节)
conventional-changelog-cli 相关依赖和配置
注意:我们是在commit完成之后生成日志,所以本地的changelog才是最新的,而远程仓库最新的changelog是上个版本的changelog,我们可以再单独为changelog进行一次提交
npm install conventional-changelog-cli -D
"scripts": {
"commit": "git add . && git-cz && npm run changelog",//此处添加npm run changelog
"changelog": "conventional-changelog -p angular -u -i CHANGELOG.md -s "
}
完整配置🗃️
安装依赖
注意容易出现版本问题,例如eslint和prettier插件的版本不适配,stylelint插件之间版本的不适配等,可以参照package.json指定版本安装
npm create vite@latest
npx eslint --init
npm i prettier eslint-config-prettier eslint-plugin-prettier -D
npm i stylelint postcss postcss-html postcss-scss stylelint-config-prettier stylelint-config-recommended-scss stylelint-config-standard stylelint-config-standard-vue stylelint-scss stylelint-order -D
npm install lint-staged --save-dev
npm install husky --save-dev
npx husky install
npm set-script prepare "husky install"
npx husky add .husky/pre-commit 'npx lint-staged';
npm i @commitlint/cli -D
npm i @commitlint/config-conventional -D
npm install commitizen -D
npm install cz-customizable --save-dev
npm install conventional-changelog-cli -D
package.json
{
"name": "mmcat-vue3-template",
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview",
"lint": "eslint . --ext .ts,.vue --fix && stylelint **/*.css **/*.vue --fix",
"prepare": "husky install",
"commit": "git add . && git-cz && npm run changelog",
"changelog": "conventional-changelog -p angular -u -i CHANGELOG.md -s -r 0"
},
"lint-staged": {
"*.{ts,vue}": [
"npm run lint",
"prettier --write",
"eslint --cache --fix"
],
"*.css": "stylelint --fix"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E $HUSKY_GIT_PARAMS"
}
},
"config": {
"commitizen": {
"path": "./node_modules/cz-customizable"
}
},
"dependencies": {
"vue": "^3.2.47"
},
"devDependencies": {
"@commitlint/cli": "^17.6.3",
"@commitlint/config-conventional": "^17.6.3",
"@typescript-eslint/eslint-plugin": "^5.59.5",
"@typescript-eslint/parser": "^5.15.0",
"@vitejs/plugin-vue": "^4.2.3",
"commitizen": "^4.3.0",
"conventional-changelog-cli": "^2.2.2",
"cz-customizable": "^7.0.0",
"eslint": "^8.40.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-standard-with-typescript": "^34.0.1",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.7.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.12.0",
"husky": "^8.0.3",
"lint-staged": "^13.2.2",
"postcss": "^8.4.23",
"postcss-html": "^1.5.0",
"postcss-scss": "^4.0.6",
"prettier": "^2.8.8",
"stylelint": "^14.6.1",
"stylelint-config-html": "^1.0.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-recommended-scss": "^6.0.0",
"stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-standard": "^25.0.0",
"stylelint-config-standard-scss": "^3.0.0",
"stylelint-order": "^5.0.0",
"typescript": "^4.5.4",
"vite": "^4.3.5",
"vue-tsc": "^1.4.2"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"lib": ["esnext", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
/* Bundler mode */
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": false,
"strictNullChecks": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue",
"vite.config.ts",
"commitlint.config.js"
],
"references": [{ "path": "./tsconfig.node.json" }]
}
.eslintrc.js & .eslintignore
module.exports = {
// 环境,可用的全局变量
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
//将启用所有标记为“推荐”的规则(eslint官方)
"eslint:recommended",
// "plugin:vue/vue3-recommended",
"plugin:vue/vue3-essential",
// "plugin:vue/essential", vue2版本
// "plugin:@typescript-eslint/recommended",
"standard-with-typescript",
"plugin:prettier/recommended", //关闭eslint和prettier 相冲突的规则。赋予 eslint 用 prettier 格式化文档的功能。
"prettier", //放最后
],
parser: "vue-eslint-parser", //指定vue文件解析器,解决报错 Parsing error: Unexpected token )
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
parser: "@typescript-eslint/parser",
project: ["./tsconfig.json"], // 让ESLint 可以获取到项目中的 TypeScript 类型信息,包括类型定义和类型检查结果。
extraFileExtensions: [".vue"], // 这个配置的作用就是告诉 @typescript-eslint/parser 把 .vue 文件也做为 TypeScript 脚本来解析。(对于内嵌ts的vue文件)
},
rules: {
"no-irregular-whitespace": "error", // 不合法空格
"prettier/prettier": "error", // 让代码文件中不符合prettier格式化规则的都标记为错误
"arrow-body-style": "off", // 箭头函数的函数体规则(官方冲突默认不可解决,选择关闭)
"prefer-arrow-callback": "off", // 检测可以转换为箭头函数的函数(官方冲突默认不可解决,选择关闭)
// '@typescript-eslint/no-var-requires': 0, // 0关闭规则,1警告,2错误
"@typescript-eslint/no-empty-function": 1, //空函数,defineProps时会用到
"vue/multi-word-component-names": 1,
},
};
*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
/public
/docs
.husky
.local
/bin
.eslintrc.js
prettier.config.js
/src/mock/*
.prettierrc.js & .prettierignore
开发时团队共享vscode的prettier插件
{
"recommendations": ["esbenp.prettier-vscode"]
}
module.exports = {
printWidth: 50, // 多次测试发现50比较合理,超过最大值换行
// 使用 2 个空格缩进
tabWidth: 2,
// 不使用缩进符,而使用空格
useTabs: false,
// 行尾需要有分号
semi: true,
// 使用单引号代替双引号
singleQuote: true,
// 对象的 key 仅在必要时用引号
quoteProps: "as-needed",
// jsx 不使用单引号,而使用双引号
jsxSingleQuote: false,
// 尾随逗号
trailingComma: "all",
// 大括号内的首尾需要空格
bracketSpacing: true,
// jsx 标签的反尖括号需要换行。将多行 HTML(HTML、JSX、Vue、Angular)的'>'元素放在最后一行的末尾,而不是单独放在下一行(不适用于自闭合元素)。
bracketSameLine: false,
// 箭头函数,只有一个参数的时候,不需要小括号
arrowParens: "avoid",
// 使用默认的折行标准
proseWrap: "preserve",
// // 不格式化vue文件,vue文件的格式化单独设置
// vueIndentScriptAndStyle: false,
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: "ignore",
// 换行符规则 auto
endOfLine: "auto",
};
/dist/*
.local
.output.js
/node_modules/**
**/*.svg
**/*.sh
/public/*
.stylelintrc.js & .stylelintignore
module.exports = {
extends: [
"stylelint-config-standard",
"stylelint-config-prettier",
"stylelint-config-recommended-vue",
],
plugins: ["stylelint-order"],
rules: {
"no-irregular-whitespace": null,
"font-family-no-missing-generic-family-keyword": null,
"order/order": ["custom-properties", "declarations"],
"order/properties-order": [
"position",
"top",
"right",
"bottom",
"left",
"z-index",
"display",
"justify-content",
"align-items",
"float",
"clear",
"overflow",
"overflow-x",
"overflow-y",
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"padding",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left",
"width",
"min-width",
"max-width",
"height",
"min-height",
"max-height",
"font-size",
"font-family",
"font-weight",
"border",
"border-style",
"border-width",
"border-color",
"border-top",
"border-top-style",
"border-top-width",
"border-top-color",
"border-right",
"border-right-style",
"border-right-width",
"border-right-color",
"border-bottom",
"border-bottom-style",
"border-bottom-width",
"border-bottom-color",
"border-left",
"border-left-style",
"border-left-width",
"border-left-color",
"border-radius",
"text-align",
"text-justify",
"text-indent",
"text-overflow",
"text-decoration",
"white-space",
"color",
"background",
"background-position",
"background-repeat",
"background-size",
"background-color",
"background-clip",
"opacity",
"filter",
"list-style",
"outline",
"visibility",
"box-shadow",
"text-shadow",
"resize",
"transition",
],
},
};
dist/*
/node_modules/**
*.json
*.d.ts
.local
*.js
**/*.svg
**/*.sh
.md
*.ts
.husky文件夹
pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
commit-msg
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install commitlint --edit $1
commitlint.config.js
/* feat:新增功能
* fix:bug 修复
* docs:文档更新
* style:不影响程序逻辑的代码修改(修改空白字符,格式缩进,补全缺失的分号等,没有改变代码逻辑)
* refactor:重构代码(既没有新增功能,也没有修复 bug)
* perf:性能, 体验优化
* test:新增测试用例或是更新现有测试
* build:打包发布可上线版本(新版本)
* ci:主要目的是修改项目继续集成流程(例如 Travis,Jenkins,GitLab CI,Circle等)的提交
* chore:改变构建流程、或者增加依赖库、工具等
* revert:回滚某个更早之前的提交
*/
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'test',
'fix',
'docs',
'style',
'refactor',
'perf',
'chore',
'revert',
],
],
'subject-full-stop': [0, 'never'],
'subject-case': [0, 'never'],
},
};
.cz-config.js
module.exports = {
// 可选类型
types: [
{ value: 'feat', name: '✨ feat: 新功能' },
{ value: 'test', name: '✅ test: 增加测试' },
{ value: 'fix', name: '🐛 fix: 修复' },
{ value: 'docs', name: '📝 docs: 文档变更' },
{ value: 'style', name: '💄 style: 代码格式(不影响代码运行的变动)' },
{ value: 'refactor', name: '♻️ refactor: 重构(既不是增加feature,也不是修复bug)'},
{ value: 'perf', name: '⚡️ perf: 性能优化' },
{ value: 'chore', name: '🔧 chore: 改变构建流程、或者增加依赖库、工具等' },
{ value: 'revert', name: '⏪️ revert: 回退' },
],
// 消息步骤
messages: {
type: '请选择提交类型(必填):',
customScope: '请输入修改范围(可选):',
subject: '请简要描述提交(必填):',
body: '请输入详细描述(必填):',
footer: '请输入要关闭的issue(可选):',
confirmCommit: '确认使用以上信息提交?(y/n/e/h)'
},
// 关闭scope关键词(我倒是关不掉...))
scopes: [],
allowCustomScopes: false,
// 跳过问题
skipQuestions: ['customScope', 'footer'],
// subject文字长度限制默认是72
subjectLimit: 72
}
转载自:https://juejin.cn/post/7232572368622485565