本文以 React Native 项目为示例介绍了前端规范化开发涉及的工具及知识,但是所涉及内容具有通用性,建议读者点赞收藏(^▽^)。

另外安利一下 @sigmayun/react-native-template-typescript,这是一个基于 typescript 的 react native 开箱即用的模板。本文所涉及的大部分内容都集成到了该模板中。

gitconfig

1
2
3
4
5
6
7
8
9
# 初始化设置
$ git config --global user.name 'your_name'
$ git config --global user.email 'your_email@aliyun.com'
# 提高命令输出的可读性
$ git config --global color.ui auto
# git 记住用户名和密码
$ git config --global credential.helper store
# core.autocrlf
$ git config --global core.autocrlf input

以上配置内容可以在 ~/.gitconfig 文件中找到。

npm scripts

package.json 文件的 scripts 字段是定义可执行脚本用的,可以利用它来实现简单的工作流。如果不是大型的项目,不建议使用 gulp,npm scripts 一样可以完成工作流设计的任务。下面是 React Native 项目默认的 scripts,如今我们可以把使用和扩展 scripts 看做是前端基本功。

1
2
3
4
5
6
7
8
9
{
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "react-native start",
"test": "jest",
"lint": "eslint ."
}
}

使用 EditorConfig 实现跨编辑器代码风格统一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# EditorConfig is awesome: http://EditorConfig.org

# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

[*.gradle]
indent_size = 4

[BUCK]
indent_size = 4

使用ESLint规范代码

作者自己团队的 ESLint 方案是基于 eslint-config-airbnb 扩展的,有兴趣可以体验一下 @sishuguojixuefu/eslint-config

安装依赖

1
2
3
4
5
6
7
8
9
10
11
# 安装 eslint-config-airbnb 及其 peerDependencies
$ yarn global add install-peerdeps
$ install-peerdeps -D eslint-config-airbnb
# 支持 react-native
$ yarn add -D eslint-plugin-react-native
# 支持 typescript
$ yarn add -D @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-import-resolver-typescript typescript
# 支持 prettier
$ yarn add -D prettier eslint-plugin-prettier eslint-config-prettier
# 其他
$ yarn add -D eslint-plugin-promise eslint-plugin-you-dont-need-lodash-underscore eslint-plugin-you-dont-need-momentjs

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
"eslintConfig": {
"extends": [
"airbnb",
"airbnb/hooks",
"plugin:react-native/all",
"plugin:@typescript-eslint/recommended",
"plugin:promise/recommended",
"plugin:you-dont-need-lodash-underscore/compatible",
"plugin:you-dont-need-momentjs/recommended",
"plugin:prettier/recommended",
"prettier",
"prettier/react",
"prettier/@typescript-eslint"
],
"env": {
"react-native/react-native": true
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
}
},
"settings": {
"import/extensions": [".js", ".ts", ".tsx"],
"import/resolver": {
"typescript": {
"alwaysTryTypes": true
}
}
}
}
}

.prettierrc.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
module.exports = {
printWidth: 150, // 一行的字符数,如果超过会进行换行,默认为80
tabWidth: 2, // tab缩进大小,默认为2
useTabs: false, // 使用tab缩进,默认false
semi: false, // 使用分号, 默认true
/**
* 行尾逗号,默认none,可选 none|es5|all
* es5 包括es5中的数组、对象
* all 包括函数对象等所有可选
*/
trailingComma: 'es5',
singleQuote: true, // 使用单引号, 默认false(在jsx中配置无效, 默认都是双引号)
/**
* 对象中的空格 默认true
* true: { foo: bar }
* false: {foo: bar}
*/
bracketSpacing: true,
/**
* JSX标签闭合位置 默认false
* false:
* <div
* className=""
* style={{}}
* >
* true:
* <div
* className=""
* style={{}} >
*/
jsxBracketSameLine: false,
/**
* 箭头函数参数括号 默认avoid 可选 avoid| always
* avoid 能省略括号的时候就省略 例如x => x
* always 总是有括号
*/
arrowParens: 'avoid',
vueIndentScriptAndStyle: false, // vue 文件 script 和 style 标签缩进,默认false
endOfLine: 'lf', // 强制使用 unix 风格的换行符
}

