React编码规范及持续集成实践(EditorConfig+ESLint+Jenkins)

工具

  • EditorConfig
  • ESLint
  • Jenkins

EditorConfig

在编辑时约束代码风格,在IDE中如:WebStorm格式化时(command+shift+f)将按照配置中的规则进行格式化。官方文档:https://editorconfig.org/,一份规则示例:

# top-most EditorConfig file
root = true
[*]
Unix-style newlines with a newline ending every file
end_of_line = lf
[*.{js,py}]
# 字符编码集
charset = utf-8
# 缩进使用 tab 或者 space
indent_style = space
# 缩进为space时缩进字符数
indent_size = 2
# 是否将尾行空格自动删除
trim_trailing_whitespace = true
# 是否使文件以一个空白行结尾
insert_final_newline = true
# 编码区字符数(宽度)限定 结合eslint max-len WebStorm支持 VSCode不支持
max_line_length = 100
# 引号样式 single double auto
quote_type = single
# 花括号是否另起一行
#curly_bracket_next_line = true
# 操作符两边是否有空格 true false hybrid
spaces_around_operators = true
# 括号两边是否有空格 none inside outside both
#spaces_around_brackets = both

WebStorm默认支持EditorConfig,其它IDE可能需要下载插件支持,WebStorm下导出.editorconfig,Perferences->CodeStyle->EditorConfig如下:


editorconfig.png

ESLint

插件化的javascript代码检测工具。官方文档:https://cn.eslint.org/

安装ESLint

npm install -g eslint

初始化

eslint -- init
这里我们选择问答方式生成初始化的eslint配置文件

image.png

选择完成后ESLint会根据选择的配置下载相关的插件,如我们选择使用了React
package.json中就有eslint-plugin-react包,相关依赖下载完成后在项目根目录下会生成.eslintrc.json(或.eslintrc.js根据你选择的配置)文件
image.png

  • .eslintrc.json文件
{
    "env": {
        "node": true,
        "browser": true,
        "es6": true
    },
    "parser": "babel-eslint",
    "plugins": [
        "react"
    ],
    "extends": "standard",
    "rules": {
      "react/jsx-uses-vars": 2,
      "camelcase":0
    }
}

文档配置详情说明 https://cn.eslint.org/docs/user-guide/configuring

  • parser
"parser": "babel-eslint"

解析器可能的配置有Esprima Babel-ESLint typescript-eslint-parser

  • extends
"extends": "standard"

extends决定了ESLint使用何种配置插件进行代码检查,如:

"extends": [
        "eslint:recommended",
        "plugin:react/recommended"
    ],
"plugins": [
        "react"
    ]

就是启用ESLint推荐规则和React推荐规则,插件eslint-plugin-react及其规则说明,extends其它值可以有:airbnb,eslint:recommended,eslint:all

"extends": "airbnb", // airbnb eslint:recommended standard  eslint:all
npm -i eslint-config-airbnb --save-dev

同时会下载相关依赖插件eslint-plugin-import, eslint-plugin-jsx-a11y,eslint-plugin-react,启用对React和jsx的一些规则检查
插件eslint-plugin-import及其规则说明
插件eslint-plugin-react及其规则说明
插件eslint-plugin-jsx-a11y及其规则说明

  • rules
    ESLint 附带有大量的规则。你可以使用注释或配置文件修改你项目中要使用的规则。要改变一个规则设置,你必须将规则 ID 设置为下列值之一:
    "off" 或 0 - 关闭规则
    "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
    "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
    如下一个简单示例:
"rules": {
      "quotes": [
            "error",
            "single"
        ], //强制单引号
      "camelcase":2 //强制驼峰
    }

命令行执行检查扫描

由于ESLint我是本地安装的(--save-dev)需要切换到node_modules目录下执行,目录结构(React-Native项目)

image.png

node_modules/.bin/eslint src index.js

