建立团队代码规范的意义
- 增强团队协作效率 :每个工程师都有自己主观的编程风格,但作为一个团队,必须在可读性上找到最大公约数
- 提高代码质量 :优秀的编码习惯,应该沉淀下来成为一个团队的规范,而不是工程师个人的选择
- 减缓系统腐化速度 :一个工程总会腐化,但在保持可读性和代码质量的情况下,我们可以减慢它的速度
建立代码规范的原则
- 代码规范是一个找“公约数”的过程,需要听取团队中每一位成员的意见,除了会引起质量问题的编码习惯,其他意见都值得被尊重
- 代码规范是为了帮助人与人之间的协作,可读性应该是第一目标
- 代码规范不应成为工程师工作之外的负担,建立规范的过程可以求同存异、小步快跑
现有社区方案
Google HTML / CSS /JS规范
著名的谷歌前端规范,大而全
Airbnb Style 规范(包括CSS和Sass )
Airbnb的样式规范,不仅包含CSS规范,亦包含Sass的规范
Airbnb JavaScript 规范
Airbnb的JavaScript编码规范
JavaScript Standard Style
Standard规范,影响力最大的JS编码规范,生态丰富,提供了开箱即用的各种lint规则和编辑器插件
Vue Style Guide
VueJS官方推荐的编码规范
Airbnb React/JSX Style Guide
Airbnb JavaScript规范的React/JSX部分
建立自定义代码规范- ESLint
ESLint是一款高度可配置的JavaScript 静态代码检查工具,已成为JS代码检查的实施标准
特性
- 完全的可插拔
- 一切行为都通过配置产生任意rule之间都是独立的
原理
先通过解析器(parser) 将JavaScript代码解析为抽象语法树(AST),再调用规则(rule)对AST进行检查,从而实现对代码的检查
AST浅析
AST是一种可遍历的、描述代码的树状结构,利用AST可以方便地分析代码的结构和内容。对AST语法树结果感兴趣的可以参考:AST Explore
ESLint的配置
配置文件格式
JavaScript,JSON 或者YAML,也可以在packagejson中的eslintConfig字段。我们以JSON为例
ESLint配置的主要内容
1.Parser:ESLint使用哪种解析器
2.Environments:选择你的代码跑在什么环境中(browser/node/commonjs/es6/es2017/worker)
3.Globals:除了Env之外,其他需要额外指定的全局变量
4.Rules:规则
5.Plugins:一组以上配置项以及processor的集合,往往用于特定类型文件的代码检查,如.md文件
6.Extends:你想继承的配置
parser的配置
parser:指定ESLint使用哪种解析器: Espree(默认)、Esprima、Babel-ESLint@typescript-eslint/parser。一般不需指定
parserOptions:配置parser的参数,parser会接受这些参数,并影响其解析代码的行为
{
//...
"parser":"esprima",
"parserOptions": {
"ecmaVersion":6,
"sourceType":"module" ,
"ecmaFeatures":{
"jsx": true
}
},
//...
}
Evironments、Globals的配置
Environments预置环境:
browser/node/commonjs/shared-node-browser/es6/es2017/es2020/ worker /amd/ mocha /jasmine /jest/ phantomjs /protractor/ qunitjquery / prototypejs/ shelljs / meteor/ mongo /applescript / nashornserviceworker /atomtest / embertest / webextensions / greasemonkey
globals:
globals是env之外需要额外指定的全局变量。有三种配置值:
- writeable-可写
- readonly-只读
- off-不支持
{
//...
"env":{
"browser": true,
"node": true
},
"alobals":{
"varl":"writable",
"var2":"readonly",
"var3":"off"
}
//...
}
配置Rules
ESLint无默认开启的规则。但提供了推荐开启的规则:“extends”:“eslint:recommended”。可在这里查看所有内置规则的列表:ESLint Rules List
规则类型
- "off"或0-关闭规则
- "warn"或1-将规则视为一个警告
- "error"或2-将规则视为一个错误
配置形式
- 值:数字或字符串,表示错误级别
- 数组:第一项是错误级别,之后的各项是对该规则的额外的配置
{
//...
"rules":{
//允许非全等号
"egeqeq":"off",
//尽可能使用花括号
"curly": "error",
//双引号
"quotes":["error","double"],
//除了warn和error之外,对console.*方法发出警告
"no-console": ["warn", [ allow: ["warn","error"] }],
//必须写分号除了lastInonelineBlock
"semi": [2, 'always', ["omitLastInOneLineBlock": true}],
//plugin1中的规则飞是网首规则
"pluginl/rulel": "error"
},
//...
}
Plugins
ESLint 的插件是对一系列rules、environments、globals、processors等配置的封装。以eslint-plugin-vue为例:
- 可以单独引用规则
- 可以直接使用 (继承) eslint-plugin-vue配置好的config
- 预处理器的作用:解析.vue文件
module.exports = {
"rules": {
'array-bracket-spacing': require('./rules/array-bracket-spacing'),
'arrow-spacing': require('./rules/arrow-spacing'),
'attribute-hyphenation': require('./rules/attribute-hyphenation'),
//...
},
'configs': {
'base' : require('./configs/base'),
'essential': require('./configs/essential' ),
'recommended': require('./configs/recommended' ),
'vue3-recommended': require('./configs/vue3-recommended'),
//...
},
'processors': {
'.vue' : require('./processor')
}
}
Extends
Extends是一种非常灵活的ESLint配置机制,使用Extends,可以依次递归地应用每一个eslint配置文件,实现灵活的组合
- 可以用extends来全家桶式地使用第三方配置好的规则
- extends可以嵌套
- 使用extends之后,我们的rules可以:覆盖重写第三方规则、只改变第三方规则的错误等级、添加新的规则
{
//继承单个配置
"extends":"eslint:recommended",
// 继承多个配置,后面的可能覆盖前面的
"extends": "eslint:recommended","plugin:react/recommended"],
// 可以直接写配置文件的路径
"extends" :[
"./node modules/coding-standard/eslintDefaults.js",
"./node_modules/coding-standard/.eslintrc-es6",
"./node_modules/coding-standard/.eslintrc-jsx"
]
}
自定义rule
- meta部分主要包括规则的描述、类别、文档地址、修复有式以及配置下schema等信息
- create则需要定义一个函数用于返回一个包含了遍历规则的对象,并且该函数会接收context对象作为参数
示例:编写no-caller rule,禁止arguments.caller和arguments.callee的使用
module.exports = {
meta:{
type: "suggestion",
docs: {
description: "disallow the use of arguments.caller or arguments .callee"
category:"Best Practices",
recommended: false,
url:"https://eslint.org/docs/rules/no-caller"
}
schema: [],
messages: {
unexpected: "Avoid arguments .{{prop}}."
}
},
create(context) {
return {
MemberExpression( node ) {
const objectName = node.object.namepropertyName = node.property.name ;
if (objectName === "arguments" &&
!node.computed && propertyName &&
propertyName.match(/^calle[er]$/u)
){
context.report({
node,
messageId:"unexpected",
data: { prop: propertyName }
})
}
}
}
}
stylelint
Stylelint是目前生态最丰富的样式代码检查方案,主要有如下特点:
- 社区活跃,生态丰富
- 插件化,功能强大
- 不仅支持CSS,还支持SCSS、Sass 和 Less 等预处理器
- 已在Facebook、GitHub 和 WordPress等大厂得到广泛应用
//.stylelintrc.js
module.exports = {
extends:"stylelint-config-recommended",
rules: {
"at-rule-empty-line-before": [
"always",
{
except: ["blockless-after-same-name-blockless","first-nested"],
ignore: ["after-comment"],
},
]
"color-hex-case":"lower",
"color-hex-length":"short",
"comment-empty-ine-before": [
"always"
{
except: ["first-nested"],
ignore: ["stylelint-commands"],
}
]
"value-keyword-case":"ower",
"value-list-comma-space-before":"never",
"value-list-max-empty-lines": 0,
}
}
Prettier
Prettier是一个流行的代码格式化的工具
Prettier只关注格式优化,且不会以报错的形式告知格式问题,而是允许开发者按自己的方式编写代码但是会在特定时机(save,commit) ,将代码格式化为可读性最好的形式
Prettier出现的意义:
- Prettier称,自己最大的作用是:可以让大家停止对“代码格式”的无意义的辩论。
- Prettier在一众工程化工具中非常特殊,它毫不掩饰地称自己是“有主见的”,且严格控制配置项的数量,它对默认格式的选择,完全遵循 [让可读性最高] 这一标准。
- Prettier认为,在代码格式化方面牺牲一些灵活性,可以为开发者带来更多的收益。不得不承认,Prettier是对的。
Prettier配置
前面我们已经说过,Prettier的配置非常克制,主要有以下配置项:
//prettierrc
{
"parser":"babylon", // 使用的parser
"printWidth": 80, // 换行字符串闻值
"tabwidth": 2, // 缩进空格数
"useTabs": false , // 使用空格缩进
"semi": true, //句未加分号
"singleQuote": false, // 用双引号
"trailingComma": "none", //最后一个对象元素加逗号
"bracketSpacing": true, // 对象,数组加空格
"jsxBracketSameLine": false, // jsx > 是否另起一行
"arrowParens":"avoid" // (x) =>]是否要有小括号
"requirePragma" : false, //是否要注释来决定是否格式化代码
"insertPragma": false , //是否为已经格式化的代码加注释标记
"prosewrap": "preserve" //是否要换行
}
Prettier的使用
有很多种方式去触发Prettier的格式化行为: CLI、Watch Changes、git hook、与Linter集成
Watch Changes
//package.json
{
"scripts":{
"prettier-watch": "onchange '**/x.js' -- prettier --write {{changed}}"
}
}
Prettier与eslint集成
yarn add --dev eslint-config-prettier eslint-plugin-prettier
//eslintrc.json
{
"extends": ["prettier"] ,
"plugins": ["prettier"],
"rules":{
"prettier/prettier": "error"
}
}