前言
简单讲一下需要使用到的一些工具库
husky
Modern native git hooks made easy
Husky improves your commits and more 🐶 woof!
也就是说,husky为我们提供了一系列的git hooks,用于在进行git操作时的一些预处理等等
lint-staged
Run linters against staged git files and don't let 💩 slip into your code base!
专门用于在通过 git 提交代码之前,对暂存区的代码执行一系列的格式化
Biome
个人也非常推荐
不是很喜欢 eslint + prettier 那一套,麻烦,而且要装一堆插件
One toolchain for your web project
通过一个工具就可以完成包括 format、lint等等的工具链(速度也非常快,内部使用rust编写的)
顺便说一下,之前 prettier 也发起了一个 rust化的竞赛,biome也获得了最终的奖金🎉🎉🎉
Biome formatter wins the Prettier challenge | Biome (biomejs.dev)
monorepo
这边使用的是 pnpm + turbo 组合实现的
目录结构
包含三个分区
vbnet
packages:
- 'apps/*'
- 'packages/*'
- 'examples/*'
接下来我们就直接进行主题
lint
在 packages 下创建一个lint包,用于使用以上内容
以下是目录结构
首先我们先安装所需的库
bash
pnpm add husky lint-staged -D
# 注意biome需要全局安装
pnpm add --save-dev --save-exact @biomejs/biome -w
接下来我们来依依说明每个文件
biome.json
默认的一些配置,后续可以根据每个项目的不同去扩展,默认配置可以通过 extends 去导入
json
{
"$schema": "<https://biomejs.dev/schemas/1.4.1/schema.json>",
"files": {
"ignore": ["dist/*", "node_modules/*", ".vscode/*", "turbo/*"]
},
"organizeImports": {
"enabled": true,
"ignore": []
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"a11y": {
"useKeyWithClickEvents": "off",
"useKeyWithMouseEvents": "off"
}
},
"ignore": []
},
"formatter": {
"enabled": true,
"ignore": [],
"indentStyle": "space",
"lineWidth": 120,
"indentWidth": 2,
"lineEnding": "lf"
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"jsxQuoteStyle": "single",
"semicolons": "asNeeded",
"trailingComma": "all",
"arrowParentheses": "asNeeded",
"bracketSpacing": true,
"quoteProperties": "asNeeded"
}
}
}
在其他项目中,通过如下方式引用(如果是npm安装,则是node_modules)
json
{
"extends": ["./packages/lint/biome.json"]
}
prepare.js
通过npm提供的hook,可以在安装该包的时候执行prepare指令,我们可以给prepare挂载一个指令去执行该文件
需要在 package.json 中添加这条指令
json
{
"name": "@turbo/lint",
// ...
"scripts": {
"prepare": "node prepare.js",
},
// ...
}
prepare.js文件的目的就是找到git仓库所在的目录,并为其添加上.husky文件夹
首先我们需要根据目录向上去递归遍历找到最终的git仓库文件夹,找不到的话则报错(注意:husky必须安装在git所在的目录,不然会报错)
javascript
const path = require('path')
const husky = require('husky')
const fs = require('fs')
const isDiskRoot = dirPath => {
const pathObj = path.parse(dirPath)
return pathObj.root === dirPath
}
const isGitFolder = dirPath => {
const gitFolderPath = `${dirPath}\\.git`
try {
const stat = fs.statSync(gitFolderPath)
return stat.isDirectory() || stat.isFile()
} catch (error) {
return false
}
}
const findNearestGit = dirname => {
if (isDiskRoot(dirname)) {
return null
}
if (isGitFolder(dirname)) {
return dirname
}
return findNearestGit(path.resolve(dirname, '..'))
}
const gitFolder = findNearestGit(__dirname)
通过以上方式,最终就能找到 git 所在的目录了
接下来,我们根据git目录去执行husky install指令,并添加pre-commit钩子
javascript
const { execSync } = require('child_process')
const gitFolder = findNearestGit(__dirname)
if (!gitFolder) {
throw new Error('postinstall husky but cannot find .git file, please git init first!')
}
// 执行指令
execSync(`cd ${gitFolder} && husky install`)
// 找到创建好的.husky所在的目录
const preCommitFile = path.join(gitFolder, '.husky', 'pre-commit')
// 找到runLintStaged.mjs文件位置,后续需要执行该文件,进行项目格式化
const lintStagedJs = path.join(__dirname, 'runLintStaged.mjs').replace(/\\/g, '/')
// 最后将钩子设置到husky中
husky.set(
preCommitFile,
`echo ''\nnode "${lintStagedJs}"`,
)
通过这种方式,我们就可以在安装lint包的同时,帮我们创建好.husky文件夹,以及pre-commit钩子,最后在钩子中添加 node lintStagedJs
来实现格式化
runLintStaged.mjs
同理,我们需要在该文件中也要找到git仓库所在目录,然后在根目录去执行lint来进行整体的格式化
注意,有一点不一样,因为使用的是mjs,所以需要手动设置一下__dirname
javascript
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const gitFolder = findNearestGit(__dirname)
找到之后,就可以去执行格式化命令了
javascript
import lintStaged from 'lint-staged'
lintStaged({
config: { '*.{js,ts,jsx,tsx,json,css,md}': `biome format --write ${gitFolder}\\.` },
}).then(res => {
if (res) {
console.log('🚀 ~ set lintStaged successfully!')
} else {
throw new Error('🚀 ~ biome failed! please fix and retry!')
}
})
成效
最终,我们就可以在其他项目中去引用lint包了
json
{
"devDependencies": {
"@turbolc/lint": "workspace:*",
}
}
或者也可以将库发送到npm仓库中,去直接下载
安装lint库之后,我们就会看见如下界面
在pre-commit文件中,也能看到对应的hook
内容
shell
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
node "...(目录)/turbo-web/packages/lint/runLintStaged.mjs"
后面,在你提交commit的时候,就会触发该钩子了