扫描src目录以及根目录下的index.js文件,扫描结算后我们在命令行会看到如下结果:

image.png

Jenkins

在命令行中生成的结果,不方便定位与查看,这里通过Jekins做持续集成对项目进行规范化管理。

  • package.json
    编辑package.json增加lint命令支持
"scripts": {
    "lint": "node_modules/.bin/eslint --ext .js src index.js -c .eslintrc.json -f checkstyle > eslint.xml",
    "start": "node node_modules/react-native/local-cli/cli.js start"
  }

--ext .js src index.js 表示扫描/src目录下扩展名为.js的文件 以及根目录下的index.js文件
-c .eslintrc.json 表示选择根目录下的.eslintrc.json文件作为扫描的配置文件
-f checkstyle >eslint.xml将扫描结果以checkstyle方式输出报告,输出到根目录下的eslint.xml
eslint命令详情-官方文档

  • 配置工程与选择分支


    image.png
  • 配置submodule
    由于node_modules以sub-modules添加到了工程源码库管理,需要拉取子module


    image.png
  • 添加构建脚本


    image.png

    切换到library(node_modules)目录拉取目标分支最新代码,再切换回根目录执行lint命令。

  • 添加构建后步骤
    将构建结果以Checkstyle results的形式输出,选择CheckStyle需要Jenkins插件支持。


    image.png
  • 查看结果
    image.png

    查看整个项目的扫描结果,根据需要浏览具体代码,选择或者禁用某些规则,然后重新编辑.eslintrc.json文件生成一份适用于自己团队的规则文件。

eslint配置示例(基于airbnb规范)

  • array-bracket-spacing 强制数组方括号中使用一致的空格 2
  • array-callback-return 强制数组方法的回调函数中有 return 语句 0
  • arrow-body-style 要求箭头函数体使用大括号 1
  • arrow-parens 要求箭头函数的参数使用圆括号 0
  • brace-style 强制在代码块中使用一致的大括号风格 2
  • camelcase 强制使用骆驼拼写法命名约定 2
  • class-methods-use-this 强制类方法使用 this 1
  • comma-dangle 要求或禁止末尾逗号
"comma-dangle": [1, {
            "objects": "always",
            "imports": "never",
            "arrays": "never",
            "exports": "never",
            "functions": "never"
    }]
  • consistent-return要求 return 语句要么总是指定返回的值,要么不指定 2
  • default-case要求 switch 语句中有 default 分支 0
  • dot-notation 强制尽可能地使用点号 2
  • eol-last 要求或禁止文件末尾存在空行 2
  • eqeqeq 要求使用 === 和 !== 2
  • func-names 要求或禁止使用命名的 function 表达式 2
  • function-paren-newline 强制在函数括号内使用一致的换行 2
  • global-require 要求 require() 出现在顶层模块作用域中 0
  • guard-for-in 要求 for-in 循环中有一个 if 语句 1
  • import/first 将全部import写在模块开始的位置 0
  • import/newline-after-import improt结束后应有空行 2
  • import/no-duplicates 禁止重复导入相同文件 2
  • import/no-extraneous-dependencies 禁止导入未在包中声明的外部模块 2
  • import/no-mutable-exports 可导出对象禁止用let或者var修饰 ->const 2
  • import/no-unresolved 确保导入的模块可以被解析为本地文件系统上的模块 0
  • import/prefer-default-export 当从模块中只导出单个出口时使用默认导出 1
  • indent 缩进风格
"indent": [
            "error",
            2,
            {"SwitchCase": 1} // set 1 -> 2 spaces; set 2 -> 4 spaces
    ]
  • jsx-quotes 强制在 JSX 属性中一致地使用双引号或单引号 2 prefer-single
  • linebreak-style 强制使用一致的换行风格 2 lf
"linebreak-style": [
            "error",
            "unix"
    ]
  • max-len 强制一行的最大长度 100 1
