一文搞懂前端项目规范配置-Git提交配置+ eslint +stylelint+注释配置

3,218 阅读8分钟

项目规范配置

1.git提交规范配置

  • commitlint 约束commit messag规范
  • lint-stage 提交代码时只针对暂存区文件(git add), 进行代码lint检查并fix
  • husky git hooks工具 git操作时可运行指定钩子命令

配置commitlint

规范git commit message, 约束commit提交格式commitlint文档说明

git commit -m <type>(<scope>?): <subject>

type(必须):

  • feat:新功能(feature)
  • ci:自动化流程配置修改
  • fix:修补bug
  • docs:文档更新(documentation)
  • style:修改了空格、缩进等(不影响代码运行的变动)
  • refactor:功能重构(即不是新增功能,也不是修改bug的代码变动)
  • test:增加测试
  • chore:构建过程或辅助工具的变动 比如 webpack babel eslint配置
  • perf:优化相关,比如提升性能、体验。
  • revert:回滚

scope(可选):

scope用于说明 commit 影响的范围,比如 feat(src/element.js): element按需导入

subject(必须): commit的简短描述

# example
git commit -m "some message" # fails
git commit -m "fix: some message" # passes

安装commitlint

commitlint官方文档

# 安装 commitlint
npm install --save-dev @commitlint/config-conventional  @commitlint/cli

# 第二种安装commitlint写法
# 如果命令窗口是 mac iterm2 或 windows cmder支持此复合写法安装 (windows cmd powershell不支持此写法会报错)
npm install --save-dev @commitlint/{cli,config-conventional}

项目目录下创建commitlint配置文件:

module.exports = {
  extends: ['@commitlint/config-conventional']
}

安装lint-stage husky (配合commitlint使用)

安装lint-stage

lint-stage代码lint工具 只处理暂存区文件,husky git钩子工具

# 装lint-stage 
npm i -D lint-staged

安装husky

npm i husky -D

通过husky安装两个hook

yarn husky add,添加一个commit-msg hook 和 pre-commit hook

husky与commitlint文档说明 windows建议用 git bash 执行命令 mac 建议用iterm2 执行命令

# Install Husky v6
npm install husky --save-dev
# or
yarn add husky --dev

# Active hooks
# 激活开启 husky 执行完会看到根目录下生成.husky文件夹 里面会保存husky add增加的hook文件
npx husky install
# or
yarn husky install

# Add hook
# 再添加一个pre-commit hook 代码提交时 用来执行lint-staged命令
# --no-install 参数表示强制npx使用项目本地安装的commitlint 和 lint-staged npm包
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit $1'
# or
yarn husky add .husky/commit-msg 'yarn commitlint --edit $1'

刚刚用husky添加的两个hook会在当前根目录下 ./husky文件夹里看到commit-msg pre-commit

package.json添加如下内容(样式校验会在后面说明)

"husky": {
    "hooks": {
      "pre-commit": "lint-staged",
      "commit-msg": "npx --no-install commitlint --edit $1"
    }
  },
  "lint-staged": {
    "*.{js,vue}": [
      "stylelint --config  ./.stylelintrc --fix",
      "eslint --fix"
    ],
    "*.{less,css}": [
      "stylelint --config  ./.stylelintrc --fix"
    ]
  }

验证配置

git commit时 liint-staged会先对暂存区文件进行代码格式化 然后检查commit message规范'

commit 失败

git commit -m "提交代码"

控制台错误信息

qbank git:(cq-dev) ✗ git commit -m"提交代码"Preparing...
✔ Running tasks...
✔ Applying modifications...
✔ Cleaning up...
⧗   input: 提交代码
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]

✖   found 2 problems, 0 warnings
ⓘ   Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint

husky - commit-msg hook exited with code 1 (error)

commit 成功

# type 类型 feat(项目新功能) fix(修补bug) test(测试) chore(工程配置改动)
# scope 影响范围 比如 src/main
# subject msg简短描述
# type(scope): subject  冒号后面也要有一个空格
git commit -m "chore(config): 添加commitlint和lint-stage配置"

控制台信息

