学习笔记:代码格式规范

172 阅读11分钟

Eslint

是一个插件化的Javascript代码格式检查工具。

1. 依赖安装
# eslint 安装
npm install eslint --save-dev
# eslint 插件安装
npm install eslint-plugin-vue --save-dev

npm install @typescript-eslint/eslint-plugin --save-dev

npm install eslint-plugin-prettier --save-dev

# typescript parser
npm install @typescript-eslint/parser --save-dev

# airbnb 规范
npm install eslint-config-airbnb-base --save-dev
2. 配置Eslint规则

在根目录下新建.eslintrc.js文件 (1)推荐配置 airbnb 规范详细配置见 github.com/airbnb/java…

module.exports = {
  root: true,
  env: {
    browser: true,
    node: true,
    es2021: true,
  },
  parser: 'vue-eslint-parser',
  extends: [
    'plugin:vue/vue3-recommended',
    'airbnb-base',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
    'prettier',
  ],
  parserOptions: {
    ecmaVersion: 12,
    parser: '@typescript-eslint/parser',
    sourceType: 'module'
  },
  plugins: ['vue', '@typescript-eslint', 'prettier'],
  rules: {
    // 根据需求覆盖eslint规则
    ...
  }
}

(2)常用配置

rules: {
    "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
    "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
    "@typescript-eslint/no-explicit-any": "off",
    "@typescript-eslint/camelcase": "off",
    "quotes": [1, "double"], // 引号类型 `` "" ''
    "semi": ["off", "always"], // 语句强制分号结尾
    "semi-spacing": [0, { before: false, after: true }], // 分号前后空格
    "newline-after-var": 2, // 变量声明后是否需要空一行
    "getter-return": ["error", { allowImplicit: true }], // 强制 getter 函数中出现 return 语句
    "no-control-regex": "error", // 禁止在正则表达式中出现控制字符
    "no-dupe-args": "error", // 禁止在函数定义或表达中出现重名参数
    "no-dupe-keys": "error", // 禁止对象字面量中出现重复的 key
    "no-duplicate-case": "error", // 禁止出现重复的 case 标签
    "no-empty": "error", // 禁止出现空语句块
    "no-empty-character-class": "error", // 禁止在正则表达式中使用空字符集
    "no-ex-assign": "error", // 禁止对 catch 子句中的异常重新赋值
    "no-extra-semi": "error", // 禁用不必要的分号
    "no-func-assign": "error", // 禁止对 function 声明重新赋值
    "no-inner-declarations": "error", // 要求函数声明和变量声明(可选的)在程序或函数体的顶部
    "no-irregular-whitespace": "error", // 禁止不规则的空白
    "no-obj-calls": "error", // 禁止将 Math、JSON 和 Reflect 对象当作函数进行调用
    "no-unsafe-negation": "error", // 禁止对关系运算符的左操作数使用否定操作符
    "require-atomic-updates": "error", // 禁止由于 await 或 yield的使用而可能导致出现竞态条件的赋值
    "use-isnan": "error", // 禁止与 ‘NaN’ 的比较
    "valid-typeof": ["error", { requireStringLiterals: true }], // 强制 typeof 表达式与有效的字符串进行比较
    "array-callback-return": "error", // 强制数组方法的回调函数中有 return 语句
    "block-scoped-var": "error", // 强制把变量的使用限制在其定义的作用域范围内
    "curly": "error", // 强制所有控制语句使用一致的括号风格
    "default-case": "error", // 要求 switch 语句中有 default 分支
    "dot-location": ["error", "property"], // 强制要求点操作符和属性放在同一行
    "dot-notation": ["error"], // 强制尽可能地使用点号
    "eqeqeq": ["error", "always"], // 要求使用 === 和 !==
    "max-classes-per-file": "error", // 制每个文件只能包含一个特定数量的类,没有更多
    "no-case-declarations": "error", // 不允许在 case 子句中使用词法声明, 可以用大括号
    "no-else-return": "error", // 禁止 if 语句中 return 语句之后有 else 块
    "no-empty-function": "error", // 禁止出现空函数
    "no-empty-pattern": "error", // 禁止使用空解构模式
    "no-fallthrough": ["error", { commentPattern: "break[\\s\\w]*omitted" }], // 禁止 case 语句落空, 如果结尾有注释满足break[\\s\\w]*omitted,则忽略
    "no-floating-decimal": "error", // 禁止数字字面量中使用前导和末尾小数点
    "no-global-assign": "error", // 禁止对原生对象或只读的全局对象进行赋值
    "no-multi-spaces": ["error", { ignoreEOLComments: true }], // 禁止在逻辑表达式、条件表达式、声明、数组元素、对象属性、序列和函数参数周围使用多个空格
    "no-octal": "error", // 禁用八进制字面量
    "no-redeclare": "error", // 禁止多次声明同一变量
    "no-self-assign": "error", // 禁止自我赋值
    "no-with": "error", // 禁用 with 语句
    "require-await": "error", // 禁止使用不带 await 表达式的 async 函数
    "no-shadow-restricted-names": "error", // 禁止将标识符定义为受限的名字
    "array-bracket-newline": ["error", { multiline: true }],
    "array-bracket-spacing": ["error", "never"], // 禁止在数组括号头和尾出现空格
    "block-spacing": "error", // 禁止或强制在代码块中开括号前和闭括号后有空格
    "brace-style": "error", // 强制在代码块中使用一致的大括号风格
    "camelcase": "error", // 强制使用骆驼拼写法命名约定
    "comma-dangle": ["error", "always-multiline"], // 要求使用拖尾逗号
    "comma-spacing": ["error", { before: false, after: true }], // 强制在逗号前后使用一致的空格(禁止在逗号前使用空格, 要求在逗号后使用一个或多个空格)
    "indent": ["error", 2], // 缩进风格, 2空格
    "jsx-quotes": ["error", "prefer-double"], // 强制所有不包含双引号的 JSX 属性值使用双引号
    "key-spacing": ["error", { beforeColon: false }], // 禁止在对象字面量的键和冒号之间存在空格
    "keyword-spacing": ["error", { before: true }], // 要求在关键字之前至少有一个空格
    "line-comment-position": ["error", { position: "above" }], // 强制行注释只在代码上方
    // "lines-between-class-members": ["error", "always"], // 要求类成员之间出现空行
    "newline-per-chained-call": ["error", { ignoreChainWithDepth: 2 }], // 要求在方法链中, 允许在同一行成链的最大深度
    "no-lonely-if": "error", // 禁止 if 语句作为唯一语句出现在 else 语句块中
    "no-multiple-empty-lines": ["error", { max: 1, maxEOF: 0 }], // 强制最大连续空行数(1), 强制文件末尾的没有连续空行数
    "no-whitespace-before-property": "error", // 禁止属性前有空白
    // "object-curly-newline": ["error", { multiline: true }], // 强制花括号内使用换行符的一致性, 如果在属性内部或属性之间有换行符,就要求有换行符
    "padding-line-between-statements": [
      "error",
      { blankLine: "always", prev: ["const", "let", "var"], next: "*" },
      { blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"] },
    ], // 要求或禁止在语句间填充空行, 该配置要求变量声明之后都有空行
    "space-infix-ops": "error", // 要求操作符周围有空格
    "spaced-comment": ["error", "always"], // 强制在注释中前后添加空格
    "arrow-spacing": "error", // 强制箭头函数的箭头前后使用一致的空格
    "no-class-assign": "error", // 禁止修改类声明的变量
    "no-const-assign": "error", // 禁止修改用const声明的变量
    "no-dupe-class-members": "error", // 禁止类成员中出现重复的名称
    "no-duplicate-imports": "error", // 禁止重复模块导入
    "no-new-symbol": "error", // 禁止 Symbolnew 操作符和 new 一起使用
    // "no-var": "error", // 要求使用 let 或 const 而不是 var
    "require-yield": "error", // 要求 generator 函数内有 yield
    "rest-spread-spacing": ["error", "never"], // 扩展运算符及其表达式之间不允许有空格
  }

更多规则详见官网:eslint.bootcss.com/docs/rules/

3. 配置忽略检查的文件

在根目录下新建.eslintignore文件,一般忽略node_modules、dist等文件

4. vite编译执行Eslint检查

每次代码有变动,重新编译时都会进行代码格式检查 (1)安装依赖

npm install vite-plugin-eslint --save-dev

(2)vite.config.js中添加配置

import eslintPlugin from 'vite-plugin-eslint'

plugins: [
  eslintPlugin()
],
5. 使用命令执行检查

在package.json的scripts中配置

"script": {
    "lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
    ...
  }

Tslint

待补充...

Stylelint

样式格式检查工具,支持检查多种类型的样式,包括css、less、scss、vue等。

1. 依赖安装
# stylelint 及 样式规则排序
npm install --save-dev stylelint stylelint-order
# stylelint 拓展配置
npm install --save-dev stylelint-config-prettier 
npm install --save-dev stylelint-config-recommended
npm install --save-dev stylelint-config-recommended-vue
npm install --save-dev stylelint-config-standard
# postcss
npm install --save-dev postcss postcss-html postcss-scss
2. Stylelint配置

(1)推荐配置规则 在项目根目录下新建.stylelintrc.js文件,推荐配置规则如下

module.exports = {
  root: true,
  plugins: ['stylelint-order'],
  extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
  customSyntax: 'postcss-html',
  rules: {
    'function-no-unknown': null,
    '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,
    'string-quotes': 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',
    // 'declaration-block-trailing-semicolon': 'always',
    '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'],
  overrides: [
    {
      files: ['*.vue', '**/*.vue', '*.html', '**/*.html'],
      extends: ['stylelint-config-recommended'],
      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']
          }
        ]
      }
    },
    {
      files: ['*.scss', '**/*.scss'],
      customSyntax: 'postcss-scss',
      extends: ['stylelint-config-standard', 'stylelint-config-recommended-vue']
    }
  ]
}