"max-len": [
            "warn",
            100
    ]
  • newline-per-chained-call 要求方法链中每个调用都有一个换行符 2
  • no-bitwise 禁用按位运算符 1
  • no-case-declarations 不允许在 case 子句中使用词法声明 2
  • no-confusing-arrow 禁止在可能与比较操作符相混淆的地方使用箭头函数 2
  • no-continue 禁用 continue 语句 1
  • no-else-return 禁止 if 语句中 return 语句之后有 else 块 2
  • no-empty 禁止出现空语句块 2
  • no-extend-native 禁止扩展原生类型 2 exceptions Date
"no-extend-native": [
            "error",
            {"exceptions": ["Date"]}
    ]
  • no-extra-semi 禁止不必要的分号 2
  • no-lonely-if 禁止 if 作为唯一的语句出现在 else 语句中 2
  • no-loop-func 禁止在循环中出现 function 声明和表达式 1
  • no-mixed-operators 禁止混合使用不同的操作符 0
  • no-mixed-spaces-and-tabs 禁止空格和 tab 的混合缩进 2
  • no-multi-assign 禁止连续赋值 2
  • no-nested-ternary 禁用嵌套的三元表达式 2
  • no-param-reassign 禁止对 function 的参数进行重新赋值 2
  • no-plusplus 禁用一元操作符 ++ 和 -- 0
  • no-prototype-builtins 禁止直接调用 Object.prototypes 的内置属性 2
  • no-restricted-globals 禁用特定的全局变量 2
  • no-restricted-properties 禁止使用对象的某些属性 1
  • no-restricted-syntax 禁用特定的语法 使用for-each map for-i 2
  • no-shadow 禁止变量声明与外层作用域的变量同名 2
  • no-tabs 禁用 tab 2
  • no-trailing-spaces 禁用行尾空格 2
  • no-undef 禁用未声明的变量,除非它们在 /*global */ 注释中被提到 2
  • no-underscore-dangle 禁止标识符中有悬空下划线 0
  • no-unreachable 禁止在return、throw、continue 和 break 语句之后出现不可达代码 2
  • no-unused-expressions 禁止出现未使用过的表达式 2 allowShortCircuit true
"no-unused-expressions": ["error", {"allowShortCircuit": true}]
  • no-unused-vars 禁止出现未使用过的变量 2
  • no-use-before-define 禁止在变量定义之前使用它们 2
  • no-useless-concat 禁止不必要的字符串字面量或模板字面量的连接 0
  • no-useless-constructor 禁用不必要的构造函数 2
  • no-useless-escape 禁用不必要的转义字符 0
  • no-var 要求使用 let 或 const 而不是 var 2
  • object-curly-newline 强制大括号内换行符的一致性 2
  • object-curly-spacing 强制在大括号中使用一致的空格 2
  • object-shorthand 要求或禁止对象字面量中方法和属性使用简写语法 2
  • one-var 强制函数中的变量要么一起声明要么分开声明 0
  • one-var-declaration-per-line 要求或禁止在变量声明周围换行 0
  • operator-assignment 要求或禁止在可能的情况下使用简化的赋值操作符 1
  • padded-blocks 要求或禁止块内填充 2 class always
"padded-blocks": [
            "error", {"classes": "always"}
    ]
  • prefer-arrow-callback 要求回调函数使用箭头函数 2
  • prefer-const 要求使用 const 声明那些声明后不再被修改的变量 2
  • prefer-destructuring 优先使用数组和对象解构 2 object
"prefer-destructuring": [
            "error", {"array": false, "object": true}
    ]
  • prefer-rest-params 要求使用剩余参数而不是 arguments 2
  • prefer-spread 要求使用扩展运算符而非 .apply() 2
  • prefer-template 要求使用模板字面量而非字符串连接 2
  • quote-props 要求对象字面量属性名称用引号括起来 2
  • quotes 强制使用一致的反勾号、双引号或单引号 2