qbank git:(cq-dev) ✗ git commit -m "chore(config): 添加commitlint和lint-stage配置"
✔ Preparing...
✔ Running tasks...
✔ Applying modifications...
✔ Cleaning up...
[cq-dev 8098a3e6] chore(config): 添加commitlint和lint-stage配置
 7 files changed, 984 insertions(+), 14 deletions(-)
 create mode 100644 .husky/.gitignore
 create mode 100755 .husky/commit-msg
 create mode 100755 .husky/pre-commit
 create mode 100644 commitlint.config.js
 

2.EsLint + styleLint 配置

安装esLint依赖:

npm install eslint-plugin-vue eslint @vue/cli-plugin-eslint -D

安装styleLint依赖:

npm install stylelint-config-standard stylelint-order stylelint -D

.eslintrc.js文件配置

module.exports = {
  root: true, // 检测到最近一级.eslintrc*
  env: {
    es6: true, // 支持并启用es6语法
    node: true, // 支持node语法及变量
    browser: true, // 支持浏览器全局变量
  },
  extends: ['plugin:vue/recommended', 'eslint:recommended'], // 第三方插件
  plugins: ['vue'],
  parserOptions: {
    parser: 'babel-eslint', // 解析器,默认使用Espree
    ecmaVersion: 2018,
    sourceType: 'module', // 指定文件来源类型,"script" (默认) 或 "module"(如果你的代码是 ECMAScript 模块)
  },
  // 全局变量不做校验
  globals: {
    moment: 'writable',
    Vue: 'writable',
    VueRouter: 'writable',
    VueI18n: 'writable',
    ELEMENT: 'writable',
    TWEEN: 'writable',
    _: 'writable',
    MathJax: 'writable'
  },
  rules: {
    indent: ['error', 2, {SwitchCase: 1}],
    'no-debugger': 2,
    'no-unused-vars': 1,
    eqeqeq: 2,
    quotes: ['error', 'single', {'allowTemplateLiterals': true}],
    'no-irregular-whitespace': 2, // 禁止不规则的空格
    'no-multi-spaces': 'error', // 禁止多个空格
    'space-infix-ops': 2, // 运算符前后禁止多个空格
    'array-bracket-spacing': ['error', 'never'], // 数组统一空格
    'block-spacing': ['error', 'always'],
    'comma-spacing': ['error'],
    'comma-style': ['error', 'last'],
    'computed-property-spacing': ['error', 'never'],
    'func-call-spacing': ['error', 'never'],
    'key-spacing': ['error', {'beforeColon': false, 'afterColon': true}], // 冒号空格
    'keyword-spacing': ['error', {'before': true}], //if () {}空格else
    'no-whitespace-before-property': 'error',
    'semi-spacing': 'error', //分号空格
    'space-before-blocks': ['error', 'never'], //function name()空格{}
    'space-before-function-paren': ['error', 'never'], //function name空格(){}
    'space-in-parens': ['error', 'never'],
    'arrow-spacing': ['error', {'before': false, 'after': false}], //()空格=>空格{}
    'rest-spread-spacing': ['error', 'never'], // 空格...空格{}
    'no-unreachable': 1,
    'no-console': ["error", { allow: ["error","warn"] }],

    'no-trailing-spaces': 2,
    'object-curly-spacing': ['error', 'never'],
    // 'vetur.validation.template': false,
    // 'vue/valid-template-root': 'off',
    'vue/no-v-html': 0,
    'vue/component-tags-order': ['error', {'order': ['style', 'template', 'script']}],

    'vue/html-quotes': ['error', 'double'],
    'vue/require-v-for-key': 1, // v-for要有key
    'vue/html-self-closing': 'off', // 标签闭合
    'vue/html-closing-bracket-newline': ['error', {
      'singleline': 'never',
      'multiline': 'never'
    }],
    'vue/html-closing-bracket-spacing': 'error', // 标签后是否允许空格
    'vue/html-end-tags': 'error', // 标签自我关闭
    'vue/mustache-interpolation-spacing': 2, // 标签插值中前后固定一个空格
    'vue/no-reserved-component-names': 'error', // 禁止保留名称
    'vue/no-unsupported-features': 1, // 未支持的语法
    'vue/no-unused-components': 1, // 未注册的组件
    'vue/padding-line-between-blocks': 1, //
    'vue/no-use-v-if-with-v-for': 1,
    'vue/singleline-html-element-content-newline': 0, // {{}}强制换行
    // "vue/static-class-names-order": 1, // name属性
    'vue/max-attributes-per-line': ['error', { // 单行和多行属性数量
      'singleline': 10,
      'multiline': {
        'max': 1,
        'allowFirstLine': false
      }
    }],
  },
};

