Vue3后台管理系统综合解决方案(一)--- 配置项目规范

75 阅读11分钟

一、前言

当项目进行多人开发时,每个人的编码习惯、git提交习惯都不一样,那么就需要一种约定限制,按照统一风格进行代码编写和git提交。

代码规范使用eslint + prettier,git提交规范使用commitlint + husky。下面将详细说明操作步骤。

二、操作步骤

  1. 安装eslint

    pnpm add -D eslint
    
  2. 初始化配置eslint

    npx eslint --init
    

    (1)选择模式: (To check syntax and find problems)

    You can also run this command directly using 'npm init @eslint/config'.
    ? How would you like to use ESLint? ...
      To check syntax only
    > To check syntax and find problems
      To check syntax, find problems, and enforce code style
    

    (2)选择语言模块: (选JavaScript modules)

    ? What type of modules does your project use? ...
    > JavaScript modules (import/export)
      CommonJS (require/exports)
      None of these
    

    (3)选择语言框架 (选Vue.js)

    ? Which framework does your project use? ...
      React
    > Vue.js
      None of these
    

    (4)是否使用ts (视自己情况而定,我这里不用选No)

    ? Does your project use TypeScript? » No / Yes
    

    (5)代码在哪里运行 (用空格选中 Browser+Node)

    ? Where does your code run? ...  (Press <space> to select, <a> to toggle all, <i> to invert selection)
    √ Browser
    √ Node
    

    (6)您希望您的配置文件是什么格式? (选JavaScript)

    ? What format do you want your config file to be in? ...
    > JavaScript
      YAML
      JSON
    

    (7)您想现在安装它们吗? (选择Yes)

    ? Would you like to install them now? » No / Yes
    

    (8)您要使用哪个软件包管理器? (选择pnpm)

    ? Which package manager do you want to use? ...
      npm
      yarn
    > pnpm
    

    (9)安装完成后在项目中会出现.eslint.config.js文件,更改文件为.eslintrc.cjs,并将内容全部替换成如下

    // 在rules里面简单的一些配置:
    // "off" 或 0 - 关闭规则
    // "warn" 或 1 - 开启规则,使用警告级别的错误
    // "error" 或 2 - 开启规则,使用错误级别的错误
    module.exports = {
      env: {
        browser: true,
        es2021: true,
        node: true
      },
      extends: [
        'eslint:recommended', // 使用推荐的eslint
        'plugin:vue/vue3-recommended', // 使用插件支持vue3
        // 接入 prettier 的规则
        'plugin:prettier/recommended',
        'eslint-config-prettier'
      ],
      parserOptions: {
        ecmaVersion: 13,
        sourceType: 'module',
        ecmaFeatures: {
          modules: true,
          jsx: true
        },
        requireConfigFile: false,
        parser: '@babel/eslint-parser'
      },
      // eslint-plugin-vue
      plugins: [
        'vue', // 引入vue的插件 vue <==> eslint-plugin-vue
        'prettier' // 引入规范插件  prettier <==>  eslint-plugin-prettier
      ],
      globals: {
        defineProps: 'readonly',
        defineEmits: 'readonly',
        defineExpose: 'readonly',
        withDefaults: 'readonly'
      },
      // 这里时配置规则的,自己看情况配置
      // 这里可以进行自定义规则配置
      // key:规则代号
      // value:具体的限定方式
      // "off" or 0 - 关闭规则
      // "warn" or 1 - 将规则视为一个警告(不会影响退出码),只警告,不会退出程序
      // "error" or 2 - 将规则视为一个错误 (退出码为1),报错并退出程序
      rules: {
        // 自定义规则 - 其实上面集成后有很多内置的规则, 这里可以进行规则的一些修改
        'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 上线环境用打印就报警告, 开发环境关闭此规则
        'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // debugger可以终止代码执行
        'vue/multi-word-component-names': 'off', // 自定义组件名称应该由多单词大驼峰命名组成,防止和html标签冲突 --- 关闭
        'vue/max-attributes-per-line': [
          2,
          // 多个特性的元素应该分多行撰写,每个特性一行
          {
            singleline: 10,
            multiline: {
              max: 1
            }
          }
        ],
        'vue/prop-name-casing': [1, 'camelCase'], // 在声明prop的时候,其命名应该始终使用驼峰命名
        'vue/require-v-for-key': 1, // 给v-for设置键值,与key结合使用,可以高效的更新虚拟DOM
        'vue/no-use-v-if-with-v-for': [
          2,
          {
            allowUsingIterationVar: false
          }
        ],
        // 不要把 v-if 和 v-for 用在同一个元素上——因为v-for 比 v-if 具有更高的优先级
        'vue/order-in-components': [
          1,
          {
            // 组件/实例的选项的顺序
            order: [
              'el',
              'name',
              'parent',
              'functional',
              ['delimiters', 'comments'],
              ['components', 'directives', 'filters'],
              'extends',
              'mixins',
              'inheritAttrs',
              'model',
              ['props', 'propsData'],
              'data',
              'computed',
              'watch',
              'LIFECYCLE_HOOKS',
              'methods',
              ['template', 'render'],
              'renderError'
            ]
          }
        ],
        // //
        // /// js.规范 /
        // /
        'arrow-spacing': [
          2,
          {
            // 在箭头函数之前/之后需要空格
            before: true,
            after: true
          }
        ],
        camelcase: [
          0,
          {
            // 需要驼峰命名
            properties: 'always'
          }
        ],
        'comma-dangle': [0, 'never'], // 要求或禁止使用尾随逗号;最后一个属性是不需要逗号
        'comma-spacing': [
          2,
          {
            // 强制逗号旁边的间距: 左右一个空格
            before: false,
            after: true
          }
        ],
        'comma-style': [2, 'last'], // 逗号风格
        'constructor-super': 2, // 构建方法中使用super方法
        curly: [2, 'multi-line'],
        'dot-location': [1, 'property'], // 在dot之前和之后强制换行
        'eol-last': 2, // 在文件末尾要求或禁止换行
        eqeqeq: [1, 'always', { null: 'ignore' }], // 是否使用全等
        indent: [
          'off',
          2,
          {
            // 强制执行一致的缩进
            SwitchCase: 1
          }
        ],
        'jsx-quotes': [2, 'prefer-single'], // 强制在JSX文件中一致使用单引号
        'keyword-spacing': [
          2,
          {
            // 关键字前后强制执行一致的间距
            before: true,
            after: true
          }
        ],
        'new-cap': [
          2,
          {
            // 要求构造函数名称以大写字母开头
            newIsCap: true,
            capIsNew: false
          }
        ],
        'new-parens': 2, // 调用不带参数的函数时需要括号
        'no-array-constructor': 2, // 禁止阵列构建器
        'no-class-assign': 2, // 禁止修改类声明的变量
        'no-cond-assign': 2, // 在条件语句中禁止赋值运算符
        'no-const-assign': 2, // 禁止修改使用const声明的变量
        'no-control-regex': 0, // 禁止正则表达式中的控制字符
        'no-delete-var': 2, // 禁止删除变量
        'no-dupe-args': 2, // 在函数定义中禁止重复参数
        'no-dupe-class-members': 2, // 禁止在类成员中重复名称
        'no-dupe-keys': 2, // 禁止对象重复声明属性
        'no-duplicate-case': 2, // 规则禁止重复案例标签
        'no-empty-character-class': 2, // 禁止在正则表达式中使用空字符类
        'no-empty-pattern': 2, // 不允许空的解构模式
        'no-eval': 2, // 禁止使用eval()
        'no-ex-assign': 2, // 禁止在catch子句中重新分配异常
        'no-extend-native': 2, // 禁止扩展原生对象
        'no-extra-bind': 2, // 禁止不必要的功能绑定
        'no-extra-boolean-cast': 2, // 禁止不必要的布尔类型转换
        'no-extra-parens': [2, 'functions'], // 禁止不必要的括号
        'no-func-assign': 2, // 禁止重新分配函数声明
        'no-implied-eval': 2,
        'no-inner-declarations': [2, 'functions'], // 禁止嵌套块中的变量或函数声明
        'no-invalid-regexp': 2, // 禁止在RegExp中使用无效的正则表达式字符串
        'no-irregular-whitespace': 2, // 不允许不规则的空白
        'no-iterator': 2, // 禁止迭代器
        'no-label-var': 2, // 禁止变量名称的标签
        'no-labels': [
          2,
          {
            allowLoop: false,
            allowSwitch: false
          }
        ],
        'no-lone-blocks': 2, // 禁止不必要的嵌套块
        'no-mixed-spaces-and-tabs': 2, // 禁止使用混合空格和制表符进行缩进
        'no-multi-spaces': 2, // 禁止多个空格
        'no-multi-str': 2, // 禁止多行字符串
        'no-multiple-empty-lines': [
          2,
          {
            // 禁止多个空行
            max: 1
          }
        ],
        'no-native-reassign': 2,
        'no-negated-in-lhs': 2,
        'no-new-object': 2,
        'no-new-require': 2,
        'no-new-symbol': 2,
        'no-new-wrappers': 2,
        'no-obj-calls': 2,
        'no-octal': 2,
        'no-octal-escape': 2,
        'no-path-concat': 2,
        'no-proto': 2,
        'no-redeclare': 2,
        'no-regex-spaces': 2,
        'no-return-assign': [2, 'except-parens'],
        'no-self-assign': 2,
        'no-self-compare': 2,
        'no-sequences': 2,
        'no-shadow-restricted-names': 2,
        'no-spaced-func': 2,
        'no-sparse-arrays': 2,
        'no-this-before-super': 2,
        'no-throw-literal': 2,
        'no-trailing-spaces': 2,
        'no-undef': 0,
        'no-undef-init': 2,
        'no-unexpected-multiline': 2,
        'no-unmodified-loop-condition': 2, // 禁止未修改的循环条件
        'no-unneeded-ternary': [
          2,
          {
            // 当存在更简单的替代方案时,不允许三元运算符
            defaultAssignment: false
          }
        ],
        'no-unreachable': 2, // 返回,抛出,继续和中断语句后禁止无法访问的代码
        'no-unsafe-finally': 2, // 禁止finally块中的控制流语句
        'no-unused-vars': [
          1,
          {
            // 禁止使用未声明的变量
            vars: 'all',
            args: 'none'
          }
        ],
        'no-useless-call': 2, // 禁止不必要的call()和apply()方法
        'no-useless-computed-key': 2, // 禁止在对象上使用不必要的计算属性键
        'no-useless-constructor': 2, // 禁止不必要的构造方法
        'no-useless-escape': 0, // 禁止不必要的转义用法
        'no-whitespace-before-property': 2, // 在属性之前禁止空格
        'no-with': 2,
        'linebreak-style': [0, 'error', 'windows'],
        'one-var': [
          2,
          {
            initialized: 'never'
          }
        ],
        'operator-linebreak': [
          2,
          'after',
          {
            // 为维护强制执行一致的换行方式
            overrides: {
              '?': 'before',
              ':': 'before'
            }
          }
        ],
        'padded-blocks': [2, 'never'], // 在块内要求或禁止填充
        quotes: [
          2,
          'single',
          {
            avoidEscape: true,
            allowTemplateLiterals: true
          }
        ],
        semi: [2, 'never'],
        'semi-spacing': [
          2,
          {
            before: false,
            after: true
          }
        ],
        'space-before-blocks': [2, 'always'], // 不要存在多余的块空间
        'space-in-parens': [2, 'never'],
        'space-infix-ops': 2,
        'space-unary-ops': [
          2,
          {
            words: true,
            nonwords: false
          }
        ],
        'spaced-comment': [
          2,
          'always',
          {
            markers: ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
          }
        ],
        'template-curly-spacing': [2, 'never'],
        'use-isnan': 2,
        'valid-typeof': 2,
        'wrap-iife': [2, 'any'],
        'yield-star-spacing': [2, 'both'],
        yoda: [2, 'never'],
        'prefer-const': 1,
        'object-curly-spacing': [
          2,
          'always',
          {
            objectsInObjects: false
          }
        ],
        'array-bracket-spacing': [2, 'never'],
        'prettier/prettier': ['error', { endOfLine: 'auto' }] // 忽略换行格式的检查
      }
    }
    
  3. 新建.eslintignore文件,内容如下:

    dist
    node_modules
    
  4. 安装vite-plugin-eslint插件,用于配置vite运行时自动检测eslint规范。

    pnpm add -D vite-plugin-eslint
    
  5. 安装eslint-parser

    pnpm add -D @babel/core
    pnpm add -D @babel/eslint-parser
    
  6. 安装prettier

    pnpm add -D prettier
    pnpm add -D eslint-config-prettier // eslint兼容的插件
    pnpm add -D eslint-plugin-prettier // eslint的prettier
    
  7. 配置vite.config.js

    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import eslintPlugin from 'vite-plugin-eslint'// https://vitejs.dev/config/
    export default defineConfig({
      plugins: [
        vue(),
        eslintPlugin({
          include: ['src/**/*.js', 'src/**/*.vue', 'src/*.js', 'src/*.vue'],
          exclude: ['./node_modules/**'],
          cache: false
        })
      ]
    })
    
  8. 配置 .prettierrc,先修改文件为.prettierrc.cjs,复制内容如下(这里主要配置代码的格式规范的,有些设置要与.eslintrc.js配置一致,防止冲突)

    module.exports = {
      tabWidth: 2, // 使用2个空格缩进
      useTabs: false, // 不使用制表缩进,而使用空格
      semi: false, // 代码结尾是否加分号
      trailingComma: 'none', // 代码末尾不需要逗号  参考 https://prettier.io/docs/en/options.html#prose-wrap
      singleQuote: true, // 是否使用单引号
      printWidth: 120, // 超过多少字符强制换行
      arrowParens: 'avoid', // 单个参数的箭头函数不加括号 arg => arg
      bracketSpacing: true, // 对象大括号内两边是否加空格 { a:0 }
      endOfLine: 'auto', // 文件换行格式 LF/CRLF
      quoteProps: 'as-needed', // 对象的key仅在必要时用引号
      jsxSingleQuote: false, // jsx不使用单引号,而使用双引号
      jsxBracketSameLine: false, // jsx标签的反尖括号需要换行
      rangeStart: 0, // 每个文件格式化的范围是文件的全部内容
      rangeEnd: Infinity, // 结尾
      requirePragma: false, // 不需要写文件开头的 @prettier
      insertPragma: false, // 不需要自动在文件开头插入 @prettier
      proseWrap: 'preserve', // 使用默认的折行标准 参考 https://prettier.io/docs/en/options.html#trailing-commas
      htmlWhitespaceSensitivity: 'css' // 根据显示样式决定html要不要折行
    }
    
  9. 新建.prettierignore,内容如下:

    /dist/*
    /html/*
    .local
    /node_modules/**
    **/*.svg
    **/*.sh
    /public/*
    
  10. 添加脚本(在 packjson.json 文件的 script 字段中添加命令)

"format": "prettier --write "./**/*.{html,vue,js,ts,json,md}" "
  1. 配置VScode

    (1)安装“ESLint”插件

    (2)安装“Prettier ESLint”插件

    {
      // vscode默认启用了根据文件类型自动设置tabsize的选项
      "editor.detectIndentation": false,
      // 重新设定tabsize
      "editor.tabSize": 2,
      // 每次保存的时候自动格式化
      "editor.formatOnSave": true,
      // 每次保存的时候将代码按eslint格式进行修复
      "eslint.autoFixOnSave": true,
      // 添加vue支持
      "eslint.validate": [
        "javascript",
        "javascriptreact",
        {
          "language": "vue",
          "autoFix": true
        }
      ],
      // 让prettier使用eslint的代码格式进行校验
      "prettier.eslintIntegration": true,
      "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
      },
      "editor.fontLigatures": false,
      "[jsonc]": {
        "editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
      }
    }
    
  2. 配置husky

    (1)安装husky

    pnpm install -D husky
    

    (2)生成 husky 配置文件

    npx husky-init
    

    执行此命令后会在根目录下生成个一个.husky目录,在这个目录下面会有一个pre-commit文件,内容如下。这个文件里面的命令在我们执行commit的时候就会执行。

    #!/usr/bin/env sh
    . "$(dirname -- "$0")/_/husky.sh"
    pnpm format
    
  3. 配置commitlint(配置 git 提交时的 commit 信息,统一提交 git 提交规范)

    (1)安装commitlint

    pnpm add @commitlint/config-conventional @commitlint/cli -D
    

    (2)在项目根目录下新建 commitlint.config.cjs 文件,并填入如下代码:

    module.exports = {
      extends: ['@commitlint/config-conventional'],
      // 校验规则
      rules: {
        'type-enum': [
          2,
          'always',
          ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'chore', 'revert', 'build']
        ],
        'type-case': [0],
        'type-empty': [0],
        'scope-empty': [0],
        'scope-case': [0],
        'subject-full-stop': [0, 'never'],
        'subject-case': [0, 'never'],
        'header-max-length': [0, 'always', 72]
      }
    }
    

    配置说明:

    'feat',     //新特性、新功能
    'fix',      //修改bug
    'docs',     //文档修改
    'style',    //代码格式修改, 注意不是 css 修改
    'refactor', //代码重构
    'perf',     //优化相关,比如提升性能、体验
    'test',     //测试用例修改
    'chore',    //其他修改, 比如改变构建流程、或者增加依赖库、工具等
    'revert',   //回滚到上一个版本
    'build',    //编译相关的修改,例如发布版本、对项目构建或者依赖的改动
    

    (3)添加脚本(在 packjson.json 文件的 script 字段中添加命令)

    "commitlint": "commitlint --config commitlint.config.cjs -e -V"
    

    (4)在项目的.husky目录下创建commit-msg文件,表示执行commit时进行校验,内容如下:

    #!/usr/bin/env sh
    . "$(dirname -- "$0")/_/husky.sh"
    pnpm commitlint
    

    (5)在项目的.husky目录下创建pre-commit文件,表示执行commit前进行代码规范化,内容如下:

    #!/usr/bin/env sh
    . "$(dirname -- "$0")/_/husky.sh"
    pnpm format
    
  4. 当前package.json

