统一开发环境、了解配置原理(下)

3,412 阅读11分钟

本文为稀土掘金技术社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究!

在上一小节中,我们完成了eslintprettier的配置,但是工程化的配置当然不仅仅于此,我们还需要一些其他的配套让我们的工程看起来更加稳固,这里就不统一总结,我们直接进入主题,去了解其他的配置和其原理吧。

stylelint样式规则配置

除了对我们的js代码vue代码进行检测之外,我们的css也是至关重要的一个角色,在我们日常的开发中,多人协作的场景下,每个人的习惯不同会让css代码看起来比较混乱,要想使用这个工具,我们还是需要先安装stylelint

pnpm i stylelint -D

然后我们需要使用它,使用方式和eslint大同小异,在根目录添加一个配置文件stylelint.config.js文件,然后导出一个对象即可,同时也具有,pluginextendsrules这些配置。

首先配置规则呢也是给rules对象添加规则即可,在这里可以看到所有默认的规则,在这里选择即可,如果你觉得这个配置麻烦,我们也可以选择去使用开源的别人的规则继承下来,然后自己去修改自己不喜欢的规则,比如其标准配置可以下载stylelint-config-standard这个包,也有比较知名的stylelint-config-airbnb开源包,二选一即可。

同时因为我们已经使用了prettier,在这里面可能也会有一些css的相关规则,我们需要将其全部关闭,防止和我们这里的配置进行冲突,所以我们可以使用stylelint-config-prettier包,它会将所有的prettier冲突规则全部关闭。

其次stylelint默认其也只能检测css,而如果你使用的是scss或者less等预处理器,那么就需要下载相对应的插件,比如我们的组件库是scss,我们就需要下载stylelint-scss,让其可以对scss生效。

pnpm i stylelint-scss -D

在有了上述的了解之后我们可以有了以下的基础配置:

/* https://stylelint.io/user-guide/rules/selector-class-pattern/ */
module.exports = {
  root: true,
  plugins: ['stylelint-scss'],
  extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
  syntax: 'scss',
  rules: {},
  ignoreFiles: ['**./*.js,', '**./*.ts,', '**./*.tsx,', '**./*.jsx,', '**./*.vue,']
};

有了这些基础配置之后,想要忽略某些规则也是同理,在根目录下创建.stylelintignore 文件即可,我们已经继承了stylelint-config-standard的规则了,所以我们可以去检测自己的样式是不是有问题,和eslint一样,我们也去package.json之中配置一条检测命令:

"lint:css": "stylelint 'packages/theme-chalk/src/**/*.scss' --fix"

