关于 hairy
这是一项面向 TypeScript 和 JavaScript 工具链项目的个人 Web 开发偏好技能,说明常用技术栈、架构指引、依赖维护方式,以及 lint 和 typecheck 等质量检查要求。
主要功能
- 01使用 pnpm 管理包
- 02Strict TypeScript 与 ESM 偏好
- 03使用 @antfu/eslint-config lint
- 04Vitest 测试约定
- 05架构与依赖指导
- 06Lint 和 typecheck 完成门槛
适用场景
- 01使 Web 项目符合 Hairyf 的工具偏好
- 02为项目或迁移选择架构
- 03使用 taze 保持依赖更新
- 04配置 lint、测试和文档
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ hairyf/ skills --skill hairy安装后在 Claude Code 中输入/hairy确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/antfu-eslint-config.mdapp-development.mdcore-arch-upkeep-routing.mdcore-deps-taze.mdcore-lint-typecheck.mdcore-unjs-preferences.md详细介绍
Hairyf 的偏好设置
本 skill 涵盖 Hairyf 在 Web 开发中偏好的工具链、配置和最佳实践。本 skill 带有明确的主观倾向。
快速摘要
| 类别 | 偏好 |
|---|---|
| 包管理器 | pnpm |
| 语言 | TypeScript(严格模式) |
| 模块系统 | ESM("type": "module") |
| Lint 与格式化 | @antfu/eslint-config(不使用 Prettier) |
| 测试 | Vitest |
| Git Hooks | simple-git-hooks + lint-staged |
| 文档 | VitePress(位于 docs/) |
全局偏好
应当尽可能遵循的高层级通用偏好:
“specify” 关键字
当某个任务被标记为 “specify”(例如:“specify this repo according to hairy”)时:
- 将其视为一个请求:检查当前项目,并在合理可行的范围内对其进行优化,使其尽可能符合这些偏好。
- 具体来说,这应当触发:
- 通过
@skills/arch-upkeep及相关arch-*skills 进行架构检测和升级规划。 - 感知偏好的技术栈选型(优先通过
@skills/unjs选择 unjs 生态)。 - 通过
@skills/taze进行依赖新鲜度检查与升级。 - 在认为 “specify” 任务完成之前,最后执行一遍
lint+typecheck(如有测试也一并运行)。
- 通过
优先选择 unjs 生态框架
- 在选择框架或运行时(SSR、API、工具链、开发服务器等)时,优先选择 unjs 生态项目(例如 Nuxt、Nitro、h3、unstorage、unplugin、unocss、ofetch 以及其他由 unjs 维护的工具)。
- 只有在有明确且合理的理由时(缺少功能、生态限制或历史遗留问题),才退而选择非 unjs 方案。
- 对于具体选择,委托给
@skills/unjs。
架构必须映射到 arch-* skills
项目的架构应始终映射到某个规范的 arch-* skill(tsdown、CLI、monorepo、webext、vscode)。
- 当当前形态无法干净地映射到任何目标架构时,将其视为一个
arch-*skill,并规划迁移,而不是继续添加临时结构。 - 使用
@skills/arch-upkeep来:- 检测当前架构。
- 推荐目标
arch-*skill。 - 编排向该架构的增量迁移。
使用 taze 保持依赖新鲜
- 依赖应当持续保持新鲜,而不仅仅是在大规模重构期间。
- 优先使用
taze(参见@skills/taze)来:- 审计过时的依赖。
- 执行受控升级(定期升级 minor/patch;major 需明确审查)。
- 使用 pnpm workspaces 和 catalogs 在 monorepo 中对齐版本。
- 避免手动编辑
package.json中的版本,除非有特定理由不遵循taze的建议。
始终以 lint + typecheck 收尾
- 在实现任何非平凡的更改(功能、重构、配置变更、依赖升级、CI 变更等)之后,在认为任务完成之前,始终运行 lint 和 typecheck。
- 标准脚本:
nr lint→ 通过@antfu/eslint-config运行 ESLint。nr typecheck→ 以严格模式进行 TypeScript 类型检查(全项目范围)。
- 对于 CI 和 Git Hooks:
- 确保 pre-commit hooks 至少对暂存文件运行
lint。 - 确保 GitHub Actions(或其他 CI)在 PR 和
main推送时同时运行lint和typecheck。
- 确保 pre-commit hooks 至少对暂存文件运行
核心技术栈
包管理器(pnpm)
使用 pnpm 作为包管理器。
对于 monorepo 设置,使用 pnpm workspaces:
# pnpm-workspace.yaml
packages:
- 'packages/*'
在 pnpm-workspace.yaml 中使用 pnpm 具名 catalogs 来管理依赖版本:
| Catalog | 用途 |
|---|---|
prod | 生产依赖 |
inlined | 由打包器内联的依赖 |
dev | 开发工具(linter、打包器、测试、开发服务器) |
frontend | 打包进前端的前端库 |
Catalog 名称不限于以上这些,可以根据需要进行调整。避免使用默认 catalog。
@antfu/ni
使用 @antfu/ni 统一包管理器命令。它会根据 lockfile 自动检测包管理器(pnpm/npm/yarn/bun)。
| 命令 | 描述 |
|---|---|
ni | 安装依赖 |
ni <pkg> | 添加依赖 |
ni -D <pkg> | 添加开发依赖 |
nr <script> | 运行脚本 |
nu | 升级依赖 |
nun <pkg> | 卸载依赖 |
nci | 干净安装(类似 pnpm i --frozen-lockfile) |
nlx <pkg> | 执行包(类似 npx) |
如果找不到这些命令,请使用 pnpm i -g @antfu/ni 全局安装。
TypeScript(严格模式)
始终使用启用了严格模式的 TypeScript。
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
}
}
ESM(ECMAScript 模块)
始终在 ESM 模式下工作。在 package.json 中设置 "type": "module"。
代码质量
ESLint (@antfu/eslint-config)
使用 @antfu/eslint-config 进行格式化和 lint。这消除了对 Prettier 的需求。
创建 eslint.config.js,并添加 // @ts-check 注释:
// @ts-check
import antfu from '@antfu/eslint-config'
export default antfu()
向 package.json 添加脚本:
{
"scripts": {
"lint": "eslint ."
}
}
当遇到 lint 错误时,尝试使用 nr lint --fix 修复它们。不要添加 lint:fix 脚本。
Git 钩子(simple-git-hooks + lint-staged)
使用 simple-git-hooks 配合 lint-staged 进行提交前 lint:
{
"simple-git-hooks": {
"pre-commit": "pnpm i --frozen-lockfile --ignore-scripts --offline && npx lint-staged"
},
"lint-staged": {
"*": "eslint --fix"
},
"scripts": {
"prepare": "npx simple-git-hooks"
}
}
单元测试(Vitest)
使用 Vitest 进行单元测试。
{
"scripts": {
"test": "vitest"
}
}
约定:
- 将测试文件放在源文件旁边:
foo.ts→foo.test.ts(同一目录) - 高级测试放在每个包的
tests/目录中 - 使用
describe和itAPI(而非test) - 使用
expectAPI 进行断言 - 仅将
assert用于 TypeScript 空值断言 - 使用
toMatchSnapshot进行复杂输出断言 - 使用带有显式文件路径和扩展名的
toMatchFileSnapshot处理特定语言的输出(从 lint 中排除这些文件)
项目设置
发布(库项目)
对于库项目,通过由 bumpp 触发的 GitHub Releases 进行发布:
{
"scripts": {
"release": "bumpp -r"
}
}
文档(VitePress)
使用 VitePress 编写文档。将文档放在 docs/ 目录下。
docs/
├── .vitepress/
│ └── config.ts
├── index.md
└── guide/
└── getting-started.md
向 package.json 添加脚本:
{
"scripts": {
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs"
}
}
参考
全局偏好
| 主题 | 描述 | 参考 |
|---|---|---|
| 偏好 unjs 生态 | 优先使用 unjs 生态的框架和工具;委托给 @skills/unjs | core-unjs-preferences |
| 通过 arch-* 进行架构 | 将仓库形态映射到规范的 arch-* 技能,并通过 arch-upkeep 升级 | core-arch-upkeep-routing |
| 使用 taze 保持依赖新鲜 | 使用 taze 和受控升级保持依赖持续新鲜 | core-deps-taze |
| Lint + 类型检查作为门槛 | 始终在本地和 CI 中以 lint + 类型检查收尾 | core-lint-typecheck |
项目设置
| 主题 | 描述 | 参考 |
|---|---|---|
| @antfu/eslint-config | 用于格式化和 lint 的 ESLint flat 配置 | antfu-eslint-config |
| VS Code 扩展 | 推荐的开发扩展 | vscode-extensions |
开发
| 主题 | 描述 | 参考 |
|---|---|---|
| 应用开发 | Vue/Vite/Nuxt/UnoCSS Web 应用的偏好 | app-development |