hairy

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Hairyf's Preferences

Hairyf的开发偏好

This skill covers Hairyf's preferred tooling, configurations, and best practices for web development. This skill is opinionated.
本内容涵盖了Hairyf在Web开发中偏好的工具、配置以及最佳实践,带有明确的个人倾向。

Quick Summary

快速概览

CategoryPreference
Package Managerpnpm
LanguageTypeScript (strict mode)
Module SystemESM (
"type": "module"
)
Linting & Formatting@antfu/eslint-config (no Prettier)
TestingVitest
Git Hookssimple-git-hooks + lint-staged
DocumentationVitePress (in
docs/
)

分类偏好选择
包管理器pnpm
开发语言TypeScript(严格模式)
模块系统ESM (
"type": "module"
)
代码检查与格式化@antfu/eslint-config(无需Prettier)
测试框架Vitest
Git钩子simple-git-hooks + lint-staged
文档工具VitePress(存放于
docs/
目录)

Core Stack

核心技术栈

Package Manager (pnpm)

包管理器(pnpm)

Use pnpm as the package manager.
For monorepo setups, use pnpm workspaces:
yaml
undefined
使用pnpm作为包管理器。
对于单仓库多项目(monorepo)配置,使用pnpm工作区:
yaml
undefined

pnpm-workspace.yaml

pnpm-workspace.yaml

packages:
  • 'packages/*'


Use pnpm named catalogs in `pnpm-workspace.yaml` to manage dependency versions:

| Catalog | Purpose |
|---------|---------|
| `prod` | Production dependencies |
| `inlined` | Dependencies inlined by bundler |
| `dev` | Development tools (linter, bundler, testing, dev-server) |
| `frontend` | Frontend libraries bundled into frontend |

Catalog names are not limited to the above and can be adjusted based on needs. Avoid using default catalog.
packages:
  • 'packages/*'


在`pnpm-workspace.yaml`中使用pnpm命名目录来管理依赖版本:

| 目录名称 | 用途 |
|---------|---------|
| `prod` | 生产环境依赖 |
| `inlined` | 构建工具内联的依赖 |
| `dev` | 开发工具(代码检查器、构建工具、测试框架、开发服务器) |
| `frontend` | 前端库(将被打包到前端产物中) |

目录名称不限于上述示例,可根据需求调整。避免使用默认目录。

@antfu/ni

@antfu/ni

Use
@antfu/ni
for unified package manager commands. It auto-detects the package manager (pnpm/npm/yarn/bun) based on lockfile.
CommandDescription
ni
Install dependencies
ni <pkg>
Add dependency
ni -D <pkg>
Add dev dependency
nr <script>
Run script
nu
Upgrade dependencies
nun <pkg>
Uninstall dependency
nci
Clean install (like
pnpm i --frozen-lockfile
)
nlx <pkg>
Execute package (like
npx
)
Install globally with
pnpm i -g @antfu/ni
if the commands are not found.
使用
@antfu/ni
统一包管理器命令。它会根据锁文件自动检测包管理器(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 (Strict Mode)

TypeScript(严格模式)

Always use TypeScript with strict mode enabled.
json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true
  }
}
始终启用严格模式使用TypeScript。
json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true
  }
}

ESM (ECMAScript Modules)

ESM(ECMAScript模块)

Always work in ESM mode. Set
"type": "module"
in
package.json
.

始终使用ESM模式。在
package.json
中设置
"type": "module"

Code Quality

代码质量保障

ESLint (@antfu/eslint-config)

ESLint代码检查(@antfu/eslint-config)

Use
@antfu/eslint-config
for both formatting and linting. This eliminates the need for Prettier.
Create
eslint.config.js
with
// @ts-check
comment:
js
// @ts-check
import antfu from '@antfu/eslint-config'

export default antfu()
Add script to
package.json
:
json
{
  "scripts": {
    "lint": "eslint ."
  }
}
When getting linting errors, try to fix them with
nr lint --fix
. Don't add
lint:fix
script.
使用
@antfu/eslint-config
同时处理代码格式化与检查,无需再使用Prettier。
创建带有
// @ts-check
注释的
eslint.config.js
文件:
js
// @ts-check
import antfu from '@antfu/eslint-config'