因为我们的项目css全部写在了`theme-chalk子项目中,所以我们只需要对齐一个目录检测即可,然后我们使用这个命令去检测看看:

001.png

此时告诉我们当我们去检测非css的情况下,我们需要指定的customSyntax字段,根据提示我们去安装一个postcss-scss

pnpm i postcss-scss -D

然后再修改一下其检测脚本:

"lint:css": "stylelint 'packages/theme-chalk/src/**/*.scss' --fix --custom-syntax postcss-scss"

此时我们再次进行检测,会发现之前的警告已经不在了,只剩下下面这些错误,说明我们的配置是ok的,并且也检测了不符合规则的错误:

002.png

但是当我们点击到详细文件的时候,会发现并没有红线的错误,那么这样对我们开发的时候是十分不方便的,我们希望的是在开发的时候就可以实时的看到错误,所以,和eslint或者prettier一样,我们需要安装对应的编辑器插件styelint插件,当我们安装之后呢,依然还是没有红线的报错,为什么呢 ?

因为我们还没有配置编辑器,编辑器不知道需要检测类似scss的语言,所以我们对编辑器的配置进行添加,在.vscode配置文件中,在settings.json后面追加这些配置:

{
  "eslint.validate": ["html", "vue", "javascript", "jsx"],
  "emmet.syntaxProfiles": {
    "vue-html": "html",
    "vue": "html"
  },
  "editor.tabSize": 2,
  "eslint.alwaysShowStatus": true,
  "eslint.quiet": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
    "source.fixAll": true
  },
  "stylelint.customSyntax": "postcss-scss",
  "stylelint.validate": [
      "css",
      "less",
      "postcss",
      "scss",
      "vue",
      "sass"
  ],
}

新增stylelint.validate的配置,告诉插件我们需要检测哪些后缀结尾的文件,我们根据自己的需求添加即可,当我们配置完成之后,记得重载窗口,让配置生效,在重载窗口之后,我们就可以编辑器可以通过红线报错了:

003.png

此时我们已经完成了在开发过程的对css校验的良好体验了,可以锦上添花,增加一个配置,让我们在保存文件的时候对可以修复的错误规则进行自动修复,和eslint一样,我们在上面的编辑器配置中新增"source.fixAll.stylel即可实现。

"editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
    "source.fixAll": true,
    "source.fixAll.stylelint": true
  },

继续还是别忘记重载窗口,之后我们可以修复的一些指令在我们保存文件的时候就会自动修复,比如文件空格,缩进这些小问题我们就可以不需要在开发的时候自己修改了。

最后组件库中我还使用了一个这个包stylelint-order,可以自定义样式的排序顺序,当然只需做一点了解即可,知道他是干嘛的就行,实际开发中不一定需要,我们还是得配置一些自己的rules规则才能使最终的体验比较友好。

上面就是关于style样式这块儿的开发工程了,到这个程度就可以保证你有一个相对还不错的样式开发体验了,也可以明白不同的包在这个工程中扮演的角色了,接下来,开始我们的下一步。

ls-lint文件命名规则配置

在一个项目中,除了对代码的一些规则限制外,我们对文件的命名也是需要限制的,比如我们去命名一个变量的时候我们就知道这个变量是什么意思了,我们如何对文件也做到这样的限制呢?我们可以通过文件名就知道这是哪个页面,这是什么组建,名称的语义化是其中一个,第二个就是命名形式的规则,比如我们都使用驼峰命名还是使用连字符命名等等都是在工程中需要考虑的问题,我们如何能实现呢?

这里就需要使用到ls-lint了,他可以对我们的文件名进行检测,并告诉你这些命名是否合理,需要注意的是我们下载的包是@ls-lint/ls-lint,不是ls-lint,这个包名被占用了。

pnpm i @ls-lint/ls-lint -D

下载完之后呢,同样需要一个配置文件,我们同样在根目录下创建一个配置文件,.ls-lint.yml文件,然后进行配置即可,配置的规则呢很简单,什么目录,或者什么格式的文件使用什么规则进行命名,同时告诉插件哪些文件忽略,配置思想是大同小异的。这里看看我的配置做做参考:

ls:
  packages/components/**:
    .dir: kebab-case
    .vue: kebab-case
    .js: kebab-case
    .ts: kebab-case
    .json: kebab-case
    .d.ts: kebab-case
    .tsx: kebab-case

ignore:
  - .git
  - .vscode
  - node_modules

上述配置忽略的很容易理解,上面的呢就是告诉插件我们对packages/components/下面的所有文件,然后下面不同的格式使用什么样的命名,为了统一,一般建议所有文件都进行统一的规则命名,命名的方式有很多种,下面是不同的命名规则可以参考。

规则别名描述
正则-满则正则表达式^{pattern}$
lowercase-文件或目录名必须全小写,数字除外,如 abeautifulname
camelcasecamelCase文件和目录名必须为驼峰式,且只支持字母和数字,如 aBeautifulCase
pascalcasePascalCase文件和目录名必须满足帕斯卡命名法,且只支持字母和数字,如 ABeautifulName
snakecasesnake_case文件和目录名必须为下划线联接,且只支持字母、数字和下划线,如 a_beautiful_name
kebabcasekebab-case文件和目录名必须为中划线联接,且只支持字母、数字和中划线,如 a-beautiful-name
pointcasepoint.case文件和目录名必须满足点文件规范,且只支持字母、数字和点,如 a.beautiful.name

而我们上面配置的规则的意思是全部使用连字符的方式命名并且全部是小写。

配置完规则之后我们如何去进行检测呢,他为我们提供了一个ls-lint的脚本,我们只需要在scripts当中去添加这个脚本然后去运行检测就行:

"lint:ls-lint": "ls-lint",

此时去执行检测即可,如果没有的话呢就会直接结束,如果有就会告诉你错误,我们去创建一个不符合规则的名称比如userLogin这种驼峰的,很明显不符合规则,我们看看:

004.png

就会出现这样的错误,很明显命名规则不合适,但是问题来了,这样的文件命名并不是我们写代码可以实时提醒的,也不能有红色波浪线告知你,我们不能每次让用户都去自己执行一下npm run lint:ls-lint这样来检测吧,这样过于繁琐而且似乎没这个必要,新来的开发同事也不会知道有这种操作,所以我们需要自己去强制实现这种校验并且不需要用户自己去手动执行我们可以怎么做呢?

husky静态限制

使用这个工具可以帮我们解决上述问题,那么首先我们需要知道什么是husky,它是干什么的呢?

Modern native Git hooks made easy (轻松创建现代化的原生 git hooks) Husky improves your commits and more 🐶 woof!

其作用呢就是在我们使用git提交的过程前后,进行一系列的hook操作,我们也可以理解其就是一个git的生命周期,我们可以在这个过程中做一些事情,然后我们就可以让用户提交的时候检测一次上面的文件命名是否有问题,如果有就阻止用户提交代码,除此之外我们也就可以对代码进行校验了,上面的eslintprettierstylelint这些工具我们都可以让其全部检测通过才允许用户提交代码,这样一来,我们就可以保证提交到仓库的代码是有一定可靠性的,同时减少了很多不必要的基础错误,那么如何来使用呢?

其实husky的新老版本是有破坏性变更的,不同版本的配置也是不一样的,但是呢当然还是学新不学旧,我们直接看最新版,这里直接进入文档,告诉我们以下几步:

  • npm pkg set scripts.prepare="husky install"
  • npm run prepare
  • npx husky add .husky/pre-commit "npm test"

上面是什么意思呢,第一步让我们添加一个脚本,scripts下面添加一个prepare,然后执行husky install,其实这个prepare可以在用户npm install下载完依赖之后直接执行,其实就表示用户下完依赖然后执行这个脚本而已,我们可以根据他的这样提示完成这两步,或者我们直接npx husky install也可以完成其初始化,我们执行这个命令后发现

005.png

在根目录下出现了这个配置文件,具体的作用呢就不在这里过多解释了,有兴趣的可以看看其中的实现,用的是shell脚本来编写的,我们其实也不需要关心,我们直接进入第三步,使用这个命令可以添加一个pre-commit的脚本,在这个hook当中去执行npm test脚本,我们生成看看吧:

006.png

我们发现在.husky当中出现了一个pre-commit的文件并且在其中写入了上面的内容,上面呢前两行都是一样的,第一行申明当前文件用node执行,第二行就是就是匹配到hook然后执行对应的脚本,所以,文件名就代表了hook,我们想要增加新的hook可以复制一份改个文件名就行,具体执行的内容替换掉npm test就行,正常来说,pre-commit就是最多的,我们做个测试,将npm test修改为echo 来自husky的pre-commit

这样我们就可以在commit的时候打印这句话了,来试试看:

007.png

我们发现,在commit的时候,就会打印这句话了,当然了,不止有这一个hook,还会有下面这些,但是使用频率最高的就是pre-commit了。

git hooks 分为客户端与服务端,有下面这些钩子,但是实际使用上并不会太多

  • 客户端 hooks

    • 提交工作流

      • pre-commit
      • prepare-commit-msg
      • commit-msg
      • post-commit
    • email 工作流

      • applypatch-msg
      • pre-applypatch
      • post-applypatch
    • 其它

      • pre-rebase
      • post-rewrite
      • post-checkout
      • post-merge
      • pre-push
      • pre-auto-gc
  • 服务器端 hooks

    • pre-receive
    • update
    • post-receive

上面的这些钩子具体我们可以看看文档,但是实际上不会使用太多,我们已经明白了其使用方式,此时如果要对文件进行检测就会很简单了。

我们只需要把上面的echo修改为我们需要的脚本即可,比如检测文件名,检测eslintprettierstylelint等等,都可以放在这里检测,只有检测通过了,才允许我们进行提交。

所以至此我们也需要在scripts当中去增加这些脚本脚本,方便我们单独测试或者在这种hook当中使用:

"scripts": {
    "dev": "pnpm run -C example dev",
    "dev:docs": "pnpm run -C docs dev",
    "clear": "rimraf dist",
    "clear:cache": "rimraf node_modules/.cache/ rimraf node_modules/.vite",
    "clear:lib": "rimraf node_modules",
    "lint:fix": "eslint . --fix",
    "lint:eslint": "eslint .",
    "lint:prettier": "prettier --write .",
    "lint:css": "stylelint 'packages/theme-chalk/src/**/*.scss' --fix --custom-syntax postcss-scss",
    "lint:ls-lint": "ls-lint",
    "reinstall": "rimraf pnpm-lock.yarm && rimraf node_modules && pnpm install",
    "prepare": "husky install",
    "postinstall": "npx husky install"
  },

我们添加了很多不同的校验命令和检测命令,比如在上述脚本之后再去添加一个检测css的脚本然后再次commit看看

008.png

我们发现此时在执行脚本遇到错误的时候就会直接退出,也就意味着如果我们定义的规则在本地都不能 通过的时候是不允许用户提交上线的,这样的配置会让项目安全性大大提高,同理,我们可以添加上所有校验脚本,修复脚本,让很多可以自动修复的规则也进行修复,之前再允许项目上传到git中去即可,看似我们的工程已经差不多了,但是此时会面临一个问题,在我们项目庞大的时候,让这些脚本一次运行一遍需要耗费的时间是我们不能接受的,很显然也不合理,如果我们只改了一行代码还得这个流程,那也太麻烦了,所以我们还需要对其进行加固。

lint-staged提高校验效率

使用lint-staged前可以先大概看看其文档,我们在进行使用前也进行一些简单的介绍,他有什么特点呢?

lint-staged 是一个命令行工具,它能够对 git 的 staged(暂存区)中的文件使用 linter 工具格式化,修复一些风格问题,并再次添加到 staged 上。

上面我们说到了我们不应该对所有文件进行修复和检测,所以我们可以用到这个工具,他可以帮我们只检测本次变更的文件,不会影响之前的文件,这样一来需要检测文件数量大大变少,我们检测的时间也大大变少,这是其其中一个优点。

pnpm i lint-staged -D

那么它是如何使用呢,和上述工具一样,他也提供了一个脚本,lint-staged,所以我们也需要在scripts当中去添加这样一个脚本用于调用它:

"lint:staged": "lint-staged",

很明显使用调用脚本即可,在这之前我们还是需要一个我们的配置文件,它需要告诉我们使用哪些命令去检测,对于不同类型的文件如何检测等等,创建一个配置文件的形式依然有很多,使用rcconfigjson,yaml什么格式都行,我们这里创建一个文件.lintstagedrc用于配置我们需要的参数。

module.exports = {
  '*.{js,jsx,ts,tsx}': ['eslint --fix', 'prettier --write'],
  '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': ['prettier --write--parser json'],
  'package.json': ['prettier --write'],
  '*.vue': ['prettier --write', 'eslint --fix'],
  'packages/theme-chalk/src/**/*.{scss,css}': ['stylelint --fix --custom-syntax postcss-scss', 'prettier --write'],
  '*.md': ['prettier --write']
};

上述就是一个简单的配置,告诉其对于不同的文件我们需要执行什么命令,但是上面都是关于修复的命令,如果你需要你的文件还得通过你的一些比如eslint的所有规则校验,那么你也可以加上你的校验命令,然后我们执行npm run lint:staged我们上面添加的脚本就可以对本次提交的所有文件进行检测了。

如果你没有任何提交变更,此时去执行这个命名是不会有任何操作的并且会给你一个报错提示。

009.png

正常的检测就会如上图一样,依次检测完我们的所有文件,当遇到错误的时候就会中断进程,这样我们就可以每次只检测变更的文件,并且可以放心去检测我们所有的脚本了。

这里他还有另一个优点,上面的这些操作他是并行完成的,也就意味着,这样的检测方式可以让他的效率更高,因为彼此之间的检测不会互相影响,我们并行检测就可以更加快速完成这个工作了。

此时我们只需要把我们的钩子中npm run lint:css改为我们的这个新脚本npm run lint:staged就可以实现我们想要的功能了,可以在提交之前完成我们所有需要的检测命令,保证别的开发同事拉取下来代码是没有错误提示的,也显著的强制提示了我们的代码质量。

对于pre-commit的钩子翻译过来就是commit之前,这个操作发生在我们commit信息之前的,如果没有通过,我们是没有commit成功的,与之对应的还有一个钩子commit-msg是提交时的钩子,这两个也是我们使用频率最高的两个钩子,我们常说的对commit信息校验的钩子便是这个hook了,在我们校验完我们的脚本之后,我们还想校验我们的commit信息可以怎么做呢?

commitlint提交信息校验限制

在使用前我们需要想想为什么使用,很多公司应该都会有这种规范,清晰命令的commit信息可以帮助我们更好的溯源,也可以让我们更加清晰的了解每次提交都变更了什么内容,一般在开源的项目当中基本都会使用到,这样也方便多成员对项目更快的理解。

一般使用前我们直接先下载这个包即可,但是虽然我们使用的是commitlint但是我们下载的包应该是@commitlint/cli,打开其npmjs我们可以看到下面:

010.png

让我们直接使用@commitlint/cli,所以记得别下错了,也知道什么原因了。

pnpm i @commitlint/cli -D

要想使用他还是老规矩我们创建一个配置文件,commitlint.config.js。他的配置方法和eslint是很像的,一般都是三板斧,继承忽略,自定义rules,我们要么使用开源的别人配置好的,要么自己配置,要么就使用开源的,再去覆盖掉自己不喜欢的,一般比较知名的开源规则。

  • @commitlint/config-conventionalAnglar的提交规范

我们可以使用这个规范然后自己修改一部分即可:

pnpm i @commitlint/config-conventional -D

下载完之后我们去完善我们的配置文件:

module.exports = {
  ignores: [commit => commit.includes('init')],
  extends: ['@commitlint/config-conventional'],
  rules: {
    'body-leading-blank': [2, 'always'],
    'footer-leading-blank': [1, 'always'],
    'header-max-length': [2, 'always', 108],
    'subject-empty': [2, 'never'],
    'type-empty': [2, 'never'],
    'subject-case': [0]
  }
};

上面的内容很简单,忽略了信息中含有init关键字的信息,同时继承了@commitlint/config-conventional规则,最后覆盖了一部分自己不喜欢的,此时配置文件编写完毕后,我们就可以去使用它了,如何使用呢?

使用commitlint

首先这个东西如何调用呢?直接调用npx --no-install commitlint --edit "$1"即可,老版本的调用和新版本不一样,如果要看具体变更可以[查看文档](commitlint - Lint commit messages)获取具体信息。

上面我们提到了我们可以在commit-msghook钩子中进行检测,所以我们需要先去创建这个钩子,之前我们说了,在.husky下面创建的文件名就是一个钩子,所以我们可以这样创建:

  • 我们可以直接复制一份pre-commit文件,然后将里面的npm run lint:staged改为我们上面的调用脚本方法,同时将文件名改为commit-msg即可,这样就完成了调用。
  • 当然也可以根据官方提供的脚本直接去添加一个hook钩子,我们可以npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"' 这样也可以完成一个添加

大同小异,我们只需要明白,一个文件就是一个hook,文件名代表了具体的hook,这就是其配置原理,他会在具体的hook中找到同名文件然后执行。

我们可以测试一下去随便提交一个commit信息。

011.png

我们发现首先执行了了,pre-commit钩子,然后检测了文件,之后就检测了我们的commit-msg钩子,发现提交的信息不符合规范,然后退出了本次提交,说明我们的配置和钩子生效了,配置规范呢就自己去看这个@commitlint/config-conventional的规则了。文档地址可以参考这里,相信大家或多或少对这个提交的规范也是有一定了解的。

此时我们已经完成了对提交规范的限制了。但是这个提交信息呢要想符合规范并且想做到格式统一,单纯的告诉同事让他们按照规范写有点不容易,还得需要记忆成本,所以我们可以使用工具去辅助他完成这个工作。

对了还得补充一点,如果你想自定义校验提交限制,我们可以自己去编辑一个js文件,然后替换掉上面的commitlint的脚本改为node xxx.js即可。

使用工具辅助完成提交

对于commitlint有很多的配套辅助工具,可以通过cli来帮助我们逐步填写所有信息。

  • commitizen
  • cz-conventional-changelog
  • commitlint-config-cz
  • cz-customizable

这些工具都可以帮我们完成,具体使用还是自行查看文档,我们可以随便挑选里面的工具来使用,这里我使用了cz-conventional-changelog这也是官方文档中推荐使用的。

pnpm i cz-conventional-changelog -D

如何使用呢?我们打开文档看看。

012.png

让我们在package.json当中去进行一些配置信息,可以进入官网看更多的信息,这里我们主要使用的只需要这一条即可,其他的规则是需要和你上面配置的commitlint.config.js想匹配的,否则工具生成的信息就会在上面失败,这里如果出现冲突了,自己可以覆盖冲突配置或者让两边保持统一。

"config": {
    "commitizen": {
      "path": "cz-conventional-changelog"
    }
  },

有了这个配置,我们就可以去调用这个工具提供的一个脚本了git cz,我们只需要在scripts当中配置这个脚本规则:

"commit": "git-cz"

这个工具就可以帮我们去生成完整的并且格式统一的commit信息命令了,我们只需要在git add之后去执行npm run commit就可以保证大家的提交信息是一致的,同时工具帮你完成所有信息的归纳统一。

013.png

如果你觉得英文或者提示不是你想要的,你也可以通过配置文件中prompt字段进行修改,具体的配置,就可以对其进行适配了。

很多开源项目也会有那种各类的表情包在上面也是在此处完成的。

总结

本节内容我们完成了对于一个项目工程化的完善,对项目添加了stylelint样式校验,ls-lint文件命名校验, 同时使用husky工具通过对hook在不同阶段通过lint-staged校验和修复了所有提交文件信息,并在commit-msg钩子中对commit信息进行了规范校验,最后我们再使用了commitlint的配套工具,让我们可以通过脚本直接信息。

我们已经完成了项目整体规范的一大步了,此时的项目基础规范已经想对健全了,要想之后有更好的体验,我们可以逐步完成对配置的进一步优化并找到适合自己项目的最佳规范,完成上一节和这一节的内容,你就可以为你的项目添加一套不错的工程化基础设施了。

现在我们的组件库基础设施已经更进一步了,下一小节,我们需要完成对组件库文档的建设,让我们的组件库生态逐步完善。

最后欢迎加入本期专栏,让我们从零开始,一起完成组件库的建设吧。

本期专栏历史文章