前端代码规范由约定和约束两部分,约束部分通过ESLint实现,约定部分需要主动遵循。
代码约束
通过ESLint从两个方面对代码进行约束:
- 代码风格:比如使用空格还是使用Tab,每行代码的最大长度等代码格式。
- 代码质量:对容易导致bug、可能导致潜在问题的写法约束,比如不能使用
var、判断条件不能为常量等。
ESLint
ESLint是用于检测代码是否符合用户定制规则的工具,通过VSCode ESLint插件实现自动检测代码并自动修复。
- 下载ESLint:
yarn add eslint --dev; - 配置ESLint: 在项目根目录新建
.eslintrc文件并写好配置,配置信息示例:
{
env: {
browser: true,
es6: true,
},
rules: {
semi: ["error", "never"],
quotes: ["error", "double"],
},
}
- 安装ESLint插件;
- 当保存文件时开启自动修复功能,打开VSCode设置,修改设置:
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
通过上面四步,开发中有不符合规范的代码,VSCode会自动报错,且有些代码可以自动修复。
代码风格Prettier
我们采用Prettier作为代码风格规范。Prettier是一款代码格式化工具,它可以解析你的代码并输出为符合一定代码风格规范的代码。使用它团队成员无需再讨论代码格式问题了。我们在ESLint中继承Prettier规则:
- 安装依赖:
yarn add prettier --exact --dev,yarn add --dev eslint-config-prettier eslint-plugin-prettier。注意prettier不同版本规则不同,所以要指定具体版本。 - ESLint配置中继承规则,注意prettier配置要放在最后,否则可能引起prettier规则和其它规则冲突。配置如下:
{
"extends": ["plugin:prettier/recommended"]
}
通过以上两步我们就在ESLint中集成了Prettier,保证了代码风格的统一。
代码质量规范
npm包eslint-config-react-app包含了很多ESLint配置规则:
- es6相关的规则;
- typescript相关的规则;
- react相关的规则。
我们项目是基于Create React App创建的TypeScript项目,默认包含了该规则。如果项目不是基于Create React App创建,需要安装相关依赖包,并继承配置。通过继承eslint-config-react-app我们实现了对代码质量的约束。
pre-commit拦截
通过ESLint和prettier、react-app两个配置文件,我们实现了代码规范的约束。但是如果没有安装VSCode插件ESLint,那么约束是失效的,不合乎代码规范的代码有可能进入代码库。我们通过 git pre-commit钩子在代码提交前执行eslint命令,那么不合乎代码规范的代码就会报错、commit失败,从而保证入库的代码都是合乎代码规范的。
husky是触发git 钩子的包,通过它我们可以在配置文件package.json中配置要执行的命令。lint-staged是对暂存区的文件执行任意的命令。安装包: yarn add husky lint-staged --dev,package.json配置:
{
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,jsx,ts,tsx}": [
"eslint --max-warnings 0"
]
}
}
通过上面配置当提交代码时会触发pre-commit命令,然后执行lint-staged命令,最后对暂存区的文件执行eslint命令。
代码约定
代码约定中主要是关于开发中积累的一些最佳实践、不能使用ESLint的规则等。
- 异步方案
推荐写法
async function fn() {
await promise...
}
不推荐写法
async function fn() {
Promise.then((resolve, reject) => {
...
}).then((resolve, reject) => {
...
});
}
- 使用枚举
代码中使用两次以上的字面量,要定义为枚举变量
- hoc
class 组件使用装饰器模式;Function 组件如果有两层以上 hoc,要使用 compose 组织。
export default compose<React.ComponentClass<IProps, any>>(
create(),
translate()
)(AppListHead);
- 禁用 componentWillReceiveProps, UNSAFE_componentWillReceiveProps()
componentWillReceiveProps 易引发 bug,增加代码复杂度,react 17 中将会被移除。以下替代方案使组件可预测、可维护:
- props 改变时,执行副作用(数据提取),使用 componentDidUpdate
- props 改变时,重新计算某些数据,使用 memoize
- props 改变时,重置 state,使组件完全受控或使用 key 使组件完全不受控
- props 传递明确
传递给组件的 props 不要冗余,只传递必要的 props;不可把父组件实例传递给子组件。
//不推荐写法
<SubComponent {...this.props} parent={this}/>
- 避免数据突变
直接修改 redux 中的数据,容易导致不易察觉的 bug。对于复杂数据,推荐使用immer。
- 单个 JS 文件不超过 800 行
超过 800 行,要考虑组件拆分。
参考
- eslint https://eslint.org/
- prettier https://prettier.io/
- lint-staged https://github.com/okonet/lint-staged