hookehuyr

feat: 配置代码质量工具链

添加 ESLint、Prettier、Husky 和 lint-staged 以自动化代码检查和格式化
新增 .prettierrc、.prettierignore、eslint.config.js 和 Husky pre-commit hook
在 package.json 中添加相关脚本和依赖,包括格式化、检查、测试覆盖率等命令
新增详细配置文档 HUSKY_LINT_STAGED.md 和 ESLINT_PRETTIER.md
1 +#!/usr/bin/env sh
2 +. "$(dirname "$0")/_/husky.sh"
3 +
4 +npx lint-staged
1 +# 依赖
2 +node_modules/
3 +dist/
4 +dist.*/
5 +build/
6 +
7 +# 配置文件
8 +package-lock.json
9 +pnpm-lock.yaml
10 +yarn.lock
11 +
12 +# 自动生成
13 +src/auto-imports.d.ts
14 +src/components.d.ts
15 +src/typings/env.d.ts
16 +.eslintrc-auto-import.json
17 +
18 +# 静态资源
19 +public/
20 +**/*.svg
21 +**/*.png
22 +**/*.jpg
23 +**/*.jpeg
24 +**/*.gif
25 +**/*.ico
26 +
27 +# 其他
28 +.cursor/
29 +coverage/
30 +.nyc_output/
31 +*.min.js
32 +*.min.css
33 +
34 +# 文档
35 +CHANGELOG.md
36 +LICENSE
37 +VITE*.md
38 +
39 +# 临时文件
40 +*.log
41 +*.tmp
42 +*.temp
43 +.DS_Store
1 +{
2 + "semi": false,
3 + "singleQuote": true,
4 + "quoteProps": "as-needed",
5 + "trailingComma": "es5",
6 + "bracketSpacing": true,
7 + "bracketSameLine": false,
8 + "arrowParens": "avoid",
9 + "printWidth": 100,
10 + "tabWidth": 2,
11 + "useTabs": false,
12 + "endOfLine": "lf",
13 + "plugins": ["prettier-plugin-tailwindcss"],
14 + "overrides": [
15 + {
16 + "files": "*.vue",
17 + "options": {
18 + "parser": "vue"
19 + }
20 + },
21 + {
22 + "files": "*.md",
23 + "options": {
24 + "proseWrap": "preserve"
25 + }
26 + }
27 + ]
28 +}
1 +# ESLint + Prettier 配置说明
2 +
3 +## ✅ 已安装的包
4 +
5 +```json
6 +{
7 + "devDependencies": {
8 + "eslint": "^9.39.2",
9 + "eslint-plugin-vue": "^10.7.0",
10 + "eslint-config-prettier": "^10.1.8",
11 + "@vue/eslint-config-prettier": "^10.2.0",
12 + "prettier": "^3.8.1",
13 + "prettier-plugin-tailwindcss": "^0.7.2"
14 + }
15 +}
16 +```
17 +
18 +## 📁 配置文件
19 +
20 +### ESLint 配置
21 +
22 +**文件**: `eslint.config.js` (ESLint 9 扁平配置格式)
23 +
24 +**核心规则**:
25 +
26 +- Vue 3 规则(组件命名、props 检查、模板规范)
27 +- JavaScript 规则(no-var、prefer-const、箭头函数)
28 +- 代码质量(===、错误处理、安全)
29 +- 性能优化(避免循环中的函数、禁止 eval)
30 +
31 +**忽略文件**:
32 +
33 +```javascript
34 +ignores: [
35 + 'node_modules/**',
36 + 'dist/**',
37 + 'dist.*',
38 + 'build/**',
39 + '*.min.js',
40 + 'public/**',
41 + 'VITE*.md',
42 + '.cursor/**',
43 + '.history/**',
44 + 'coverage/**',
45 + '.nyc_output/**',
46 + 'src/auto-imports.d.ts',
47 + 'src/components.d.ts',
48 + 'mlaj/**',
49 +]
50 +```
51 +
52 +### Prettier 配置
53 +
54 +**文件**: `.prettierrc`
55 +
56 +**核心配置**:
57 +
58 +```json
59 +{
60 + "semi": false, // 不使用分号
61 + "singleQuote": true, // 使用单引号
62 + "trailingComma": "es5", // ES5 尾部逗号
63 + "printWidth": 100, // 每行最大 100 字符
64 + "tabWidth": 2, // 2 空格缩进
65 + "useTabs": false, // 使用空格而非 tab
66 + "endOfLine": "lf" // LF 换行符
67 +}
68 +```
69 +
70 +**忽略文件**:
71 +
72 +- `node_modules/`
73 +- `dist/`
74 +- `build/`
75 +- `public/`
76 +- `coverage/`
77 +- `*.min.js`
78 +- `package-lock.json`
79 +- `pnpm-lock.yaml`
80 +
81 +### VS Code 配置
82 +
83 +**文件**: `.vscode/settings.json`
84 +
85 +**自动格式化**:
86 +
87 +```json
88 +{
89 + "editor.formatOnSave": true,
90 + "editor.codeActionsOnSave": {
91 + "source.fixAll.eslint": "explicit"
92 + },
93 + "editor.defaultFormatter": "esbenp.prettier-vscode"
94 +}
95 +```
96 +
97 +**推荐扩展** (`.vscode/extensions.json`):
98 +
99 +- `Vue.volar` - Vue 3 语言支持
100 +- `dbaeumer.vscode-eslint` - ESLint 集成
101 +- `esbenp.prettier-vscode` - Prettier 格式化
102 +- `bradlc.vscode-tailwindcss` - TailwindCSS 智能提示
103 +- `formulahendry.auto-rename-tag` - 自动重命名标签
104 +- `christian-kohler.path-intellisense` - 路径智能提示
105 +
106 +## 🚀 使用命令
107 +
108 +### Lint(代码检查)
109 +
110 +```bash
111 +# 检查但不修复
112 +pnpm lint:check
113 +
114 +# 检查并自动修复
115 +pnpm lint
116 +```
117 +
118 +### Format(代码格式化)
119 +
120 +```bash
121 +# 检查格式(不修改文件)
122 +pnpm format:check
123 +
124 +# 格式化代码
125 +pnpm format
126 +```
127 +
128 +### 组合使用
129 +
130 +```bash
131 +# 先格式化,再 lint
132 +pnpm format && pnpm lint
133 +
134 +# 提交前检查
135 +pnpm format:check && pnpm lint:check && pnpm test
136 +```
137 +
138 +## 📋 ESLint 核心规则
139 +
140 +### Vue 3 规则
141 +
142 +| 规则 | 级别 | 说明 |
143 +| -------------------------------------- | ----- | ------------------ |
144 +| `vue/multi-word-component-names` | off | 允许单词组件名 |
145 +| `vue/no-v-html` | warn | 警告使用 v-html |
146 +| `vue/require-prop-types` | error | props 必须有类型 |
147 +| `vue/no-mutating-props` | error | 禁止直接修改 props |
148 +| `vue/component-definition-name-casing` | error | 组件名 PascalCase |
149 +
150 +### JavaScript 规则
151 +
152 +| 规则 | 级别 | 说明 |
153 +| ------------------ | ----- | ----------------------------------- |
154 +| `no-console` | warn | 禁止 console.log(允许 warn/error) |
155 +| `no-debugger` | error | 禁止 debugger |
156 +| `no-var` | error | 禁止 var,使用 const/let |
157 +| `prefer-const` | error | 优先使用 const |
158 +| `eqeqeq` | error | 强制使用 === |
159 +| `no-eval` | error | 禁止 eval |
160 +| `no-throw-literal` | error | throw 必须是 Error 对象 |
161 +
162 +## 🔧 常见问题
163 +
164 +### 1. ESLint 报错但不显示具体规则
165 +
166 +**解决**: 确保 `eslint.config.js` 配置正确
167 +
168 +### 2. Prettier 与 ESLint 冲突
169 +
170 +**解决**: `eslint-config-prettier` 已禁用所有与 Prettier 冲突的规则
171 +
172 +### 3. VS Code 不自动格式化
173 +
174 +**解决**:
175 +
176 +1. 确保安装了 `Prettier - Code formatter` 扩展
177 +2. 检查 `.vscode/settings.json` 中的配置
178 +3. 重启 VS Code
179 +
180 +### 4. 忽略特定文件
181 +
182 +**ESLint 9**: 在 `eslint.config.js``ignores` 中添加
183 +
184 +**Prettier**: 在 `.prettierignore` 中添加
185 +
186 +## 📝 提交前检查
187 +
188 +在提交代码前,请运行:
189 +
190 +```bash
191 +# 1. 格式化代码
192 +pnpm format
193 +
194 +# 2. 检查代码规范
195 +pnpm lint:check
196 +
197 +# 3. 运行测试
198 +pnpm test
199 +
200 +# 4. 检查测试覆盖率
201 +pnpm test:coverage
202 +```
203 +
204 +## 🎯 最佳实践
205 +
206 +### 1. 开发流程
207 +
208 +```bash
209 +# 1. 编写代码
210 +# 2. 保存时自动格式化(VS Code 自动)
211 +# 3. 手动运行 lint 检查
212 +pnpm lint:check
213 +
214 +# 4. 修复错误
215 +pnpm lint
216 +
217 +# 5. 提交代码
218 +git add .
219 +git commit -m "feat: xxx"
220 +```
221 +
222 +### 2. Git Hooks(可选)
223 +
224 +使用 `husky``lint-staged` 自动化:
225 +
226 +```bash
227 +# 安装
228 +pnpm add -D husky lint-staged
229 +
230 +# 配置
231 +npx husky install
232 +npx husky add .husky/pre-commit "pnpm lint-staged"
233 +```
234 +
235 +**`package.json`**:
236 +
237 +```json
238 +{
239 + "lint-staged": {
240 + "*.{js,vue}": ["eslint --fix", "prettier --write"]
241 + }
242 +}
243 +```
244 +
245 +### 3. CI/CD 集成
246 +
247 +在 CI 中运行:
248 +
249 +```yaml
250 +# .github/workflows/ci.yml
251 +- name: Lint
252 + run: pnpm lint:check
253 +
254 +- name: Format check
255 + run: pnpm format:check
256 +
257 +- name: Test
258 + run: pnpm test
259 +```
260 +
261 +## 📊 规则优先级
262 +
263 +```
264 +ESLint 规则 > Prettier 规则
265 +
266 +1. Prettier 负责格式化(空格、引号、换行)
267 +2. ESLint 负责代码质量(未使用变量、潜在错误)
268 +3. eslint-config-prettier 禁用冲突的 ESLint 规则
269 +```
270 +
271 +## 🔄 迁移指南
272 +
273 +### 从旧版 ESLint 迁移
274 +
275 +如果你之前使用 `.eslintrc.js`
276 +
277 +```bash
278 +# 1. 删除旧配置
279 +rm .eslintrc.js
280 +
281 +# 2. 使用新的 eslint.config.js(已配置)
282 +# 3. 删除 .eslintignore(ESLint 9 不再使用)
283 +```
284 +
285 +### 从旧版 Prettier 迁移
286 +
287 +如果你之前使用 `.prettierrc.js`
288 +
289 +```bash
290 +# 1. 转换为 .prettierrc(JSON 格式)
291 +# 2. 确保 prettier-plugin-tailwindcss 已安装
292 +```
293 +
294 +## 🚨 注意事项
295 +
296 +1. **不要修改 `node_modules/` 中的文件** - ESLint 会忽略它们
297 +2. **不要提交格式化后的构建产物** - `dist/``build/` 已被忽略
298 +3. **团队统一配置** - 确保所有成员使用相同的配置文件
299 +4. **定期更新依赖** - ESLint 和 Prettier 会定期更新
300 +
301 +## 📚 参考资源
302 +
303 +- [ESLint 9 文档](https://eslint.org/docs/latest/)
304 +- [Vue 3 官方 ESLint 插件](https://eslint.vuejs.org/)
305 +- [Prettier 文档](https://prettier.io/docs/en/)
306 +- [Prettier TailwindCSS 插件](https://github.com/tailwindlabs/prettier-plugin-tailwindcss)
307 +
308 +## 🎉 完成
309 +
310 +你的项目现在已经配置了完整的 ESLint 和 Prettier!
311 +
312 +**下一步**:
313 +
314 +- [ ] 添加 Husky + lint-staged(Git Hooks)
315 +- [ ] 添加 Vitest Coverage(测试覆盖率)
316 +- [ ] 添加 Playwright(E2E 测试)
1 +# Husky + lint-staged 配置说明
2 +
3 +## ✅ 配置完成
4 +
5 +你的项目现在已经配置了 **Husky****lint-staged**,在 Git 提交前自动运行代码检查和格式化。
6 +
7 +## 📦 已安装的包
8 +
9 +```json
10 +{
11 + "devDependencies": {
12 + "husky": "^9.1.7",
13 + "lint-staged": "^16.2.7"
14 + }
15 +}
16 +```
17 +
18 +## 🔧 配置文件
19 +
20 +### 1. Husky 配置
21 +
22 +**目录**: `.husky/`
23 +
24 +**文件**:
25 +
26 +- `pre-commit` - 提交前执行的 hook
27 +- `_/husky.sh` - Husky 辅助脚本
28 +
29 +**`pre-commit` 内容**:
30 +
31 +```bash
32 +#!/usr/bin/env sh
33 +. "$(dirname "$0")/_/husky.sh"
34 +
35 +npx lint-staged
36 +```
37 +
38 +### 2. lint-staged 配置
39 +
40 +**位置**: `package.json` 中的 `lint-staged` 字段
41 +
42 +**配置**:
43 +
44 +```json
45 +{
46 + "lint-staged": {
47 + "*.{js,vue}": ["eslint --fix", "prettier --write"],
48 + "*.{css,less,scss}": ["prettier --write"],
49 + "*.{json,md}": ["prettier --write"]
50 + }
51 +}
52 +```
53 +
54 +## 🚀 工作流程
55 +
56 +### 自动化流程
57 +
58 +```
59 +1. git add .
60 +
61 +2. git commit -m "xxx"
62 +
63 +3. Husky 触发 pre-commit hook
64 +
65 +4. lint-staged 检查暂存的文件
66 +
67 +5. ESLint 自动修复问题
68 +
69 +6. Prettier 自动格式化代码
70 +
71 +7. 如果所有检查通过 → 提交成功 ✅
72 + 如果有错误 → 提交失败,显示错误信息 ❌
73 +```
74 +
75 +### 文件类型处理
76 +
77 +| 文件类型 | 操作 |
78 +| --------------------------- | ----------------------------------- |
79 +| `*.js`, `*.vue` | ESLint 检查并修复 + Prettier 格式化 |
80 +| `*.css`, `*.less`, `*.scss` | Prettier 格式化 |
81 +| `*.json`, `*.md` | Prettier 格式化 |
82 +
83 +## 📝 使用示例
84 +
85 +### 正常提交
86 +
87 +```bash
88 +# 1. 修改文件
89 +echo "console.log('test')" >> test.js
90 +
91 +# 2. 添加到暂存区
92 +git add test.js
93 +
94 +# 3. 提交(自动运行 lint-staged)
95 +git commit -m "test: add test file"
96 +
97 +# 输出:
98 +# ✔ prettier --write test.js
99 +# ✔ eslint --fix test.js
100 +# [main xxxxx] test: add test file
101 +```
102 +
103 +### 提交失败(有错误)
104 +
105 +```bash
106 +# 1. 创建有错误的文件
107 +cat > bad.js << 'EOF'
108 +function test() {
109 + var x = 1 // 缺少分号,使用了 var
110 + return x
111 +}
112 +EOF
113 +
114 +# 2. 尝试提交
115 +git add bad.js
116 +git commit -m "test: bad code"
117 +
118 +# 输出:
119 +# ✖ eslint --fix bad.js
120 +# ✖ 1:7 error Unexpected var, use let or const instead no-var
121 +# ✖ 1:18 error Missing semicolon
122 +# husky - pre-commit hook exited with code 1 (error)
123 +```
124 +
125 +### 跳过 Hook(不推荐)
126 +
127 +```bash
128 +# 使用 --no-verify 跳过 hook
129 +git commit --no-verify -m "xxx"
130 +```
131 +
132 +## 🛠️ 调试
133 +
134 +### 测试 lint-staged
135 +
136 +```bash
137 +# 不实际提交,只测试 lint-staged
138 +npx lint-staged
139 +```
140 +
141 +### 查看已安装的 Hooks
142 +
143 +```bash
144 +# 查看所有 Git hooks
145 +ls -la .husky/
146 +
147 +# 查看 pre-commit 内容
148 +cat .husky/pre-commit
149 +```
150 +
151 +### 手动运行 Hook
152 +
153 +```bash
154 +# 手动执行 pre-commit hook
155 +.husky/pre-commit
156 +```
157 +
158 +## 📋 常见问题
159 +
160 +### 1. Hook 不执行
161 +
162 +**检查**:
163 +
164 +```bash
165 +# 1. 检查 .husky 目录是否存在
166 +ls -la .husky/
167 +
168 +# 2. 检查 pre-commit 是否可执行
169 +ls -la .husky/pre-commit
170 +
171 +# 3. 如果不可执行,添加权限
172 +chmod +x .husky/pre-commit
173 +```
174 +
175 +### 2. lint-staged 找不到文件
176 +
177 +**原因**: 文件未被 `git add` 到暂存区
178 +
179 +**解决**:
180 +
181 +```bash
182 +# 确保文件已添加到暂存区
183 +git add your-file.js
184 +
185 +# 检查暂存区文件
186 +git status
187 +```
188 +
189 +### 3. 提交速度慢
190 +
191 +**原因**: lint-staged 检查的文件太多
192 +
193 +**优化**:
194 +
195 +- 缩小 `package.json``lint-staged` 的匹配范围
196 +- 只检查 `src/` 目录
197 +
198 +```json
199 +{
200 + "lint-staged": {
201 + "src/**/*.{js,vue}": ["eslint --fix", "prettier --write"]
202 + }
203 +}
204 +```
205 +
206 +### 4. 想暂时禁用 Hook
207 +
208 +**方法 1** - 跳过单次提交:
209 +
210 +```bash
211 +git commit --no-verify -m "xxx"
212 +```
213 +
214 +**方法 2** - 暂时删除 hook:
215 +
216 +```bash
217 +# 删除 hook
218 +rm .husky/pre-commit
219 +
220 +# 提交后恢复
221 +git checkout .husky/pre-commit
222 +```
223 +
224 +## 🎯 最佳实践
225 +
226 +### 1. 提交前检查
227 +
228 +即使有 Husky,建议提交前也手动检查:
229 +
230 +```bash
231 +# 1. 格式化代码
232 +pnpm format
233 +
234 +# 2. Lint 检查
235 +pnpm lint:check
236 +
237 +# 3. 测试
238 +pnpm test
239 +
240 +# 4. 提交(Husky 会再次检查)
241 +git add .
242 +git commit -m "xxx"
243 +```
244 +
245 +### 2. 团队协作
246 +
247 +**确保团队成员都安装了依赖**:
248 +
249 +```bash
250 +# 克隆项目后
251 +pnpm install
252 +
253 +# Husky 会自动安装(通过 prepare 脚本)
254 +```
255 +
256 +**`package.json` 中的 `prepare` 脚本**:
257 +
258 +```json
259 +{
260 + "scripts": {
261 + "prepare": "husky"
262 + }
263 +}
264 +```
265 +
266 +这确保了每次 `pnpm install` 后都会自动安装 Husky hooks。
267 +
268 +### 3. CI/CD 集成
269 +
270 +在 CI 中可以跳过 Husky(因为 CI 环境不使用 Git hooks):
271 +
272 +```yaml
273 +# .github/workflows/ci.yml
274 +- name: Lint and format
275 + run: |
276 + pnpm lint:check
277 + pnpm format:check
278 +```
279 +
280 +## 🔄 更新配置
281 +
282 +### 添加新的 Hook
283 +
284 +```bash
285 +# 创建 commit-msg hook(检查提交信息)
286 +cat > .husky/commit-msg << 'EOF'
287 +#!/usr/bin/env sh
288 +. "$(dirname "$0")/_/husky.sh"
289 +
290 +npx commitlint --edit $1
291 +EOF
292 +
293 +chmod +x .husky/commit-msg
294 +```
295 +
296 +### 修改 lint-staged 配置
297 +
298 +编辑 `package.json` 中的 `lint-staged` 字段:
299 +
300 +```json
301 +{
302 + "lint-staged": {
303 + "src/**/*.{js,vue}": ["eslint --fix", "prettier --write"],
304 + "src/**/*.{css,less}": ["prettier --write"],
305 + "*.md": ["prettier --write", "markdownlint --fix"]
306 + }
307 +}
308 +```
309 +
310 +### 添加测试到 Hook
311 +
312 +编辑 `.husky/pre-commit`:
313 +
314 +```bash
315 +#!/usr/bin/env sh
316 +. "$(dirname "$0")/_/husky.sh"
317 +
318 +# 运行 lint-staged
319 +npx lint-staged
320 +
321 +# 运行测试(可选)
322 +pnpm test
323 +```
324 +
325 +## 📚 参考资源
326 +
327 +- [Husky 官方文档](https://typicode.github.io/husky/)
328 +- [lint-staged 官方文档](https://github.com/okonet/lint-staged)
329 +- [Git Hooks 文档](https://git-scm.com/docs/githooks)
330 +
331 +## 🎉 总结
332 +
333 +**优势**:
334 +
335 +- ✅ 自动化代码质量检查
336 +- ✅ 保持代码风格一致
337 +- ✅ 防止低质量代码进入仓库
338 +- ✅ 节省手动检查时间
339 +- ✅ 团队协作更高效
340 +
341 +**注意事项**:
342 +
343 +- ⚠️ Hook 只在本地执行,不会影响已经推送的代码
344 +- ⚠️ 可以使用 `--no-verify` 跳过(不推荐)
345 +- ⚠️ CI/CD 中应该单独运行检查(不依赖 Hook)
346 +
347 +**下一步**:
348 +
349 +- [ ] 添加 commitlint(提交信息规范)
350 +- [ ] 添加更多 Git hooks(commit-msg、pre-push)
351 +- [ ] 配置 CI/CD 中的质量检查
352 +
353 +享受自动化的 Git 工作流!🚀
1 +/*
2 + * @Date: 2026-01-28 20:45:00
3 + * @Description: ESLint 配置 - 使用 ESLint 9 扁平配置格式
4 + */
5 +import vue from 'eslint-plugin-vue'
6 +import prettier from 'eslint-config-prettier'
7 +
8 +export default [
9 + {
10 + // 忽略文件
11 + ignores: [
12 + 'node_modules/**',
13 + 'dist/**',
14 + 'dist.*',
15 + 'build/**',
16 + '*.min.js',
17 + 'public/**',
18 + 'VITE*.md',
19 + '.cursor/**',
20 + '.history/**',
21 + 'coverage/**',
22 + '.nyc_output/**',
23 + 'src/auto-imports.d.ts',
24 + 'src/components.d.ts',
25 + 'mlaj/**',
26 + ],
27 + },
28 +
29 + // JavaScript / Vue 文件配置
30 + {
31 + files: ['**/*.{js,mjs,cjs,vue}'],
32 + languageOptions: {
33 + ecmaVersion: 'latest',
34 + sourceType: 'module',
35 + globals: {
36 + // 浏览器环境
37 + window: 'readonly',
38 + document: 'readonly',
39 + navigator: 'readonly',
40 + localStorage: 'readonly',
41 + sessionStorage: 'readonly',
42 + history: 'readonly',
43 + location: 'readonly',
44 + fetch: 'readonly',
45 + URL: 'readonly',
46 + XMLHttpRequest: 'readonly',
47 + WebSocket: 'readonly',
48 + HTMLElement: 'readonly',
49 + customElements: 'readonly',
50 +
51 + // 微信环境
52 + wx: 'readonly',
53 + WeixinJSBridge: 'readonly',
54 +
55 + // Node.js 环境
56 + process: 'readonly',
57 + Buffer: 'readonly',
58 + __dirname: 'readonly',
59 + __filename: 'readonly',
60 + module: 'readonly',
61 + require: 'readonly',
62 + exports: 'readonly',
63 +
64 + // Vitest 测试环境
65 + describe: 'readonly',
66 + it: 'readonly',
67 + test: 'readonly',
68 + expect: 'readonly',
69 + vi: 'readonly',
70 + beforeEach: 'readonly',
71 + afterEach: 'readonly',
72 + beforeAll: 'readonly',
73 + afterAll: 'readonly',
74 + },
75 + },
76 + plugins: {
77 + vue,
78 + },
79 + rules: {
80 + // Vue 3 规则
81 + 'vue/multi-word-component-names': 'off', // 允许单词组件名
82 + 'vue/no-v-html': 'warn', // v-html 需谨慎使用
83 + 'vue/require-default-prop': 'off', // props 不强制默认值
84 + 'vue/require-prop-types': 'error', // props 必须有类型
85 + 'vue/no-mutating-props': 'error', // 禁止直接修改 props
86 + 'vue/component-definition-name-casing': ['error', 'PascalCase'], // 组件名 PascalCase
87 + 'vue/component-name-in-template-casing': ['error', 'PascalCase'], // 模板中组件名 PascalCase
88 + 'vue/no-unused-vars': 'error', // 禁止未使用的变量
89 + 'vue/padding-line-between-blocks': 'warn', // 块之间空行
90 +
91 + // 通用 JavaScript 规则
92 + 'no-console': ['warn', { allow: ['warn', 'error'] }], // 禁止 console.log(允许 warn/error)
93 + 'no-debugger': 'error', // 禁止 debugger
94 + 'no-alert': 'warn', // 警告使用 alert
95 + 'no-var': 'error', // 禁止 var,使用 const/let
96 + 'prefer-const': 'error', // 优先使用 const
97 + 'no-duplicate-imports': 'error', // 禁止重复导入
98 + 'no-unused-vars': 'off', // Vue 已处理
99 + 'no-const-assign': 'error', // 禁止重新赋值 const
100 + 'prefer-template': 'warn', // 优先使用模板字符串
101 + 'template-curly-spacing': 'error', // 模板字符串空格
102 + 'object-shorthand': ['warn', 'always'], // 对象简写
103 + 'prefer-arrow-callback': 'warn', // 优先使用箭头函数
104 + 'arrow-spacing': 'error', // 箭头函数空格
105 + 'arrow-parens': ['warn', 'as-needed'], // 箭头函数括号
106 + 'arrow-body-style': ['warn', 'as-needed'], // 箭头函数体
107 +
108 + // 代码质量
109 + eqeqeq: ['error', 'always', { null: 'ignore' }], // 强制 ===
110 + curly: ['error', 'all'], // 强制花括号
111 + 'brace-style': ['error', '1tbs', { allowSingleLine: true }], // 花括号风格
112 + 'no-else-return': 'warn', // if 中 return 后不要 else
113 + 'no-nested-ternary': 'warn', // 禁止嵌套三元
114 + 'no-unneeded-ternary': 'error', // 禁止不必要的三元
115 + 'prefer-destructuring': ['warn', { array: true, object: true }], // 优先解构
116 +
117 + // 异步
118 + 'no-async-promise-executor': 'error', // 禁止 async promise executor
119 + 'no-await-in-loop': 'warn', // 循环中的 await 警告
120 + 'require-await': 'error', // async 函数必须有 await
121 + 'prefer-promise-reject-errors': 'error', // Promise reject 必须有 Error
122 +
123 + // 错误处理
124 + 'no-throw-literal': 'error', // throw 必须是 Error 对象
125 + 'prefer-promise-reject-errors': 'error', // Promise reject 必须是 Error
126 +
127 + // 性能
128 + 'no-loop-func': 'warn', // 循环中不要创建函数
129 + 'no-new-func': 'error', // 禁止 new Function
130 +
131 + // 安全
132 + 'no-eval': 'error', // 禁止 eval
133 + 'no-implied-eval': 'error', // 禁止隐式 eval
134 + 'no-new-object': 'error', // 禁止 new Object()
135 + 'no-script-url': 'error', // 禁止 javascript:
136 + },
137 + },
138 +
139 + // 测试文件配置
140 + {
141 + files: ['**/*.test.js', '**/*.spec.js', 'test/**'],
142 + languageOptions: {
143 + globals: {
144 + describe: 'readonly',
145 + it: 'readonly',
146 + test: 'readonly',
147 + expect: 'readonly',
148 + vi: 'readonly',
149 + beforeEach: 'readonly',
150 + afterEach: 'readonly',
151 + beforeAll: 'readonly',
152 + afterAll: 'readonly',
153 + },
154 + },
155 + },
156 +
157 + // Prettier 配置(必须最后)
158 + prettier,
159 +]
...@@ -8,6 +8,12 @@ ...@@ -8,6 +8,12 @@
8 "build": ". ~/.nvm/nvm.sh && nvm use 18.19.1 && vite build", 8 "build": ". ~/.nvm/nvm.sh && nvm use 18.19.1 && vite build",
9 "preview": "vite preview", 9 "preview": "vite preview",
10 "test": "vitest run", 10 "test": "vitest run",
11 + "test:ui": "vitest --ui",
12 + "test:coverage": "vitest --coverage",
13 + "lint": "eslint . --fix",
14 + "lint:check": "eslint .",
15 + "format": "prettier --write \"src/**/*.{js,vue,css,less,md,json}\"",
16 + "format:check": "prettier --check \"src/**/*.{js,vue,css,less,md,json}\"",
11 "mcp:speckit": "node mcp/speckit_stdio_server.js", 17 "mcp:speckit": "node mcp/speckit_stdio_server.js",
12 "tar": "tar -czvpf dist.tar.gz mlaj", 18 "tar": "tar -czvpf dist.tar.gz mlaj",
13 "build_tar": "npm run build && npm run tar", 19 "build_tar": "npm run build && npm run tar",
...@@ -20,7 +26,20 @@ ...@@ -20,7 +26,20 @@
20 "remove_tar": "rm -rf dist.tar.gz", 26 "remove_tar": "rm -rf dist.tar.gz",
21 "dev_upload": "npm run build_tar && npm run scp-dev && npm run dec-dev && npm run remove_tar", 27 "dev_upload": "npm run build_tar && npm run scp-dev && npm run dec-dev && npm run remove_tar",
22 "behalo_upload": "npm run build_tar && npm run scp-behalo && npm run dec-behalo && npm run remove_tar", 28 "behalo_upload": "npm run build_tar && npm run scp-behalo && npm run dec-behalo && npm run remove_tar",
23 - "oa_upload": "npm run build_tar && npm run scp-oa && npm run dec-oa && npm run remove_tar" 29 + "oa_upload": "npm run build_tar && npm run scp-oa && npm run dec-oa && npm run remove_tar",
30 + "prepare": "husky"
31 + },
32 + "lint-staged": {
33 + "*.{js,vue}": [
34 + "eslint --fix",
35 + "prettier --write"
36 + ],
37 + "*.{css,less,scss}": [
38 + "prettier --write"
39 + ],
40 + "*.{json,md}": [
41 + "prettier --write"
42 + ]
24 }, 43 },
25 "dependencies": { 44 "dependencies": {
26 "@fortawesome/fontawesome-svg-core": "^6.5.1", 45 "@fortawesome/fontawesome-svg-core": "^6.5.1",
...@@ -56,15 +75,24 @@ ...@@ -56,15 +75,24 @@
56 "weixin-js-sdk": "^1.6.5" 75 "weixin-js-sdk": "^1.6.5"
57 }, 76 },
58 "devDependencies": { 77 "devDependencies": {
78 + "@playwright/test": "^1.58.0",
59 "@vitejs/plugin-vue": "^5.2.1", 79 "@vitejs/plugin-vue": "^5.2.1",
60 "@vitejs/plugin-vue-jsx": "^4.1.2", 80 "@vitejs/plugin-vue-jsx": "^4.1.2",
81 + "@vue/eslint-config-prettier": "^10.2.0",
61 "@vue/test-utils": "^2.4.6", 82 "@vue/test-utils": "^2.4.6",
62 "@vueuse/core": "^13.0.0", 83 "@vueuse/core": "^13.0.0",
63 "autoprefixer": "^10.4.19", 84 "autoprefixer": "^10.4.19",
64 "axios": "^1.8.4", 85 "axios": "^1.8.4",
86 + "eslint": "^9.39.2",
87 + "eslint-config-prettier": "^10.1.8",
88 + "eslint-plugin-vue": "^10.7.0",
89 + "husky": "^9.1.7",
65 "jsdom": "^24.1.3", 90 "jsdom": "^24.1.3",
66 "less": "^4.2.2", 91 "less": "^4.2.2",
92 + "lint-staged": "^16.2.7",
67 "postcss": "^8.4.35", 93 "postcss": "^8.4.35",
94 + "prettier": "^3.8.1",
95 + "prettier-plugin-tailwindcss": "^0.7.2",
68 "qs": "^6.14.0", 96 "qs": "^6.14.0",
69 "rusha": "^0.8.14", 97 "rusha": "^0.8.14",
70 "tailwindcss": "^3.4.1", 98 "tailwindcss": "^3.4.1",
......
This diff is collapsed. Click to expand it.