"quotes": [
            "error",
            "single"
    ]
  • radix 强制在parseInt()使用基数参数 0
  • react/forbid-prop-types 禁止某些propTypes 1
  • react/jsx-boolean-value 在JSX中强制布尔属性符号 2
  • react/jsx-closing-bracket-location 在JSX中验证右括号位置 1
  • react/jsx-closing-tag-location 在JSX中验证右标签位置 2
  • react/jsx-curly-brace-presence 在JSX中启用或者禁用不必要的大括号 props always children never
"react/jsx-curly-brace-presence": [
            "error",
            {"props": "always", "children": "never"}
    ]
  • react/jsx-curly-spacing 在JSX属性和表达式中加强或禁止大括号内的空格 禁止 2
  • react/jsx-equals-spacing 在JSX属性中强制或禁止等号周围的空格 禁止 2
  • react/jsx-filename-extension 限制包含JSX的文件扩展名 0
  • react/jsx-first-prop-new-line 属性强制换行 2
  • react/jsx-indent jsx中缩进检查 2
  • react/jsx-indent-props jsx中属性缩进检查 2
  • react/jsx-max-props-per-line 限制JSX中单行上的props的最大数量 2
  • react/jsx-no-bind JSX中不允许使用箭头函数和bind 2
  • react/jsx-no-duplicate-props 防止在JSX中重复的props 2
  • react/jsx-tag-spacing JSX中开起标签开始和结束空格检查 2
  • react/jsx-wrap-multilines 多行JSX中避免丢失括号 2
  • react/no-array-index-key 防止在数组中遍历中使用数组key做索引 2
  • react/no-did-mount-set-state 防止在componentDidMount中使用setState 2
  • react/no-multi-comp 防止每个文件有多个组件定义 2
  • react/no-unescaped-entities 防止无效字符出现在标记中 1
  • react/no-unused-prop-types 避免定义未使用的PropType, defined but never used 1
  • react/no-unused-state 避免定义未使用的state 2
  • react/prefer-stateless-function 无状态管理(stateless)的React组件应该继承PureComponent 1
  • react/prop-types 防止在React组件定义中丢失props验证(类型验证) 1
  • react/require-default-props 非require的props需在defaultProps中申明 1
  • react/self-closing-comp 防止没有children的组件的额外结束标签<Text></Text> 2
  • react/sort-comp强制组件方法顺序2

    ① static methods and proper

    ② lifecycle methods

    ③ custom methods

    ④ render method
  • semi 要求或禁止使用分号 2 禁止分号
"semi": [
            "error", "never"
    ]
  • space-before-function-paren 强制在 function的左括号之前使用一致的空格 2
  • spaced-comment 强制在注释中 // 或 /\ 使用一致的空格 2
  • switch-colon-spacing 强制在 switch 的冒号左右有空格 2
  • vars-on-top 要求所有的 var 声明出现在它们所在的作用域顶部 2
  • no-console: 禁止使用console 0
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容

  • 什么是 ESLint ESLint(中文站点)是一个开源的 JavaScript 代码检查工具,使用 Node.j...
    小肆逸阅读 1,496评论 0 3
  • ESLint规范说明1、工具简介ESLint是一个QA工具,用来避免低级错误和统一代码的风格。ESLint被设计为...
    小漠穷秋阅读 2,922评论 0 0
  • 前提:如果没有安装package control,可以参考sublime插件推荐以下按照顺序安装: 安装Subli...
    real勾玉阅读 1,669评论 1 2
  • ESLint 配置 ESlint 被设计为完全可配置的,这意味着你可以关闭每一个规则而只运行基本语法验证,或混合和...
    静默虚空阅读 41,281评论 3 14
  • 自从1月份开始订阅李笑来《通往财富自由之路》的专栏,便按照专栏的节奏,每日一字不差的阅读,每日结合自身进行留言,每...
    眼睛歪了阅读 240评论 1 1