eslint呼略文件 .eslintignore

dist
node_modules

.stylelintrc.js文件配置

module.exports = {
  extends: ['stylelint-config-standard'],
  plugins: ["stylelint-order"],
  rules:{
    'no-descending-specificity':null,
    'function-url-quotes': 'always',
    'string-quotes': 'double', 
    'indentation': 2,
    'unit-case':null,
    'color-hex-case': 'upper',
    'color-hex-length': 'long',
    'rule-empty-line-before': 'never',
    'font-family-no-missing-generic-family-keyword': null,
    'block-opening-brace-space-before':'always',
    'property-no-unknown':null,
    'no-empty-source':null,
   
    "order/properties-order": [

      //css内容
      'content',
      'counter-increment',
      'counter-reset',
      'quotes',
      'crop',
      'move-to',
      'page-policy',

      //css3 过渡
      
      'transition',
      'transition-property',
      'transition-duration',
      'transition-delay',
      'transition-timing-function',

      //css3 2d 3d       
      'transform-origin',
      'transform-style',
      'perspective',
      'perspective-origin',
      'backface-visibility',
      'transform',

      //动画
      'animation',
      'animation-name',
      'animation-duration',
      'animation-timing-function',
      'animation-delay',
      'animation-iteration-count',
      'animation-direction',
      'animation-play-state',
      'animation-fill-mode',

      //定位
      'box-sizing',
      'display',
      'vertical-align',
      'visibility',
      //溢出
      'overflow',
      'overflow-x',
      'overflow-y',
      'overflow-style',

      //表格
      'border-collapse',//边框合并
      'border-spacing',
      'caption-side',
      'empty-cells',
      'table-layout',


      //定位
      'position',
      'z-index',
      'left',
      'top',
      'right',
      'bottom',
      'clip',


      //浮动
      'float',
      'clear',

      //大小
      'width',
      'min-width',
      'max-width',
      'height',
      'min-height',
      'max-height',

      //填充
      'padding',
      'padding-left',
      'padding-top',
      'padding-right',
      'padding-bottom',

      //间距
      'margin',
      'margin-left',
      'margin-top',
      'margin-right',
      'margin-bottom',

      //背景
      'background',
      'background-color',
      'background-image',
      'background-size',
      'background-position',
      'background-repeat',
      'background-attachment',
      'background-origin',
      'background-clip',
      
      //边框
      'border',
      'border-width',
      'border-style',
      'border-color',
      'border-left',
      'border-left-width',
      'border-left-style',
      'border-left-color',
      'border-top',
      'border-top-width',
      'border-top-style',
      'border-top-color',
      'border-right',
      'border-right-width',
      'border-right-style',
      'border-right-color',
      'border-bottom',
      'border-bottom-width',
      'border-bottom-style',
      'border-bottom-color',
      'outline',
      'outline-width',
      'outline-style',
      'outline-color',
      'outline-offset',

      'border-image',
      'border-image-source',
      'border-image-slice',
      'border-image-width',
      'border-image-outset',
      'border-image-repeat',

      'border-radius',
      'border-top-left-radius',
      'border-top-right-radius',
      'border-bottom-right-radius',
      'border-bottom-left-radius',
      
      'box-shadow',
      


      //效果

      
      'list-style',
      'list-style-type',
      'list-style-position',
      'list-style-image',

      'opacity',
      'cursor',
      'resize',

      //文字
      'font',
      'font-family',
      'font-size',
      'line-height',
      
      'font-weight',
      'text-align',
      'text-justify',
      'text-indent',
      'letter-spacing',
      
      'white-space',
      'word-spacing',
      'text-overflow',
      
      'word-break',
      'word-wrap',
      

      'color',
      'direction',
      'font-style',
      'text-decoration',
      'text-transform',
      'text-shadow',
      
      'font-variant',
      'font-size-adjust',
      'font-stretch',

      'unicode-bidi',
      'hanging-punctuation',
      'punctuation-trim',
      'text-align-last',
      'text-emphasis',
      
      'text-outline',
      'text-wrap',


      //无效
      'box-decoration-break',

      //旋转
      'rotation',
      'rotation-point',
      
      'color-profile',
      'rendering-intent',

      'bookmark-label',
      'bookmark-level',
      'bookmark-target',
      'float-offset',
      'hyphenate-after',
      'hyphenate-before',
      'hyphenate-character',
      'hyphenate-lines',
      'hyphenate-resource',
      'hyphens',
      'image-resolution',
      'marks',
      'string-set',

      'box-align',
      'box-direction',
      'box-flex',
      'box-flex-group',
      'box-lines',
      'box-ordinal-group',
      'box-orient',
      'box-pack',
      
      'grid-columns',
      'grid-rows',
      
      'target',
      'target-name',
      'target-new',
      'target-position',
      
      'marker-offset',
      
      'marquee-direction',
      'marquee-play-count',
      'marquee-speed',
      'marquee-style',
        
      'column-count',
      'column-fill',
      'column-gap',
      'column-rule',
      'column-rule-color',
      'column-rule-style',
      'column-rule-width',
      'column-span',
      'column-width',
      'columns',
      
      'fit',
      'fit-position',
      'image-orientation',
      'page',
      'size',
      
      'orphans',
      'page-break-after',
      'page-break-before',
      'page-break-inside',
      'widows',
      
      'appearance',

      'icon',
      'nav-down',
      'nav-index',
      'nav-left',
      'nav-right',
      'nav-up'
    ]
  } 
}