{
  "name": "web_website_admin",
  "private": true,
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "prepare": "husky install",
    "commitlint": "commitlint --config commitlint.config.cjs -e -V",
    "lint": "eslint src",
    "fix": "eslint src --fix",
    "format": "prettier --write \"./**/*.{html,vue,js,ts,json,md}\" "
  },
  "dependencies": {
    "vue": "^3.4.21"
  },
  "devDependencies": {
    "@babel/core": "^7.24.5",
    "@babel/eslint-parser": "^7.24.5",
    "@commitlint/cli": "^19.3.0",
    "@commitlint/config-conventional": "^19.2.2",
    "@eslint/js": "^9.2.0",
    "@vitejs/plugin-vue": "^5.0.4",
    "eslint": "^8.57.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-config-standard": "^17.1.0",
    "eslint-plugin-import": "^2.25.2",
    "eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
    "eslint-plugin-prettier": "^5.1.3",
    "eslint-plugin-promise": "^6.0.0",
    "eslint-plugin-vue": "^9.26.0",
    "globals": "^15.2.0",
    "husky": "^8.0.0",
    "prettier": "^3.2.5",
    "vite": "^5.2.0",
    "vite-plugin-eslint": "^1.8.1"
  }
}

三、效果验证

(1)当我们打乱代码,按下ctrl + s保存,会自动根据代码规范进行格式化。

(2)当我们提交git时,提交前会执行pre-commit脚本里的内容,将其代码进行规范化,随后进行提交信息的校验,需按照我们的校验规则进行编写提交信息,否则会显示提交失败。

四、寄语

到这里,项目规范配置完成了,如需源码、资源等,观祝工种号---代码分享站领取哦~

v2-88d54674ec29c2990c2ee8c4fb228163_b (2).jpg