接手的业务和团队走过了一段适应期,想要对团队的代码风格开始进行规范,在渐进落地后整理出一套比较通用的方案。
这里主要描述结论,选型和团队中方案PK的流程暂且先跳过,后面单独起一个专题讨论。
我的团队技术栈主要是React+TS,比较有针对性,因此请选择性食用。
下面的规范主要分美化和lint两个部分,且只讨论自动的部分,不讨论风格指南相关,那我们直接开始。
Lint
什么是Lint?
什么是Lint?
In computer programming, lint is a Unix utility that flags some suspicious and non-portable constructs (likely to be bugs) in C language source code; generically, lint or a linter is any tool that flags suspicious usage in software written in any computer language. The term lint-like behavior is sometimes applied to the process of flagging suspicious language usage. Lint-like tools generally perform static analysis of source code.
ESLint
lint的核心毫无疑问是eslint,但是eslint中用哪些plugin就比较有讲究了。
必须:
- eslint-plugin-react-hooks
- React官方提供的专门针对hooks的plugin:https://zh-hans.reactjs.org/docs/hooks-rules.html
- eslint-plugin-prettier、eslint-config-prettier
- 因为要求了美化的部分所以prettier部分的plugin在我的团队中是必装的
- eslint-config-prettier是eslint-plugin-prettier的辅助插件,用来禁用eslint本身的格式化规则的
- https://github.com/prettier/eslint-plugin-prettier
- eslint-plugin-import
- ES6+导入导出语法的lint不赘述:https://github.com/import-js/eslint-plugin-import
- eslint-plugin-react
可选:
- jsx-a11y:https://github.com/jsx-eslint/eslint-plugin-jsx-a11y
- 该plugin按说对开发功能没有很直接的印象,但是为了体验和jsx的书写遍历,还是建议进行安装
- eslint-config-standard:https://github.com/standard/eslint-config-standard
- eslint-plugin-node:https://github.com/mysticatea/eslint-plugin-node
- eslint-plugin-promise:https://github.com/eslint-community/eslint-plugin-promise
StyleLint
css出现bug的几率比较小,不太容易引起人们的重视,但其实css亦是组件质量的重要部分,在很多场景仍然要消耗大量的开发成本,因此有个好的写css习惯是非常重要的。
我们的项目中并没有严格采用BEM(窟窿比较多,这个优先级很低),因此为了让有好习惯的同学看其他人的代码不会太痛苦,就采用了StyleLint,StyleLint也是前端项目必备的Lint。
这里不需要太多的配置,在我们的项目中仅使用了stylelint-config-idiomatic-order插件来控制大家代码的css样式顺序。
美化
Prettier
团队中对使不使用Prettier有一些争议,不建议使用的主要观点是认为eslint可以cover这一块了,那针对这个疑问和一些其他疑问下面给了一些思考和解答:
- 主要处理代码风格,why coding style matters
- 在线查看格式和配置的工具:https://prettier.io/playground/
- 为什么要使用Prettier https://prettier.io/docs/en/why-prettier.html 核心原因主要是两点:
- 全自动的风格格式化
- 开发人员无需再为代码风格讨论(除非很闲)
- Prettier给出的配置比较少,默认的配置:
module.exports = { // 行宽,即一行内容超过配置的数字会触发换行行为 printWidth: 80, // 缩进数 tabWidth: 2, // 缩进是否用tab,如果不是则用空格 useTabs: false, // 行尾是否有分号 semi: true, // 是否要使用单引号 singleQuote: false, /** * 对象中的Key展示引号的规则 * as-needed: 仅在必要时展示 * consistent: 如果对象中有属性需要引号,那么就都要使用 * preserve: 使用你本来的输入 */ quoteProps: 'as-needed', // jsx 是否使用单引号 jsxSingleQuote: false, /** * 末尾逗号 * es5: 在es5中的数组和对象增加尾随逗号,TS中的类型参数不会追加 * none: 没有尾随逗号 * all: 尽可能使用尾随逗号 */ trailingComma: 'es5', // 大括号内的首尾需要空格 bracketSpacing: true, // 标签的尖括号是否要跟随到最后一行的末尾,而不是单独一行(不包括自闭合) bracketSameLine: false, /** * 箭头函数参数周围的括号 * always: 始终需要括号 * avoid: 尽可能省略括号 */ arrowParens: 'always', // 每个文件格式化的范围是文件的全部内容 rangeStart: 0, rangeEnd: Infinity, // 是否需要在文件开头写 @prettier requirePragma: false, // 是否在文件开头插入 @prettier insertPragma: false, /** * 折行方式 * always: 超过print width则换行 * never: 每个文本块为一行 * preserve: 保持输入的原样 */ proseWrap: 'preserve', /** * HTML的空白换行敏感度 * css: 根据css的标准进行换行 * strict: 所有标签周围的空格都会造成换行 * ignore: 所有标签周围的空格都忽略 */ htmlWhitespaceSensitivity: 'css', /** * 换行符 * lf: \n mac or linux or git repos * crlf: \r\n windows * cr: \r 不太常用 * auto: 保持现有的换行 */ endOfLine: 'lf', // 是否强制每行单个属性 singleAttributePerLine: false };
- 和其他lint配合使用,值得一提的是,配合使用的方式就是将prettier的配置整合到对应lint中,也就是说不使用prettier也将是一种可能。
工作流相关工具
除了增加lint和美化的配置来让辅助让代码符合规范,为了让代码更确切的能达到规范的目的,我们还希望可以在提交代码的时候进行一次自动验证并进行fix,因此还需要一些其他的工具。
Lint-staged
在代码提交前进行lint,以此来强制仓库的代码格式,这个lint是对当前提交增量的文件进行lint的,官网:https://github.com/okonet/lint-staged
// package.json { // ... other config "lint-staged": { "**/*": "prettier --write --ignore-unknown", //格式化 "src/**.{js,jsx,ts,tsx}": "eslint --ext .js,.jsx,.ts,.tsx", //对js文件检测 "**/*.{less,css}": "stylelint --fix" //对css文件进行检测 } }
Husky
在git执行的生命周期钩子中追加能力,官网:https://typicode.github.io/husky/#/
- 使用
postinstall
进行了husky的预安装 postinstall
是npm生命周期的一环:https://docs.npmjs.com/cli/v8/using-npm/scripts#life-cycle-operation-order- 为什么v8版本不再支持配置而只支持脚本
- https://blog.typicode.com/husky-git-hooks-javascript-config/
- https://blog.typicode.com/husky-git-hooks-autoinstall/
- 整体来看是因为作者想让husky控制最小粒度的git hooks
- 因为机器使用的命令行不同导致无法运行对应的脚本
- 对应文档:https://typicode.github.io/husky/#/?id=command-not-found
- 从文档来看这个问题可以根据用户的路径信息进行一个钩子处理掉,但是整个行为不是自动的,所以要再考虑下
- 用npm似乎会尽可能避免该问题
- 这也可能跟命令行文件的安装方式有关(待验证)
- 在脚本中加入获取path的能力可以快速知道问题在哪
#!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" echo $PATH npm run test
- 命令输出后 会展示当前的环境变量,如果命令找不到说明命令不在环境变量中
CommitLint
对提交的commit的message进行lint,官网:https://commitlint.js.org/#/
如果自己不会写,或者想增加更规范化的提交消息,可以再增加个Commitizen
- config-conventional提供的默认规则
- https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional
其他工具
koroFileHeader
https://github.com/OBKoro1/koro1FileHeader.git
这是一个中国开发者制作的VSCode的插件,用来自动往文件头部写文件被操作的信息的,非常实用。
支持很多自定义配置,我现在使用这个工具主要记录文件创建者+创建时间+文件最后修改者+修改时间信息。