(2)忽略检查文件 在项目根目录下新建.stylelintignore文件,配置如下

# 其他类型文件
*.js
*.jsx
*.ts
*.tsx
*.jpg
*.woff

# 测试和打包目录
/mock/
/dist/
/node_modules/
3. IDE自动格式化

(1)Vscode插件市场安装stylelint (2)配置保存代码时启动stylelint:File => Preferences => Settings => 右上角:Open Settings(JSON) 增加如下配置

"editor.codeActionsOnSave": {
    ...
    "source.fixAll.stylelint": true
},
3. 使用命令执行检查

在package.json的scripts脚本中,添加如下配置,即可执行npm run lint:style进行格式检查和修正

"scripts": {
  ...
  "lint:style": "stylelint --fix \"**/*.{vue,postcss,css,scss}\" ",
  ...
}

Prettier

代码格式化工具,Eslint现在也集成了格式化功能,但Prettier支持格式化的文件类型更多,配置项也更简洁明了。

1. IDE自动格式化(Vscode)

(1)Vscode 插件市场安装 Prettier (2)项目中配置.prettierrc文件,.prettierignore忽略不希望格式化的文件,node_modules默认忽略 (3)设置Vscode默认格式化插件:File => Preferences => Settings => 搜索Default Formatter => 选择Prettier (4)设置格式化快捷键:File => Preferences => Keyboard Shorcuts,搜索Format Document (5)设置保存文件时自动格式化:File => Preferences => Settings => Format On Save 打开