插件介绍

  • eslint-config-airbnb: 该软件包提供 Airbnb 的 .eslintrc 作为可扩展的共享配置
  • eslint-plugin-react-native: 针对 ESLint 的 React Native 特定 linting 规则
  • @typescript-eslint/parser: 将 TypeScript 转换为 ESTree,使 eslint 可以识别
  • @typescript-eslint/eslint-plugin: 一个包含一堆特定于 TypeScript 的 ESLint 规则的插件
  • eslint-import-resolver-typescript: 给 eslint-plugin-import 添加 typescript 支持的插件
  • eslint-plugin-prettier: 以 ESLint 插件的形式运行 prettier
  • eslint-config-prettier: 关闭所有不必要或可能与 prettier 的规则冲突的 ESLint 规则。一定要放到最后。

vscode eslint plugin config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.lintTask.enable": true,
"eslint.packageManager": "yarn",
"eslint.alwaysShowStatus": true,
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html"
]

用 husky 和 lint-staged 构建超溜的代码检查工作流

1
$ yarn add -D husky
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"husky": {
"hooks": {
"pre-commit": "tsc --noEmit && lint-staged"
}
},
"lint-staged": {
"**/*.{js,jsx,ts,tsx}": [
"eslint --fix",
"git add"
],
"**/*.{md,json}": [
"prettier --write",
"git add"
]
}
}

Conventional Commits 约定式提交规范

Conventional Commits 是一种用于给提交信息增加人机可读含义的规范。约定式提交规范是一种基于消息的轻量级约定。它提供了一组用于创建清晰的提交历史的简单规则;这使得编写基于规范的自动化工具变得更容易。这个约定与 SemVer 相吻合,在提交信息中描述新特性、bug 修复和破坏性变更。

提交说明的结构如下所示:

1
2
3
4
5
<类型>([可选的作用域]): <描述>

[可选的正文]

[可选的脚注]

类型

  • build:: 影响构建系统或外部依赖关系的更改(示例范围:gulp、broccoli、NPM)。
  • chore:: 其他不修改srctest文件。
  • ci:: 更改持续集成文件和脚本(示例范围:Travis、Circle、BrowserStack、SauceLabs)。
  • docs:: 只是更改文档。
  • feat:: 类型为 feat 的提交表示在代码库中新增了一个功能(这和语义化版本中的 MINOR 相对应)。
  • fix::类型为 fix 的 提交表示在代码库中修复了一个 bug (这和语义化版本中的 PATCH 相对应)。
  • improvement:: 用于对当前实现进行改进而没有添加新功能或修复错误的提交。
  • perf:: 改进性能的代码更改。
  • refactor:: 代码重构,既不修复错误也不添加功能。
  • revert:: commit 回退。
  • style:: 不影响代码含义的变化(空白、格式化、缺少分号等)。
  • test:: 添加确实测试或更正现有的测试。

范围

可以为提交类型添加一个围在圆括号内的作用域,以为其提供额外的上下文信息。例如 feat(parser): adds ability to parse arrays.

BREAKING CHANGE

在可选的正文或脚注的起始位置带有 BREAKING CHANGE: 的提交,表示引入了破坏性 API 变更(这和语义化版本中的 MAJOR 相对应)。 破坏性变更可以是任意 类型 提交的一部分。

示例

包含了描述以及正文内有破坏性变更的提交说明

1
2
3
feat: allow provided config object to extend other configs

BREAKING CHANGE: `extends` key in config file is now used for extending other config files

包含了可选的 ! 字符以提醒注意破坏性变更的提交说明

1
2
3
chore!: drop Node 6 from testing matrix

BREAKING CHANGE: dropping Node 6 which hits end of life in April

