关于 centralized-eslint-prettier
centralized-eslint-prettier 是面向多工作区 TypeScript 项目的配置参考模式,适用于希望统一代码检查与格式化的团队。它以根目录配置集中规则和脚本,并按文件模式区分各工作区需求。
主要功能
- 01使用根目录 ESLint 扁平配置
- 02按文件模式应用工作区规则
- 03统一 Prettier 格式配置
- 04通过 Husky 与 lint-staged 运行提交前检查
- 05在根目录集中管理检查和格式化脚本
适用场景
- 01统一前端、后端和基础设施代码风格
- 02为不同工作区配置不同 lint 规则
- 03提交前格式化已更改文件
- 04通过单一命令检查整个代码库
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ loxosceles-dev/ dev-skills --skill centralized-eslint-prettier安装后在 Claude Code 中输入/centralized-eslint-prettier确认已加载。
详细介绍
集中式 ESLint 和 Prettier 配置
这是一个参考模式。 了解其做法,并根据你的情况调整——不要原样照搬。
问题:多工作区 TypeScript 项目(前端、后端、基础设施)需要统一的代码检查和格式化,避免重复配置,并支持提交前钩子和全仓库格式化。
解决方案:在根目录使用单个 eslint.config.mjs,通过文件模式设置工作区专属规则,统一 Prettier 配置,并通过 Husky 集中管理 npm 脚本。
为什么使用此模式?
优点:
- 单一事实来源:只有一个配置文件,无重复内容
- 工作区灵活性:通过文件模式为不同工作区设置不同规则
- 维护更简单:只需在一处更新规则
- 统一的提交前检查:所有工作区使用相同的钩子
- 易于 CI/CD 集成:一条命令即可检查整个代码库
- 与项目无关:适用于任何 TypeScript 单体仓库结构
适用场景:
- 多工作区 TypeScript 项目(Next.js + CDK、Nuxt + Node.js 等)
- 不同工作区有不同代码检查需求的项目(前端、CLI 和 Lambda)
- 希望统一代码风格,避免为每个工作区单独配置的团队
- 既需要提交前钩子,也需要全仓库格式化的项目
模式
架构:
project-root/
├── eslint.config.mjs # Single source of truth
├── .prettierrc # Unified formatting rules
├── package.json # Root scripts only
├── .husky/pre-commit # Git hooks
├── pnpm-workspace.yaml
├── frontend/
│ ├── package.json # NO lint scripts
│ └── tsconfig.json
└── infrastructure/
├── package.json # NO lint scripts
└── tsconfig.json
关键组件:
- 根目录 ESLint 配置:使用扁平配置(ESLint 9+),并基于文件模式设置规则
- 工作区专属规则:通过 glob 模式为前端、后端和 CLI 设置不同规则
- Prettier 集成:所有工作区共用单个
.prettierrc - Husky + lint-staged:提交前格式化已更改的文件
- 集中式脚本:在根目录
package.json中定义所有 lint/format 命令
实施
1. 根目录 ESLint 配置(eslint.config.mjs)
import js from '@eslint/js';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import typescriptParser from '@typescript-eslint/parser';
import globals from 'globals';
import { fileURLToPath } from 'node:url';
import path from 'node:path';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const IGNORE_PATTERNS = [
'**/node_modules/**',
'**/dist/**',
'**/build/**',
'**/.next/**',
'**/cdk.out/**',
'**/*.d.ts',
'**/*.config.js'
];
const SHARED_RULES = {
'eol-last': ['error', 'always'],
'no-console': ['warn', { allow: ['error', 'warn'] }],
'no-unused-vars': 'off'
};
export default [
// Global ignores
{ ignores: IGNORE_PATTERNS },
// Frontend TypeScript
{
files: ['frontend/**/*.{ts,tsx}'],
languageOptions: {
parser: typescriptParser,
parserOptions: {
project: path.join(__dirname, 'frontend/tsconfig.json'),
ecmaVersion: 'latest',
sourceType: 'module'
}
},
plugins: { '@typescript-eslint': typescriptEslint },
rules: {
...SHARED_RULES,
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/no-explicit-any': 'error'
}
},
// Infrastructure TypeScript
{
files: ['infrastructure/**/*.ts'],
languageOptions: {
parser: typescriptParser,
parserOptions: {
project: path.join(__dirname, 'infrastructure/tsconfig.json'),
ecmaVersion: 'latest',
sourceType: 'module'
}
},
plugins: { '@typescript-eslint': typescriptEslint },
rules: {
...SHARED_RULES,
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/no-explicit-any': 'error'
}
},
// CLI scripts - allow console output
{
files: [
'infrastructure/lib/cli/**/*.ts',
'scripts/**/*.ts'
],
rules: { 'no-console': 'off' }
}
];
2. Prettier 配置(.prettierrc)
{
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"endOfLine": "auto"
}
3. 根目录 Package.json 脚本
{
"scripts": {
"lint": "eslint . --ext .ts,.tsx,.js,.jsx",
"lint:fix": "eslint . --ext .ts,.tsx,.js,.jsx --fix",
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
"format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,md}\"",
"prepare": "husky"
},
"lint-staged": {
"**/*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write --end-of-line auto"
],
"*.{json,md,yml}": [
"prettier --write --end-of-line auto"
]
}
}
重要:工作区的 package.json 文件中不应包含 lint/format 脚本。
4. Husky 提交前钩子
# .husky/pre-commit
pnpm exec lint-staged
5. 依赖项
pnpm add -D -w eslint \
@typescript-eslint/parser \
@typescript-eslint/eslint-plugin \
typescript-eslint \
@eslint/js \
globals \
prettier \
eslint-config-prettier \
husky \
lint-staged
特定框架的变体
Next.js 前端
import nextPlugin from '@next/eslint-plugin-next';
{
files: ['frontend/**/*.{ts,tsx}'],
plugins: {
'@next/next': nextPlugin,
'@typescript-eslint': typescriptEslint
},
settings: {
next: { rootDir: path.join(__dirname, 'frontend') }
}
}
Nuxt.js 前端(自动生成的配置)
Nuxt 会自动生成 .nuxt/eslint.config.mjs。保留该文件并扩展:
// frontend/eslint.config.mjs
import withNuxt from './.nuxt/eslint.config.mjs';
import { SHARED_RULES } from '../eslint.shared.mjs';
export default withNuxt({
rules: { ...SHARED_RULES }
});
注意:对于 Nuxt,由于配置是自动生成的,请保留工作区级配置。在根目录创建 eslint.shared.mjs 以共享规则。
Lambda 函数
{
files: ['infrastructure/lib/lambdas/**/*.ts'],
rules: {
'no-console': 'off', // CloudWatch logs
'@typescript-eslint/no-explicit-any': 'error'
}
}
工作区专属模式
两层 CLI(简单项目)
{
files: ['scripts/**/*.ts', 'tools/**/*.ts'],
rules: { 'no-console': 'off' }
}
三层 CLI(基础设施项目)
// Tier 1: CLI Binaries
{
files: ['infrastructure/lib/cli/bin/**/*.ts'],
rules: { 'no-console': 'off' }
},
// Tier 2: Commands
{
files: ['infrastructure/lib/cli/commands/**/*.ts'],
rules: { 'no-console': 'off' }
},
// Tier 3: Domain Logic
{
files: ['infrastructure/core/**/*.ts'],
rules: { 'no-console': 'warn' }
}
用法
提交前(自动)
git add .
git commit -m "feat: add feature"
# Automatically runs lint-staged on changed files
全仓库格式化
# Check formatting
pnpm format:check
# Fix all files
pnpm format
# Lint entire codebase
pnpm lint
# Auto-fix linting issues
pnpm lint:fix
CI/CD 集成
# GitHub Actions
- run: pnpm install --frozen-lockfile
- run: pnpm lint
- run: pnpm format:check
权衡
需要 ESLint 9+ 扁平配置
限制:此模式使用 ESLint 9+ 扁平配置格式(.mjs 文件)。
原因:扁平配置是 ESLint 的发展方向,并能更好地支持 TypeScript。
迁移:旧的 .eslintrc.js 配置需要转换。请参阅 ESLint 迁移指南。
文件模式的顺序很重要
限制:更具体的模式必须放在通用模式之后。
示例:
// ✅ Correct order
{ files: ['**/*.ts'], rules: {...} },
{ files: ['frontend/**/*.ts'], rules: {...} },
{ files: ['frontend/lib/cli/**/*.ts'], rules: {...} }
// ❌ Wrong order - specific rules won't apply
{ files: ['frontend/lib/cli/**/*.ts'], rules: {...} },
{ files: ['**/*.ts'], rules: {...} }
Nuxt.js 例外
限制:Nuxt 会自动生成 ESLint 配置,因此需要工作区级配置。
解决方案:保留 frontend/eslint.config.mjs,并通过 eslint.shared.mjs 从根目录导入共享规则。
不适用场景
- 单工作区项目:使用工作区级配置更简单
- 非 TypeScript 项目:此模式主要面向 TypeScript(但可调整)
- 旧版 ESLint:扁平配置需要 ESLint 9+
- 工作区需求差异很大:如果各工作区需要完全不同的工具,使用独立配置可能更清晰
验证清单
完成设置后:
# 1. Full codebase linting works
pnpm lint
# 2. Auto-fix works
pnpm lint:fix
# 3. Formatting works
pnpm format
# 4. Pre-commit hooks work
git add . && git commit -m "test"
# 5. No duplicate scripts in workspaces
grep -r '"lint":' */package.json
# Should ONLY show root package.json
相关模式
渐进式改进
如果开发者纠正了此技能本应避免的行为,请建议对此技能进行具体修订,以避免今后出现相同的纠正。