2. 使用命令执行格式化

(1)相关依赖安装:npm install prettier --save-dev (2)项目中配置.prettierrc文件,.prettierignore忽略不希望格式化的文件,node_modules默认忽略 注:.prettierrc为JSON格式文件,也可配置.prettierrc.js,使用JS风格书写,最后module.exports导出 (3)package.json的script中添加脚本如下,然后执行npm run prettier命令全局格式化

"scripts": {
  ...
  "prettier": "prettier --write .",
  ...
}

(4)解决和eslint的冲突:安装eslint-config-prettier,这个插件会把有冲突的eslint规则关闭

3. Prettier 配置

(1)推荐配置

module.exports = {
  tabWidth: 2, // 缩进字节数
  useTabs: false, // 缩进不使用tab,使用空格
  printWidth: 100, // 超过最大值换行
  singleQuote: true, // 使用单引号代替双引号
  semi: false, // 句尾不添加分号
  trailingComma: 'none', // 尾部不添加逗号
  bracketSpacing: true, // 对象的key和value之间加空格
  quoteProps: 'as-needed', // 对象下的key值,有需要的情况下可以加引号
  endOfLine: 'auto', // 
  arrowParens: 'always', // (x) => {} 箭头函数参数一定要有小括号()
}

(2)常用配置

