在 Monorepo 中对代码进行规范(husky + lint-staged)

前言

简单讲一下需要使用到的一些工具库

husky

github.com/typicode/hu...

Modern native git hooks made easy

Husky improves your commits and more 🐶 woof!

也就是说,husky为我们提供了一系列的git hooks,用于在进行git操作时的一些预处理等等

lint-staged

github.com/lint-staged...

Run linters against staged git files and don't let 💩 slip into your code base!

专门用于在通过 git 提交代码之前,对暂存区的代码执行一系列的格式化

Biome

个人也非常推荐

不是很喜欢 eslint + prettier 那一套,麻烦,而且要装一堆插件

Biome

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的时候,就会触发该钩子了

相关推荐
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端
yunteng5218 小时前
通用架构(同城双活)(单点接入)
架构·同城双活·单点接入