centralized-eslint-prettier
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCentralized ESLint # Centralized ESLint & Prettier Configuration Prettier Configuration
集中式ESLint & Prettier配置
This is a reference pattern. Learn from the approach, adapt to your context — don't copy verbatim.
Problem: Multi-workspace TypeScript projects (frontend, backend, infrastructure) need consistent linting and formatting without duplication, with support for pre-commit hooks and full-repo formatting.
Solution: Single root-level with workspace-specific rules via file patterns, unified Prettier config, and centralized npm scripts with Husky integration.
eslint.config.mjs这是一个参考模式:请学习这种思路,适配你自己的场景,不要直接逐字复制。
问题:多工作区TypeScript项目(前端、后端、基础设施)需要一致的代码检查和格式化能力,同时避免配置重复,还要支持pre-commit钩子和全仓库格式化。
解决方案:根目录下唯一的文件,通过文件模式配置工作区专属规则,统一的Prettier配置,以及集成Husky的集中式npm脚本。
eslint.config.mjsWhy This Pattern?
为什么选择这个模式?
Benefits:
- Single Source of Truth: One config file, no duplication
- Workspace Flexibility: Different rules per workspace via file patterns
- Simplified Maintenance: Update rules in one place
- Consistent Pre-commit: Same hooks across all workspaces
- Easy CI/CD: Single command lints entire codebase
- Project Agnostic: Works for any TypeScript monorepo structure
Use Cases:
- Multi-workspace TypeScript projects (Next.js + CDK, Nuxt + Node.js, etc.)
- Projects with different linting needs per workspace (frontend vs CLI vs Lambda)
- Teams wanting consistent code style without per-workspace configuration
- Projects needing both pre-commit hooks and full-repo formatting
优势:
- 唯一可信源:一份配置文件,无重复
- 工作区灵活性:通过文件模式为不同工作区配置不同规则
- 简化维护:只需在一处更新规则
- 一致的Pre-commit能力:所有工作区使用相同的钩子
- 简单的CI/CD集成:单个命令即可检查整个代码库
- 项目无关性:适用于任何TypeScript monorepo结构
适用场景:
- 多工作区TypeScript项目(Next.js + CDK、Nuxt + Node.js等)
- 不同工作区有不同代码检查需求的项目(前端、CLI、Lambda之间的差异)
- 希望无需为每个工作区单独配置就能实现统一代码风格的团队
- 同时需要pre-commit钩子和全仓库格式化能力的项目
Pattern
模式结构
Architecture:
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.jsonKey Components:
- Root ESLint Config: Flat config (ESLint 9+) with file pattern-based rules
- Workspace-Specific Rules: Different rules for frontend/backend/CLI via glob patterns
- Prettier Integration: Single for all workspaces
.prettierrc - Husky + lint-staged: Pre-commit formatting on changed files
- Centralized Scripts: All lint/format commands in root
package.json
架构:
project-root/
├── eslint.config.mjs # 唯一可信源
├── .prettierrc # 统一格式化规则
├── package.json # 仅根目录存放脚本
├── .husky/pre-commit # Git钩子
├── pnpm-workspace.yaml
├── frontend/
│ ├── package.json # 不存放检查相关脚本
│ └── tsconfig.json
└── infrastructure/
├── package.json # 不存放检查相关脚本
└── tsconfig.json核心组件:
- 根目录ESLint配置:采用ESLint 9+的扁平配置,基于文件模式配置规则
- 工作区专属规则:通过glob模式为前端/后端/CLI配置不同规则
- Prettier集成:所有工作区共用唯一的配置
.prettierrc - Husky + lint-staged:pre-commit阶段自动格式化变更文件
- 集中式脚本:所有检查/格式化命令都存放在根目录中
package.json
Implementation
实现步骤
1. Root ESLint Config (eslint.config.mjs
)
eslint.config.mjs1. 根目录ESLint配置(eslint.config.mjs
)
eslint.config.mjsjavascript
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' }
}
];javascript
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 [
// 全局忽略规则
{ ignores: IGNORE_PATTERNS },
// 前端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'
}
},
// 基础设施层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脚本 - 允许控制台输出
{
files: [
'infrastructure/lib/cli/**/*.ts',
'scripts/**/*.ts'
],
rules: { 'no-console': 'off' }
}
];2. Prettier Config (.prettierrc
)
.prettierrc2. Prettier配置(.prettierrc
)
.prettierrcjson
{
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"endOfLine": "auto"
}json
{
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"endOfLine": "auto"
}3. Root Package.json Scripts
3. 根目录Package.json脚本
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"
]
}
}Critical: Workspace files should NOT have lint/format scripts.
package.jsonjson
{
"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.json4. Husky Pre-commit Hook
4. Husky Pre-commit钩子
bash
undefinedbash
undefined.husky/pre-commit
.husky/pre-commit
pnpm exec lint-staged
undefinedpnpm exec lint-staged
undefined5. Dependencies
5. 依赖安装
bash
pnpm add -D -w eslint \
@typescript-eslint/parser \
@typescript-eslint/eslint-plugin \
typescript-eslint \
@eslint/js \
globals \
prettier \
eslint-config-prettier \
husky \
lint-stagedbash
pnpm add -D -w eslint \
@typescript-eslint/parser \
@typescript-eslint/eslint-plugin \
typescript-eslint \
@eslint/js \
globals \
prettier \
eslint-config-prettier \
husky \
lint-stagedFramework-Specific Variations
框架专属变体
Next.js Frontend
Next.js前端
javascript
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') }
}
}javascript
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 Frontend (Auto-generated Config)
Nuxt.js前端(自动生成配置)
Nuxt auto-generates . Keep it and extend:
.nuxt/eslint.config.mjsjavascript
// frontend/eslint.config.mjs
import withNuxt from './.nuxt/eslint.config.mjs';
import { SHARED_RULES } from '../eslint.shared.mjs';
export default withNuxt({
rules: { ...SHARED_RULES }
});Note: For Nuxt, keep the workspace-level config due to auto-generation. Create at root to share rules.
eslint.shared.mjsNuxt会自动生成,保留该文件并扩展即可:
.nuxt/eslint.config.mjsjavascript
// 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.mjsLambda Functions
Lambda函数
javascript
{
files: ['infrastructure/lib/lambdas/**/*.ts'],
rules: {
'no-console': 'off', // CloudWatch logs
'@typescript-eslint/no-explicit-any': 'error'
}
}javascript
{
files: ['infrastructure/lib/lambdas/**/*.ts'],
rules: {
'no-console': 'off', // 适配CloudWatch日志需求
'@typescript-eslint/no-explicit-any': 'error'
}
}Workspace-Specific Patterns
工作区专属模式
Two-Tier CLI (Simple Projects)
两层CLI(简单项目)
javascript
{
files: ['scripts/**/*.ts', 'tools/**/*.ts'],
rules: { 'no-console': 'off' }
}javascript
{
files: ['scripts/**/*.ts', 'tools/**/*.ts'],
rules: { 'no-console': 'off' }
}Three-Tier CLI (Infrastructure Projects)
三层CLI(基础设施项目)
javascript
// 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' }
}javascript
// 第一层:CLI二进制文件
{
files: ['infrastructure/lib/cli/bin/**/*.ts'],
rules: { 'no-console': 'off' }
},
// 第二层:命令逻辑
{
files: ['infrastructure/lib/cli/commands/**/*.ts'],
rules: { 'no-console': 'off' }
},
// 第三层:领域逻辑
{
files: ['infrastructure/core/**/*.ts'],
rules: { 'no-console': 'warn' }
}Usage
使用方式
Pre-commit (Automatic)
Pre-commit(自动执行)
bash
git add .
git commit -m "feat: add feature"bash
git add .
git commit -m "feat: add feature"Automatically runs lint-staged on changed files
自动在变更文件上执行lint-staged
undefinedundefinedFull Repo Formatting
全仓库格式化
bash
undefinedbash
undefinedCheck formatting
检查格式化合规性
pnpm format:check
pnpm format:check
Fix all files
修复所有文件的格式问题
pnpm format
pnpm format
Lint entire codebase
检查整个代码库的代码规范
pnpm lint
pnpm lint
Auto-fix linting issues
自动修复可解决的代码规范问题
pnpm lint:fix
undefinedpnpm lint:fix
undefinedCI/CD Integration
CI/CD集成
yaml
undefinedyaml
undefinedGitHub Actions
GitHub Actions
- run: pnpm install --frozen-lockfile
- run: pnpm lint
- run: pnpm format:check
---- run: pnpm install --frozen-lockfile
- run: pnpm lint
- run: pnpm format:check
---Tradeoffs
权衡说明
ESLint 9+ Flat Config Required
要求使用ESLint 9+扁平配置
Constraint: This pattern uses ESLint 9+ flat config format ( file).
.mjsWhy: Flat config is the future of ESLint and provides better TypeScript support.
Migration: Old configs need conversion. See ESLint migration guide.
.eslintrc.js约束:该模式使用ESLint 9+的扁平配置格式(文件)。
.mjs原因:扁平配置是ESLint的未来方向,对TypeScript的支持更好。
迁移方案:旧的配置需要转换,可参考ESLint迁移指南。
.eslintrc.jsFile Pattern Ordering Matters
文件模式的顺序很重要
Constraint: More specific patterns must come after general ones.
Example:
javascript
// ✅ 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: {...} }约束:更具体的模式必须放在通用模式之后。
示例:
javascript
// ✅ 正确顺序
{ files: ['**/*.ts'], rules: {...} },
{ files: ['frontend/**/*.ts'], rules: {...} },
{ files: ['frontend/lib/cli/**/*.ts'], rules: {...} }
// ❌ 错误顺序 - 特定规则不会生效
{ files: ['frontend/lib/cli/**/*.ts'], rules: {...} },
{ files: ['**/*.ts'], rules: {...} }Nuxt.js Exception
Nuxt.js例外情况
Constraint: Nuxt auto-generates ESLint config, requiring workspace-level config.
Solution: Keep but import shared rules from root via .
frontend/eslint.config.mjseslint.shared.mjs约束:Nuxt会自动生成ESLint配置,需要保留工作区级别的配置。
解决方案:保留,但通过从根目录导入共享规则。
frontend/eslint.config.mjseslint.shared.mjsWhen NOT to Use
不适用场景
- Single-workspace projects: Simpler to use workspace-level config
- Non-TypeScript projects: Pattern is TypeScript-focused (though adaptable)
- Legacy ESLint versions: Requires ESLint 9+ for flat config
- Highly divergent workspace needs: If workspaces need completely different tooling, separate configs may be clearer
- 单工作区项目:直接使用工作区级别的配置更简单
- 非TypeScript项目:该模式聚焦于TypeScript场景(不过也可适配)
- 旧版本ESLint:需要ESLint 9+才能支持扁平配置
- 工作区需求差异极大的项目:如果各工作区需要完全不同的工具链,使用独立配置会更清晰
Verification Checklist
验证检查清单
After setup:
bash
undefined配置完成后:
bash
undefined1. Full codebase linting works
1. 全代码库检查正常运行
pnpm lint
pnpm lint
2. Auto-fix works
2. 自动修复功能正常
pnpm lint:fix
pnpm lint:fix
3. Formatting works
3. 格式化功能正常
pnpm format
pnpm format
4. Pre-commit hooks work
4. Pre-commit钩子正常工作
git add . && git commit -m "test"
git add . && git commit -m "test"
5. No duplicate scripts in workspaces
5. 工作区无重复脚本
grep -r '"lint":' */package.json
grep -r '"lint":' */package.json
Should ONLY show root package.json
应该只在根目录package.json中匹配到结果
---
---Related Patterns
相关模式
- CLI Architecture - Understanding CLI tiers for console.log rules
- Environment Validation - Fail-fast validation patterns
- CLI架构 - 了解CLI分层逻辑,合理配置console.log规则
- 环境校验 - 快速失败的校验模式
Progressive Improvement
持续优化
If the developer corrects a behavior that this skill should have prevented, suggest a specific amendment to this skill to prevent the same correction in the future.
如果开发者修正了本技能本应避免的问题,请针对本技能提出具体的修改建议,避免后续再出现同类问题。