module.exports = {
  // 1.一行代码的最大字符数,默认是80(printWidth: <int>)
  printWidth: 80,
  // 2.tab宽度为2空格(tabWidth: <int>)
  tabWidth: 2,
  // 3.是否使用tab来缩进,我们使用空格(useTabs: <bool>)
  useTabs: false,
  // 4.结尾是否添加分号,false的情况下只会在一些导致ASI错误的其工况下在开头加分号,我选择无分号结尾的风格(semi: <bool>)
  semi: false,
  // 5.使用单引号(singleQuote: <bool>)
  singleQuote: true,
  // 6.object对象中key值是否加引号(quoteProps: "<as-needed|consistent|preserve>")as-needed只有在需求要的情况下加引号,consistent是有一个需要引号就统一加,preserve是保留用户输入的引号
  quoteProps: 'as-needed',
  // 7.在jsx文件中的引号需要单独设置(jsxSingleQuote: <bool>)
  jsxSingleQuote: false,
  // 8.尾部逗号设置,es5是尾部逗号兼容es5,none就是没有尾部逗号,all是指所有可能的情况,需要node8和es2017以上的环境。(trailingComma: "<es5|none|all>")
  trailingComma: 'es5',
  // 9.object对象里面的key和value值和括号间的空格(bracketSpacing: <bool>)
  bracketSpacing: true,
  // 10.jsx标签多行属性写法时,尖括号是否另起一行(jsxBracketSameLine: <bool>)
  jsxBracketSameLine: false,
  // 11.箭头函数单个参数的情况是否省略括号,默认always是总是带括号(arrowParens: "<always|avoid>")
  arrowParens: 'always',
  // 12.range是format执行的范围,可以选执行一个文件的一部分,默认的设置是整个文件(rangeStart: <int>  rangeEnd: <int>)
  rangeStart: 0,
  rangeEnd: Infinity,
  // 18. vue script和style标签中是否缩进,开启可能会破坏编辑器的代码折叠
  vueIndentScriptAndStyle: false,
  // 19.    endOfLine: "<lf|crlf|cr|auto>" 行尾换行符,分别表示:\n \r \n\r auto ,默认是lf,
  endOfLine: 'lf',
  // 20.embeddedLanguageFormatting: "off",默认是auto,控制被引号包裹的代码是否进行格式化
  embeddedLanguageFormatting: 'off',
}

Husky + Lint-staged

Husky是为git添加hook的工具,安装后,它会在仓库的.git目录下增加相应的钩子,比如pre-commit会在git commit的时候触发。可以在pre-commit的时候执行代码格式化、单元测试等操作。 Lint-staged是过滤git暂存区文件的工具,如果要在提交代码前对全部代码做格式检查和格式化,耗时太长,使用这个工具,可以只对有变动的代码进行操作。

1. 依赖安装
npm install mrm --save-dev --registry=https://registry.npm.taobao.org

// mrm 安装 lint-staged 会自动把 husky一起下载下来
npx mrm lint-staged

安装完以后可以看到package.json的scripts中多了prepare的一个脚本,执行npm run prepare,会自动初始化husky,且默认配置使用lint-staged。

2. 配置Lint-staged

在package.json中配置lint-staged,推荐配置如下

"lint-staged": {
  "*.{js,jsx,ts,tsx}": [
    "eslint --fix",
    "prettier --write"
  ],
  "{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
    "prettier --write--parser json"
  ],
  "package.json": [
    "prettier --write"
  ],
  "*.vue": [
    "eslint --fix",
    "prettier --write",
    "stylelint --fix"
  ],
  "*.{scss,less,styl,html}": [
    "stylelint --fix",
    "prettier --write"
  ],
  "*.md": [
    "prettier --write"
  ]
}