不包含正文的提交说明

1
docs: correct spelling of CHANGELOG

包含作用域的提交说明

1
feat(lang): add polish language

为 fix 编写的提交说明,包含(可选的) issue 编号

1
2
3
4
5
fix: correct minor typos in code

see the issue for details on the typos fixed

closes issue #12

约定式提交规范

  1. 每个提交都必须使用类型字段前缀,它由一个名词组成,诸如featfix,其后接一个可选的作用域字段,以及一个必要的冒号(英文半角)和空格。
  2. 当一个提交为应用或类库实现了新特性时,必须使用feat类型。
  3. 当一个提交为应用修复 bug 时,必须使用fix类型。
  4. 作用域字段可以跟随在类型字段后面。作用有必须是一个描述某部分代码的名词,并用圆括号包围,例如:fix(parser):
  5. 描述字段必须紧接在类型/作用域前缀的空格之后。描述指的是对代码变更的简短总结,例如:fix:array parsing issue when multiplejspaces were contained in string
  6. 在简短描述之后,可以编写更长的提交正文,为代码变更提供额外的上下文信息。正文必须起始于描述字段结束的一个空行后。
  7. 在正文结束的一个空行之后,可以编写一行或或多行脚注。脚注必须包含关于提交的元信息,例如:关联的合并请求、Reviewer、破坏性变更、每条元信息一行。
  8. 破坏性变更必须标示在正文区域最开始处,或脚注区域中某一行的开始。一个破坏性变更必须包含大写的文本BREAKING CHANGE,后面紧跟冒号和空格。
  9. BREAKING CHANGE:之后必须提供描述,以描述对 API 的变更。例如:BREAKING CHANGE: environment variables now take precedence over config files
  10. 在提交说明中,可以使用featfix之外的类型。
  11. 工具的实现必须不区分大小写地解析构成约定式提交的信息单元,只有BREAKING CHANGE 必须是大写的。
  12. 可以在类型/作用域前缀之后,:之前,附加!字符,以进一步提醒注意破坏性变更。当有!前缀时,正文或脚注内必须包含BREAKING CHANGE: description

为什么使用约定式提交

  • 自动化生产 CHANGELOG。
  • 基于提交的类型,自动决定语义化的版本变更。
  • 向同事、公众与其他利益关系者传达变化的性质。
  • 触发构建和部署流程。
  • 让人们探索一个更加结构化的提交历史,以便降低对你的项目作出贡献的难度。

commitlint

commitlint检查您的提交消息是否符合conventional commit format

1
2
$ yarn add -D @commitlint/cli @commitlint/config-conventional @commitlint/prompt-cli
$ yarn add -D husky lint-staged
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// package.json
{
"scripts": {
"commit": "commit"
},
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
}

standard-version

standard-version 是一款遵循语义化版本( semver)commit message 标准规范 的版本和 changlog 自动化工具。通常情况线下,我们会在 master 分支进行如下的版本发布操作:

  1. git pull origin master
  2. 根据 package.json 中的 version 更新版本号,更新 CHANGELOG
  3. git add .
  4. git commit
  5. git tag 打版本操作
  6. git push --follow-tags origin master && npm publish:push 版本 tag 和 master 分支到仓库并发布

其中 2,3,4,5 是 standard-version 工具会自动完成的工作,配合本地的 shell 脚本,则可以自动完成一系列版本发布的工作了。

安装 & 使用

1
$ yarn add -D standard-version
1
2
3
4
5
6
// package.json
{
"scripts": {
"release": "standard-version"
}
}
  • First Release:yarn release --first-release
  • Cutting Release:yarn release
  • Release as a Pre-Release:yarn release --prerelease or yarn release --prerelease alpha
  • Release as a Target Type Imperatively (npm version-like):yarn release --release-as minor or yarn release --release-as 1.1.0,可以合并 --prerelease以此方便发布实验性特性
  • Prevent Git Hooks:yarn release --no-verify

资源参考