本文已参与「新人创作礼」活动,一起开启掘金创作之路
上一篇,我们在项目中创建了一个
.husky
文件,主要利用了husky hooks
和git hooks
的部分功能为我们的项目做提交校验与格式化。其中我们使用到了两个非常核心的lint
插件,也就是ESlint
、Prettier
。这两篇内容实质上属于同一个前端工程化的模块--代码规范化。在这一篇,我将会深入讲一下如何利用一些插件来对我们的代码进行统一的规范化管理,帮助我们在开发时写出风格统一、质量更好的代码(同时让上一篇所做的项目配置更加有效)。
一般针对代码规则的定制分为两部分:格式规则(代码的格式风格)、质量规则(代码是否可能因为语法使用不当引起潜在的 Bug)。
本项目将会使用ESlint + Prettier + Stylelint
来制定我们的代码规则,为我们的代码做统一的检查与修正。
Prettier
最好的代码格式化工具之一——Prettier
。它可以帮助我们统一开发团队的代码风格,并提供非常好的IDE
支持,方便我们在开发时能够及时检查并修改代码格式。
在上一篇,我们已经安装了Prettier
,这里我们再创建它的配置文件.prettierrc.js
(我们只需要接受Prettier
定好的一套格式规则,只做少量的规则修改)。比如:
module.exports = {
bracketSpacing: true,
singleQuote: false,
arrowParens: "avoid",
trailingComma: "none",
};
ESlint
初学者面对的最痛苦的地方肯定少不了ESlint
这个插件(记得在VSCode
中安装该插件),相信曾经很多人都跟我一样,“给你卸了!给你关了!”,但正是这个强大的插件,为我们的JS
代码提供了大量的检测规则,帮助我们写出质量更高的代码。关于ESlint
的详细介绍,我们可以阅读官网。
ESlint 插件
ESlint 辅助插件
在上一篇,我们已经安装好了ESlint
(pnpm install -D eslint
),并且配置了一个简单的.eslintrc.js
文件(当然也可以是.eslintrc
文件)。但实际上每个项目的ESlint
配置并不简单,你不仅需要根据项目框架的需求自己制定检测规则,还需要安装各种各样开发时需要的的ESlint
插件依赖,以此来帮助你获得更加友好的代码提示。
比如如下两种开发依赖:
- Vue.js 的官方
ESLint
插件:eslint-plugin-vue
Prettier
与ESlint
整合的包:eslint-config-prettier
(配置ESLint
以关闭与Prettier
冲突的规则)、eslint-plugin-prettier
(让Prettier
作为一个插件运行在ESLint
中,通过ESLint
统一检查修改双方规则)
注:
eslint-config-prettier
插件本项目并未安装,替代插件见下边。当然你也可以直接安装这个插件。
考虑到我们的项目使用的是Vue3 + TS
,所以我们需要针对Vue3 + TS
项目的基本配置做一个规则集。我们可以安装下面两个插件,他们的配置专为@vue/cli& create-vue setups
使用而设计,解决一些ESlinct
中已知的限制。
安装完成后需要在.eslintrc.js
文件的扩展选项中做配置
module.exports = {
extends: [
"eslint:recommended",
"plugin:vue/vue3-essential",
"@vue/eslint-config-prettier"
"@vue/eslint-config-typescript", // 放在末尾,以让其关闭eslint:recommended部分规则集的功能生效
],
};
官方建议:为了解决ESLint
中的一个已知限制,我们建议您与此包一起使用@rushstack/eslint-patch
,这样您就不必安装太多依赖项。
ESlint 解析器
如果我们在
template
模板中使用复杂的指令和表达式,是很容易出错的,怎么办呢?
vue-eslint-parser 解析器可以配合我们的eslint-plugin-vue
捕捉可能出现的错误。
pnpm install -D vue-eslint-parser
用法:在.eslintrc.js
文件中加入parser
选项指定解析器
{
parser: "vue-eslint-parser";
}
还可以使用parserOptions.parser
属性来指定自定义解析器来解析script
标签(除了解析器之外的其他属性将被赋予指定的解析器),这里我推荐使用 TypeScript ESLint,我们继续安装一下。
pnpm install -D @typescript-eslint/parser
pnpm install -D @typescript-eslint/eslint-plugin
{
parser: "vue-eslint-parser",
parserOptions: {
parser: "@typescript-eslint/parser",
ecmaVersion: 2020,
sourceType: "module",
jsxPragma: "React", // 如果你用了jsx写法的话(本项目中会使用到)
ecmaFeatures: {
jsx: true
}
},
}
自定义一些 ESlint 规则集
自定义规则集主要在两部分:globals
和rules
选项
globals 选项
写 TS 的时候,我们会创建一些类型文件(xxx.d.ts
),里面都是我们定义的TS
类型。为了能够让ESlint
检查到它们并给我良好的提示,我们可以在这个选项中也做相应的配置。
比如我们自定义了一个类型Fn
(定义在types
文件夹下的index.d.ts
文件)
declare interface Fn<T = any, R = T> {
(...arg: T[]): R;
}
我们需要在.eslintrc
文件中也配置一下
{
globals: {
Fn: "readonly"
}
}
rules 选项
推荐规则
{
rules: {
"vue/no-v-html": "off",
"vue/require-default-prop": "off",
"vue/require-explicit-emits": "off",
"vue/multi-word-component-names": "off",
"@typescript-eslint/no-explicit-any": "off", // any
"no-debugger": "off",
"@typescript-eslint/explicit-module-boundary-types": "off", // setup()
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"vue/html-self-closing": [
"error",
{
html: {
void: "always",
normal: "always",
component: "always"
},
svg: "always",
math: "always"
}
],
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}
],
"no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}
],
"prettier/prettier": [
"error",
{
endOfLine: "auto"
}
]
}
}
温馨提示:如果你遇到了某个语法检测警告,并对其进行了处理,发现仍然无效。请记得重启一下 VSCode!!!重启一下 VSCode!!!重启一下 VSCode!!!
到这里,我们的ESLint
配置已经基本成形(汗~真不容易啊!)。
Stylelint
Stylelint
Style,样式,懂了,用来规范CSS
代码的--样式格式规则。先安装依赖。
pnpm install -D stylelint stylelint-config-html stylelint-config-prettier stylelint-config-recommended stylelint-config-standard stylelint-order
注:stylelint-config-html
需要配合postcss-html
使用
在项目的根目录中创建一个配置文件stylelint.config.js
,推荐配置如下
module.exports = {
root: true,
plugins: ["stylelint-order"],
customSyntax: "postcss-html",
extends: ["stylelint-config-standard", "stylelint-config-prettier"],
rules: {
"selector-class-pattern": null,
"selector-pseudo-class-no-unknown": [
true,
{
ignorePseudoClasses: ["global"],
},
],
"selector-pseudo-element-no-unknown": [
true,
{
ignorePseudoElements: ["v-deep"],
},
],
"at-rule-no-unknown": [
true,
{
ignoreAtRules: [
"tailwind",
"apply",
"variants",
"responsive",
"screen",
"function",
"if",
"each",
"include",
"mixin",
],
},
],
"no-empty-source": null,
"named-grid-areas-no-invalid": null,
"unicode-bom": "never",
"no-descending-specificity": null,
"font-family-no-missing-generic-family-keyword": null,
"declaration-colon-space-after": "always-single-line",
"declaration-colon-space-before": "never",
"rule-empty-line-before": [
"always",
{
ignore: ["after-comment", "first-nested"],
},
],
"unit-no-unknown": [true, { ignoreUnits: ["rpx"] }],
"order/order": [
[
"dollar-variables",
"custom-properties",
"at-rules",
"declarations",
{
type: "at-rule",
name: "supports",
},
{
type: "at-rule",
name: "media",
},
"rules",
],
{ severity: "warning" },
],
},
ignoreFiles: ["**/*.js", "**/*.jsx", "**/*.tsx", "**/*.ts", "**/*.json"],
overrides: [
{
files: ["*.vue", "**/*.vue", "*.html", "**/*.html"],
extends: ["stylelint-config-recommended", "stylelint-config-html"],
rules: {
"keyframes-name-pattern": null,
"selector-pseudo-class-no-unknown": [
true,
{
ignorePseudoClasses: ["deep", "global"],
},
],
"selector-pseudo-element-no-unknown": [
true,
{
ignorePseudoElements: ["v-deep", "v-global", "v-slotted"],
},
],
},
},
],
};
postcss
针对CSS
的插件,我们非常常见的还有postcss
,它可以:
- 增强代码的可读性
- 自动转换助你支持最新的
CSS
语法 CSS
模块化解决命名冲突问题- 配合
stylelint
避免CSS
代码中的错误
用法看这里。又到了安装插件环节。。。
pnpm install -D postcss postcss-html postcss-import postcss-scss
本项目使用的是SASS
,如果你使用的是less
,把postcss-scss
换成postcss-less
即可
创建postcss.config.js
配置文件
module.exports = {
plugins: [require("autoprefixer"), require("postcss-import")],
};
注:这里还使用了autoprefixer
插件(pnpm install -D autoprefixer
),它可以自动在样式中添加浏览器厂商前缀,避免手动处理样式兼容问题。
忽略文件
有些文件,我们不希望他们遵循我们定义的规则集,我们可以让他们跳过检测。
.eslintignore
public
dist
*.d.ts
package.json
.stylelintignore
/dist/*
/public/*
public/*
成形与使用
先看一下现在的目录结构跟开发依赖
tsconfig.json 配置
别忘了我们还有个tsconfig.json
文件,根据我们项目的需要,给它也配置一下。
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"strict": false,
"jsx": "preserve",
"importHelpers": true,
"experimentalDecorators": true,
"strictFunctionTypes": false,
"skipLibCheck": true,
"esModuleInterop": true,
"isolatedModules": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"sourceMap": true,
"baseUrl": ".",
"allowJs": false,
"resolveJsonModule": true,
"lib": ["dom", "esnext"],
"incremental": true,
"paths": {
// 别名配置
"/@/*": ["src/*"],
"@build/*": ["build/*"],
"/#/*": ["types/*"]
},
"types": ["node", "vite/client"], // 如果你使用element-plus,记得在这里添加"element-plus/global"
"typeRoots": ["./node_modules/@types/", "./types"]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"types/*.d.ts",
"mock/*.ts",
"vite.config.ts"
],
"exclude": ["node_modules", "dist", "**/*.js"],
"references": [{ "path": "./tsconfig.node.json" }] // 工程引用
}
这里面有一个references
选项(工程引用),本项目并未使用该功能,将其删除,并删除 tsconfig.node.json
文件。官网对此选项描述的并不太直白,可以参考这里
执行 lint
前面我们配置好了一整套的ESlint + Prettier + Stylelint
代码规则,我们可以使用VSCode
的格式化快捷键对我们的代码进行格式化,还可以使用lint
命令来手动让代码跑一次校验并格式化。
所以我们需要配置一些脚本命令(关于命令的配置,建议根据项目需要查阅官网进行配置,这里仅作推荐使用):
{
"scripts": {
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock}/**/*.{vue,ts,tsx}\" --fix",
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,css,scss,postcss,less}\" --cache --cache-location node_modules/.cache/stylelint/",
"lint": "pnpm lint:eslint && pnpm lint:prettier && pnpm lint:stylelint"
}
}
在你提交代码前,pnpm lint
一下即可
关于 .eslintcache 文件
我们发现,每当我们
pnpm lint
(lint:eslint
命令)后,就会在根目录下生成一个.eslintcache
文件,这个文件有什么用?
当我们lint
代码的时候,ESLint
会帮我们检查全部代码。检查代码是需要时间的,如果我们只更改了一小部分文件,就没有必要再全部检查一遍了。这个时候,.eslintcache
出现了。
官方解释:.eslintcache
文件能帮助我们存储有关已处理文件的信息,以便仅对更改的文件进行操作。.eslintcache
默认情况下存储在缓存中。启用此选项可以通过确保仅对更改的文件进行lint
来显着提高ESLint
的运行时间。
所以我在命令"lint:eslint"
后加了eslint --cache
。
另外的,--max-warnings
允许我们指定警告阈值,控制ESLint
退出状态。我们设为0
,这样的话,如果ESLint
检查我们代码中出现了语法警告,就会报错,即无法正常通过。--fix
选项指示ESLint
尝试帮助我们修复尽可能多的问题,输出剩余的未修复问题。
VSCode 整合
关于项目的规范化都配置好了,还有一个重要的角色就是我们所使用的IDE
工具--VSCode
。
我们发现在项目的根目录创建一个.vscode
文件夹,为了保证我们代码格式风格的严格统一,通常会在这个文件夹下创建两个配置文件。
extensions.json 扩展配置文件
其实就是为了让你更快乐地进行项目的开发,帮你提升开发效率个插件工具集。
这里就做个示例(随便截了个图),具体看项目情况而定!
{
"recommendations": [
"voorjaar.windicss-intellisense",
"vscode-icons-team.vscode-icons",
"davidanson.vscode-markdownlint",
"stylelint.vscode-stylelint",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"johnsoncodehk.volar",
"mikestead.dotenv",
"eamodio.gitlens",
"antfu.iconify"
// ......
]
}
关于VSCode
有哪些非常好用的插件,网上有很多推荐,请自行搜索自己需要的。
settings.json VSCode 配置文件
示例:
{
"editor.formatOnType": true,
"editor.formatOnSave": true,
"editor.tabSize": 2,
"editor.formatOnPaste": true,
"files.autoSave": "afterDelay",
"git.confirmSync": false,
"workbench.startupEditor": "newUntitledFile",
"editor.suggestSelection": "first",
"editor.acceptSuggestionOnCommitCharacter": false,
"css.lint.propertyIgnoredDueToDisplay": "ignore",
"editor.quickSuggestions": {
"other": true,
"comments": true,
"strings": true
},
"files.associations": {
"editor.snippetSuggestions": "top"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[less]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}