export default antfu()
package.json
中添加脚本:
json
{
  "scripts": {
    "lint": "eslint ."
  }
}
遇到代码检查错误时,尝试使用
nr lint --fix
修复。不要单独添加
lint:fix
脚本。

Git Hooks (simple-git-hooks + lint-staged)

Git钩子(simple-git-hooks + lint-staged)

Use
simple-git-hooks
with
lint-staged
for pre-commit linting:
json
{
  "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"
  }
}
使用
simple-git-hooks
搭配
lint-staged
实现提交前代码检查:
json
{
  "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"
  }
}

Unit Testing (Vitest)

单元测试(Vitest)

Use Vitest for unit testing.
json
{
  "scripts": {
    "test": "vitest"
  }
}
Conventions:
  • Place test files next to source files:
    foo.ts
    foo.test.ts
    (same directory)
  • High-level tests go in
    tests/
    directory in each package
  • Use
    describe
    and
    it
    API (not
    test
    )
  • Use
    expect
    API for assertions
  • Use
    assert
    only for TypeScript null assertions
  • Use
    toMatchSnapshot
    for complex output assertions
  • Use
    toMatchFileSnapshot
    with explicit file path and extension for language-specific output (exclude those files from linting)

使用Vitest进行单元测试。
json
{
  "scripts": {
    "test": "vitest"
  }
}
约定规范:
  • 测试文件与源码文件放在同一目录:
    foo.ts
    foo.test.ts
    (相同目录)
  • 高层测试放在每个包的
    tests/
    目录下
  • 使用
    describe
    it
    API(不要使用
    test
  • 使用
    expect
    API进行断言
  • 仅在TypeScript空值断言时使用
    assert
  • 对复杂输出断言使用
    toMatchSnapshot
  • 针对特定语言的输出,使用带明确文件路径和扩展名的
    toMatchFileSnapshot
    (将这些文件排除在代码检查之外)

Project Setup

项目配置

Publishing (Library Projects)

发布流程(类库项目)

For library projects, publish through GitHub Releases triggered by
bumpp
:
json
{
  "scripts": {
    "release": "bumpp -r"
  }
}
对于类库项目,通过
bumpp
触发GitHub Releases进行发布:
json
{
  "scripts": {
    "release": "bumpp -r"
  }
}

Documentation (VitePress)

文档构建(VitePress)

Use VitePress for documentation. Place docs under
docs/
directory.
docs/
├── .vitepress/
│   └── config.ts
├── index.md
└── guide/
    └── getting-started.md
Add script to
package.json
:
json
{
  "scripts": {
    "docs:dev": "vitepress dev docs",
    "docs:build": "vitepress build docs"
  }
}

使用VitePress构建文档。文档存放于
docs/
目录下。
docs/
├── .vitepress/
│   └── config.ts
├── index.md
└── guide/
    └── getting-started.md
package.json
中添加脚本:
json
{
  "scripts": {
    "docs:dev": "vitepress dev docs",
    "docs:build": "vitepress build docs"
  }
}

References

参考资源

Project Setup

项目配置参考

TopicDescriptionReference
@antfu/eslint-configESLint flat config for formatting and lintingantfu-eslint-config
GitHub ActionsPreferred workflows using sxzz/workflowsgithub-actions
.gitignorePreferred .gitignore for JS/TS projectsgitignore
VS Code ExtensionsRecommended extensions for developmentvscode-extensions
主题说明参考链接
@antfu/eslint-config用于代码检查与格式化的ESLint扁平化配置antfu-eslint-config
GitHub Actions推荐的工作流配置(使用sxzz/workflows)github-actions
.gitignoreJS/TS项目推荐的.gitignore配置gitignore
VS Code Extensions推荐的VS Code扩展vscode-extensions

Development

开发实践参考

TopicDescriptionReference
App DevelopmentPreferences for Vue/Vite/Nuxt/UnoCSS web applicationsapp-development
Library DevelopmentPreferences for bundling and publishing TypeScript librarieslibrary-development
Monorepopnpm workspaces, centralized alias, Turborepomonorepo
主题说明参考链接
应用开发Vue/Vite/Nuxt/UnoCSS Web应用的偏好配置app-development
类库开发TypeScript类库的构建与发布偏好library-development
Monorepo单仓库多项目配置(pnpm workspaces、集中式别名、Turborepo)monorepo