项目规范最佳实践

在开发项目的过程中,会涉及到多人协作共同开发,由于每个人的个人习惯不同,对代码掌握的水平不同,所以会导致在项目的开发过程中代码质量良莠不齐。 对项目进行规范的过程主要是对代码的限制的过程,如果提高代码的准入门槛,进而可以将不规范以及不细心导致的错误降到最低。

Typescript

由于 JavaScript 是一门弱类型的语言,因而由于类型上缺乏限制导致的问题也会很多,遇到比较多的错误如下:

  • 对象中的值定义不明确

    由于未明确规定对象的值是否存在,会遇到很多例如Can not read property xx of undefined!,例如下例:

    const a = {
      pro1: { name: "n1" },
      pro3: { name: "n3" },
    };

    pro2的属性可能是是没有的,如果按照pro1/pro3的方法去直接调用 name 属性a.proj2.name,这时就会报出从可能的 undefined 中读取属性。如果使用 ts,会在调用a.proj2.name时提示出错,因而避免发生这种错误。

  • 参数传递不正确 例如我们写了一些类或者方法,如果缺乏类型校验,只能调用者来自行保证,这种约束是非常弱的。如果之后函数或者类的参数类型发生了变动,需要逐一去排查原参数调用是否出现问题。如果使用 typescript,就可以通过它的检查来节省人工的做法。

虽然 typescript 的使用会更加规范我们的代码,但是如果从一个已经维护了许久的 JavaScript 项目全量迁移到 ts 是非常痛苦的。 如果是一个新项目,建议从一开始就使用 ts 来维护,这样可以从开始就定义好需要的类型,对项目做一些类型的抽象也会相对简单。如果是一个维护了一段时间的 JavaScript 项目,建议使用逐渐替换的方法来实现 ts 化。 对于维护了一段时间的 JavaScript 项目,一个行得通的方案是通过 lint-staged 来逐渐替换 js 文件。这里有两个原则:

  • 新开发的文件要以 ts 编写

  • 新修改的 js 文件要迁移到 ts 文件

由于 ts 文件与 js 文件可以共存,在 ts 中,如果使用的组件是 ts 编写的,那么就能够使用 ts 的能力来进行检查;如果组件是 js 编写的,那么 ts 就不会进行检查。使用上述的两个原则能够实现逐步的 ts 化,不会引入新的 js 代码。在修改的过程中也会将 js 文件修改为 ts,最终将所有必要的文件都改为 ts。 虽然的 ts 的语法比较简单,但是如果编写扩展性高并且规范的类型还是需要对 ts 有一定的了解的,所以建议 ts 改造的过程需要有一个了解 ts 的人来把握类型书写的质量。

Prettier

代码风格是所有程序员都要遇到的问题,不管是团队协作还是个人练习。往往很多公司想到提高代码质量和开发效率,首先就想到从代码风格入手。但现实中却很少看到代码风格管理很好的团队。因为在大多数时候,代码风格大多存在于讨论,无法确定一个让所有人都满意的方案,就很难执行下去。

由此 Prettier 提供了一个方案,通过在配置文件中规定各种代码的风格,例如缩进等配置。通过这个配置文件来规范整个项目的代码风格。

ESlint

ESLint 是一个开源的 JavaScript 的 linting 工具,使用 espree 将 JavaScript 代码解析成抽象语法树 (AST),然后通过 AST 来分析我们代码,从而给予我们两种提示:

  • 代码质量问题:使用方式有可能有问题

  • 代码风格问题:风格不符合一定规则

如果没有特殊的规范要求,建议使用 eslint-config-airbnb 规范集。

与 ts 类似,从一个现有项目迁移到使用 Eslint 是比较困难的,推荐使用 lint staged 方案,逐渐迁移项目。保持新添加的以及新修改的文件都符合 Eslint 规范。

如果项目中使用了 ts,应该使用 typescript-eslint,而不是使用已被废弃的 tslint。

StyleLint

与 Eslint 类似,进行样式文件(css/less/sass 等)的强制性规范。

Lint Commit

在提交 git 的信息时,也是需要规范化提交的信息(git commit message)。规范化提交信息有几个好处,一是可以快速定位历史的提交,找到自己寻找的提交点;再者可以自动化生成 changelog。

规范化提交信息可以使用 commitizen,配合 cz-conventional-changelog,使用命令行提示选择并补充必要信息来进行 git 的提交。

Lint Staged

lint staged 是指只针对 git 的暂存区的文件进行检查。使用 lint staged 就能做到只检查修改的文件,无需全量扫描,对于迁移的项目也可做到逐步进行检查。

lint staged 可以对不同的文件来制定不同的检查命令,一个配置文件如下:

const fs = require("fs");
const TMP = ".tsconfig-lint.json";

module.exports = {
  "{src,server}/**/*.{ts,tsx}": (filenames) => {
    const json = JSON.stringify(
      {
        extends: "./tsconfig.json",
        include: [...filenames, "./src/externals.d.ts"],
      },
      null,
      2
    );
    fs.writeFileSync(TMP, json);
    return `tsc -p ${TMP} --noEmit --resolveJsonModule`;
  },
  "**/*.{js,ts,tsx,json,jsx,less}": "npm run lint:prettier",
  "{src,server}/**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js",
  "src/**/*.less": "npm run lint:style",
};

lint staged 往往搭配 husky 一起使用。husky 可以在 git 的钩子上定义不同的命令来进行检查。例如可以在 git 的 pre-commit 时期制定 lint-staged 的检查,这样如果检查不通过,就不会提交代码,保证了代码的规范。

CI/CD

上述中提到的保证项目规范的点都是按照本地的检查来进行的,实际上,本地是无法保证提交到远程的信息是一定符合规范的。考虑这样一个过程:远程项目本身是符合规范的,但是本地写了一些不符合规范的代码,而且忽略掉了代码检查的阶段,这样提交到远程的项目是不符合规范的。所以,远程的代码也需要一定的手段来检查。 在代码托管的平台(github/gitlab 等),会有 runner 来运行一些命令,开发者可以在 ci 文件中设置这些命令。当代码推送到远端时,可以运行代码规范检查的命令,如果命令不通过,则不允许该代码合入远端,由此保证远端代码的规范。

最后更新于