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

相关推荐
?crying9 分钟前
蓝队基础1 -- 企业信息架构与安全基础
安全·架构
清云随笔12 分钟前
axios 实现 无感刷新方案
前端
mit6.82412 分钟前
[Docker#9] 存储卷 | Volume、Bind、Tmpfs | -v/mount | MySQL 灾难恢复 | 问题
linux·运维·docker·容器·架构
鑫宝Code13 分钟前
【React】状态管理之Redux
前端·react.js·前端框架
忠实米线21 分钟前
使用pdf-lib.js实现pdf添加自定义水印功能
前端·javascript·pdf
pink大呲花24 分钟前
关于番外篇-CSS3新增特性
前端·css·css3
少年维持着烦恼.28 分钟前
第八章习题
前端·css·html
我是哈哈hh31 分钟前
HTML5和CSS3的进阶_HTML5和CSS3的新增特性
开发语言·前端·css·html·css3·html5·web
田本初1 小时前
如何修改npm包
前端·npm·node.js