Files
SearcjGal-frontend/eslint.config.js
AdingApkgg 3d414157a0 依赖升级 + 代码质量、打包体积与组件结构优化
依赖:
- pnpm update --latest(vite、vue、eslint、typescript 等 14 个包到最新版)
- 显式加入 vue-eslint-parser ^10.4.0 / workbox-build ^7.4.1,消除 peer 警告

代码质量:
- 修复 ESLint vue parser 配置(用 vue-eslint-parser 作主 parser),lint 错误 17 → 0
- tsconfig 启用 noUncheckedIndexedAccess,修复 16 个潜在 undefined 访问 bug
- 删除未使用的 src/utils/icons.ts(723 行死代码)

打包体积:
- PWA precache 10.5 MB / 424 项 → 740 KB / 24 项(字体改为运行时缓存)
- vendor CSS gzip 201 KB → 141 KB(禁用字体 base64 内联,保留 unicode-range 子集策略)
- Artalk CSS 跟随 CommentsModal 异步加载
- 字体精简:移除未使用的 300 字重,补上用到的 600
- 删除僵尸的 fancybox manualChunks 配置

健壮性:
- SSE 搜索新增 AbortController + 60s 超时,新搜索取消旧请求,组件卸载取消进行中
- settings 持久化加 300ms 防抖 + QuotaExceededError 处理 + beforeunload 强制落盘

组件拆分:
- SearchHeader.vue 1330 → 1061 行,抽出 SearchErrorCard 子组件
- SettingsModal.vue 1289 → 1171 行,抽出 AdvancedApiSettings 子组件

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 07:23:19 +08:00

190 lines
6.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import js from '@eslint/js'
import tseslint from 'typescript-eslint'
import pluginVue from 'eslint-plugin-vue'
import vueParser from 'vue-eslint-parser'
export default tseslint.config(
// 忽略的文件和目录
{
ignores: [
'**/dist/**',
'**/node_modules/**',
'**/.pnpm-store/**',
'**/public/**',
'**/*.config.js',
'**/*.config.ts',
'**/.history/**', // 忽略编辑器历史文件
'**/.vscode/**',
'**/.idea/**',
'**/coverage/**',
],
},
// JavaScript 基础规则
js.configs.recommended,
// TypeScript 最严格规则(带类型检查)
...tseslint.configs.strictTypeChecked,
...tseslint.configs.stylisticTypeChecked,
// Vue 推荐规则
...pluginVue.configs['flat/recommended'],
// TypeScript 类型检查配置
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
// 自定义规则
{
files: ['**/*.{js,mjs,cjs,ts,vue}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
// 浏览器环境全局变量
window: 'readonly',
document: 'readonly',
navigator: 'readonly',
console: 'readonly',
setTimeout: 'readonly',
clearTimeout: 'readonly',
setInterval: 'readonly',
clearInterval: 'readonly',
requestAnimationFrame: 'readonly',
fetch: 'readonly',
URL: 'readonly',
URLSearchParams: 'readonly',
localStorage: 'readonly',
sessionStorage: 'readonly',
// DOM 类型
HTMLElement: 'readonly',
HTMLImageElement: 'readonly',
Element: 'readonly',
NodeList: 'readonly',
// 事件类型
Event: 'readonly',
MouseEvent: 'readonly',
TouchEvent: 'readonly',
KeyboardEvent: 'readonly',
CustomEvent: 'readonly',
// 其他
MutationObserver: 'readonly',
ResizeObserver: 'readonly',
IntersectionObserver: 'readonly',
confirm: 'readonly',
Image: 'readonly',
AbortController: 'readonly',
},
parserOptions: {
parser: tseslint.parser,
ecmaVersion: 'latest',
sourceType: 'module',
},
},
rules: {
// TypeScript 规则(严格但实用)
'@typescript-eslint/no-explicit-any': 'warn', // any 警告(允许但不推荐)
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrors: 'none', // 忽略 catch 块中未使用的错误变量
},
],
'@typescript-eslint/no-non-null-assertion': 'warn', // 非空断言警告
'@typescript-eslint/no-floating-promises': 'warn', // Promise 未处理警告
'@typescript-eslint/await-thenable': 'error', // await 必须用于 Promise
'@typescript-eslint/require-await': 'off', // 允许空 async 函数
'@typescript-eslint/restrict-template-expressions': 'off', // 允许模板字符串中使用任意类型
'@typescript-eslint/no-confusing-void-expression': 'off', // 允许 void 表达式
'@typescript-eslint/no-unnecessary-condition': 'off', // 关闭,避免误报
// 关闭过于严格的 unsafe 规则(实际项目中误报太多)
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/no-redundant-type-constituents': 'off',
'@typescript-eslint/prefer-nullish-coalescing': 'off', // || 和 ?? 各有用途
'@typescript-eslint/use-unknown-in-catch-callback-variable': 'off', // catch 变量类型
'@typescript-eslint/no-deprecated': 'warn', // 弃用 API 警告而非错误
'@typescript-eslint/no-extraneous-class': 'off', // 允许静态类(类型定义需要)
'@typescript-eslint/no-unnecessary-type-parameters': 'off', // 允许单次使用的泛型参数
'@typescript-eslint/restrict-plus-operands': 'off', // + 操作符类型检查
'@typescript-eslint/no-implied-eval': 'warn', // 隐式 eval 警告
'@typescript-eslint/no-empty-function': 'off', // 允许空函数
'@typescript-eslint/no-misused-promises': 'warn', // Promise 误用降为警告
// Vue 规则
'vue/multi-word-component-names': 'off', // 允许单词组件名
'vue/no-v-html': 'warn', // v-html 警告XSS 风险)
'vue/require-default-prop': 'off', // 不强制要求默认 prop
'vue/require-prop-types': 'error', // 必须定义 prop 类型
'vue/html-self-closing': [
'error',
{
html: {
void: 'always',
normal: 'always',
component: 'always',
},
svg: 'always',
math: 'always',
},
],
'vue/max-attributes-per-line': 'off', // 不限制每行属性数量
'vue/singleline-html-element-content-newline': 'off',
'vue/html-indent': ['error', 2],
// 通用规则(严格模式)
'no-console': ['warn', { allow: ['warn', 'error', 'info'] }], // 允许 warn/error/info
'no-debugger': 'error',
'no-unused-vars': 'off', // 使用 TypeScript 的规则
'prefer-const': 'error',
'no-var': 'error',
'eqeqeq': ['error', 'always'],
'curly': ['error', 'all'],
'semi': ['error', 'never'], // 不使用分号
'quotes': ['error', 'single', { avoidEscape: true }],
'comma-dangle': ['error', 'always-multiline'],
'arrow-spacing': 'error',
'object-curly-spacing': ['error', 'always'],
'array-bracket-spacing': ['error', 'never'],
'space-before-function-paren': [
'error',
{
anonymous: 'always',
named: 'never',
asyncArrow: 'always',
},
],
},
},
// Vue 文件特定配置
{
files: ['**/*.vue'],
languageOptions: {
parser: vueParser,
parserOptions: {
parser: tseslint.parser,
ecmaVersion: 'latest',
sourceType: 'module',
extraFileExtensions: ['.vue'],
},
},
rules: {
// <script setup> 中变量在 template 使用ESLint 无法感知
'no-useless-assignment': 'off',
},
},
)