硅基俊宁.
Skills · 技能体系 ↗
← 返回文章

前端规范化开发实践

俊宁 · 2020-03-24
迁自历史博客,保留原文、署名、引用与原始日期;文中的版本、成果与性能结论不代表重新完成了当前验收。
查看原始出处 ↗ · 查看迁移清单
前端规范化开发实践封面

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

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

gitconfig

# 初始化设置
$ 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 看做是前端基本功。

{
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint ."
  }
}

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

# 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

安装依赖

# 安装 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

{
   "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

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 风格的换行符
}

插件介绍

vscode eslint plugin config

"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 构建超溜的代码检查工作流

$ yarn add -D husky
{
  "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 修复和破坏性变更。

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

<类型>([可选的作用域]): <描述>

[可选的正文]

[可选的脚注]

类型

范围

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

BREAKING CHANGE

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

示例

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

feat: allow provided config object to extend other configs

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

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

chore!: drop Node 6 from testing matrix

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

不包含正文的提交说明

docs: correct spelling of CHANGELOG

包含作用域的提交说明

feat(lang): add polish language

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

fix: correct minor typos in code

see the issue for details on the typos fixed

closes issue #12

约定式提交规范

  1. 每个提交都必须使用类型字段前缀,它由一个名词组成,诸如feat或fix,其后接一个可选的作用域字段,以及一个必要的冒号(英文半角)和空格。
  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. 在提交说明中,可以使用feat和fix之外的类型。
  11. 工具的实现必须不区分大小写地解析构成约定式提交的信息单元,只有BREAKING CHANGE 必须是大写的。
  12. 可以在类型/作用域前缀之后,:之前,附加!字符,以进一步提醒注意破坏性变更。当有!前缀时,正文或脚注内必须包含BREAKING CHANGE: description

为什么使用约定式提交

commitlint

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

$ yarn add -D @commitlint/cli @commitlint/config-conventional @commitlint/prompt-cli
$ yarn add -D husky lint-staged
// 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 脚本,则可以自动完成一系列版本发布的工作了。

安装 & 使用

$ yarn add -D standard-version
// package.json
{
  "scripts": {
    "release": "standard-version"
  }
}

资源参考