stylelint 呼略文件 .stylelintignore

dist
node_modules

3. vscode配置

1. vscode需要添加以下配置

```javascript
  "eslint.validate": ["javascript", "javascriptreact", "html", "vue"],
  "vetur.validation.template": false,
  "editor.codeActionsOnSave": {
    "source.fixAll": true
  },
  "workbench.activityBar.visible": true,
  "editor.quickSuggestions": {
    "strings": true
  },
  "git.enableSmartCommit": true,
  "editor.tabSize": 2,
  "git.confirmSync": false,
  "less.lint.unknownProperties": "ignore",
  "less.lint.vendorPrefix": "ignore",
  //快速添加文件头部注释和函数注释
  "fileheader.configObj": {
    "createFileTime": true, //设置为true则为文件新建时候作为date,否则注释生成时间为date
    "autoAdd": true, //自动生成注释
    //默认注释形式
    "annotationStr": {
        "head": "/*", //自定义注释头部
        "middle": " * @", //自定义注释中间部分(注意空格,这也是最终生成注释的一部分)
        "end": " */", //自定义注释尾部
        "use": true //设置自定义注释可用
    },
  },
  // 默认函数注释
  "fileheader.cursorMode": {
      "description": "", //自定义函数描述
      "param": "", //参数
      "return": "" //返回内容
  },
  "fileheader.customMade": {
      "Description": "", //文件内容描述
      "Author": "", //创建人,因为是团队合作,写死不合适,所以空着由创建人自行填写
      "Date": "Do not edit", //时间
      "LastEditTime": "Do not edit", //最后编辑时间
      "LastEditors": "Frank", //最后编辑人,写成自己的名字
      "Usage": "" //使用方法
  },
```

2. vscode需要添加以下插件

3.注释规范

已经安装好了自动添加注释插件 koroFileHeader vscode需要添加以下配置

//快速添加文件头部注释和函数注释
  "fileheader.configObj": {
    "createFileTime": true, //设置为true则为文件新建时候作为date,否则注释生成时间为date
    "autoAdd": true, //自动生成注释
    //默认注释形式
    "annotationStr": {
        "head": "/*", //自定义注释头部
        "middle": " * @", //自定义注释中间部分(注意空格,这也是最终生成注释的一部分)
        "end": " */", //自定义注释尾部
        "use": true //设置自定义注释可用
    },
  },
  // 默认函数注释
  "fileheader.cursorMode": {
      "description": "", //自定义函数描述
      "param": "", //参数
      "return": "" //返回内容
  },
  "fileheader.customMade": {
      "Description": "", //文件内容描述
      "Author": "changqing", //创建人,因为是团队合作,写死不合适,所以空着由创建人自行填写
      "Date": "Do not edit", //时间
      "LastEditTime": "Do not edit", //最后编辑时间
      "LastEditors": "jack", //最后编辑人,写成自己的名字
      "Usage": "" //使用方法
  }
  • 文件头部注释 快捷键: windows:ctrl+alt+i, mac:ctrl+cmd+i
  • 函数注释 快捷键: windows:ctrl+alt+t , mac:ctrl+cmd+t