diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 5d677b0bd..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,148 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## 技术栈 - -1. 基于 **pnpm workspaces** + **Turborepo** 的 Vue 3 + TypeScript + Vite monorepo 项目。 -2. 提供多个 UI 组件库版本(Ant Design Vue、Element Plus、Naive UI、TDesign),共享同一套使用tailwindcss+shadcn-vue的UI组件库核心框架。 -3. 要求 Node ≥ 20.19.0,pnpm ≥ 10。 -4. 使用 **prettier** + **eslint** + **stylelint** 进行代码检查和格式化。 -5. 使用 **vitest** 进行单元测试。 -6. 使用 **commitlint** 进行提交规范。 -7. 使用 **czg** 进行提交规范。 -8. 使用 **lefthook** 进行提交规范。 -9. 使用 **vsh** 进行代码检查和格式化。 -10. 使用 **turbo** 进行构建。 -11. 使用 **vite** 进行开发。 -12. 使用 **vue-tsc** 进行类型检查。 - -```bash -# 其他检查 -pnpm check:circular # 循环依赖扫描 -pnpm check:dep # depcheck 依赖检查 -pnpm check:cspell # 拼写检查 - -# 清理 -pnpm clean # 删除 dist、node_modules 等产物 -pnpm reinstall # clean + 重新安装 - -# 交互式规范提交 -pnpm commit # czg 提交向导 -``` - -Turbo 任务通过 `dependsOn: ["^build"]` 级联,构建某个应用时会自动先构建其所有依赖包。 - -## Monorepo 目录结构 - -```text -apps/ - backend-mock/ # 基于 Nitro 的 mock API 服务(h3 路由 + faker.js 数据) - web-antd/ # Ant Design Vue 应用 - web-ele/ # Element Plus 应用 - web-naive/ # Naive UI 应用 - web-tdesign/ # TDesign Vue 应用 - -packages/ - @core/ # 框架核心(不依赖具体 UI 库) - base/ # 共享工具、缓存、颜色处理、类型定义 - composables/ # 核心 Vue composable - preferences/ # PreferenceManager 类(响应式、持久化配置) - ui-kit/ # UI 组件片段:form-ui、layout-ui、menu-ui、popup-ui、shadcn-ui、tabs-ui - effects/ # 高层模块,可依赖 @core 和 UI 库 - access/ # 路由/菜单生成与权限指令 - common-ui/ # 通用 UI 组件(ApiComponent、IconPicker、VCropper、Tippy 等) - hooks/ # useAppConfig 等 - layouts/ # BasicLayout、登录页、各类 widgets - plugins/ # Motion 等插件 - request/ # RequestClient(axios 封装 + 拦截器体系) - constants/ # 全局常量(LOGIN_PATH 等) - icons/ # Iconify 图标封装 - locales/ # vue-i18n 初始化、loadLocalesMap 工具 - preferences/ # 对外暴露 @core/preferences 的公共 API - stores/ # Pinia 全局 store:useAccessStore、useUserStore、useTabbarStore - styles/ # 全局 CSS / TailwindCSS 基础样式 - types/ # 共享 TypeScript 类型 - utils/ # 共享工具函数(mergeRouteModules、mapTree 等) - -internal/ - lint-configs/ # ESLint、Prettier、Stylelint、commitlint 配置包 - node-utils/ # 构建时 Node 工具 - tailwind-config/ # 共享 Tailwind 配置 - tsconfig/ # 基础 tsconfig - vite-config/ # 共享 Vite 配置工厂 + 插件集合 - -scripts/ - vsh/ # CLI 工具(lint、check-dep、check-circular、publint) - turbo-run/ # 交互式 turbo 运行器 - -playground/ # 组件演示场 -docs/ # VitePress 文档 -``` - -## 核心架构说明 - -### 应用启动流程 - -每个应用的 `src/main.ts` 调用 `bootstrap(namespace)`(位于 `src/bootstrap.ts`),依次执行: - -1. 初始化**组件适配器**(`src/adapter/component/index.ts`)——将通用表单组件名映射到具体 UI 库的组件。 -2. 调用 `initSetupVbenForm()`(`src/adapter/form.ts`)配置通用表单系统。 -3. 依次初始化 i18n、Pinia stores、权限指令、Tippy、路由、MotionPlugin,最后挂载到 `#app`。 - -### 偏好设置系统 - -`@vben/preferences` 导出单例 `preferences`(`PreferenceManager`)。它是响应式的,自动持久化到 localStorage(以应用 namespace 为前缀),并驱动主题 CSS 变量的更新。各应用在 `src/preferences.ts` 中调用 `defineOverridesPreferences()` 覆盖默认值,无需修改核心代码。 - -### 权限/访问系统 - -`@vben/access`(`packages/effects/access`)支持三种访问模式: - -- **frontend**:根据用户角色过滤静态路由。 -- **backend**:从接口(`getAllMenusApi`)获取菜单并动态注册路由。 -- **mixed**:同时使用以上两种方式。 - -路由守卫(`src/router/guard.ts`)在登录后首次导航时调用 `generateAccess()`,将结果存入 `useAccessStore`,再重定向到目标页。`v-access` 指令和 `` 组件用于按权限码或角色控制 UI 元素显示。 - -### 请求客户端 - -`@vben/request` 将 Axios 封装为 `RequestClient`。每个应用在 `src/api/request.ts` 中创建自己的实例,挂载以下拦截器: - -- **请求拦截**:自动附加 Bearer Token 和 Accept-Language 头。 -- **`defaultResponseInterceptor`**:解包 `{ code, data, message }` 响应格式。 -- **`authenticateResponseInterceptor`**:处理 401,自动刷新 token 或跳转登录。 -- **`errorMessageResponseInterceptor`**:调用 `message.error()` 显示错误。 - -在 API 文件中从 `#/api/request` 引入 `requestClient`(自动解包响应)或 `baseRequestClient`(原始响应)。 - -### 路由组织 - -- `src/router/routes/modules/*.ts`:需要权限验证的动态路由。 -- `src/router/routes/core/`:始终可访问的路由(登录页、404 等)。 -- `mergeRouteModules(import.meta.glob(...))` 用于聚合路由模块文件。 -- 动态路由在运行时由权限系统注册。 - -### 适配器模式 - -每个 UI 库应用在 `src/adapter/` 下提供适配器,将 `@vben/common-ui` 的通用 form/modal/drawer 组件桥接到具体组件库。这是 `web-antd`、`web-ele` 等应用之间的主要差异所在。 - -### 全局 Pinia Store - -- `useAccessStore`:token、路由、菜单、锁屏、登录过期状态。 -- `useUserStore`:用户信息、角色、homePath。 -- `useTabbarStore`:已打开标签页管理。 - -所有 store 通过 `@vben/stores` 的 `initStores(app, { namespace })` 统一初始化。 - -### Mock 后端 - -`apps/backend-mock` 是一个 Nitro 服务器,可单独启动:`pnpm -F @vben/backend-mock start`。Vite 开发服务器通过 `vite.config.ts`(位于 `internal/vite-config`)将 API 请求代理到该服务。 - -## 开发约定 - -- **路径别名**:`#/*` 指向各应用的 `./src/*`(在 `package.json#imports` 中定义)。 -- **依赖版本管理**:内部包使用 `workspace:*`,第三方包使用 `catalog:`(版本集中在 `pnpm-workspace.yaml#catalog` 中管理)。 -- **提交规范**:遵循 Conventional Commits(`feat`、`fix`、`chore`、`docs`、`refactor`、`perf`、`test`、`ci`、`style`、`types`、`revert`),由 lefthook + commitlint 强制执行。 -- **pre-commit 钩子**(lefthook):自动对暂存文件执行 prettier + eslint + stylelint,推荐使用 `pnpm commit`(czg)提交。 -- **新增页面**:在 `src/views/` 下创建 `.vue` 文件,在 `src/router/routes/modules/` 下添加路由模块;若使用 backend 模式,还需确保后端接口返回对应菜单数据。 -- **国际化**:统一使用 `$t('key')`,locale 文件位于 `packages/locales/`,项目级国际化文件位于 `src/locales/langs`。 diff --git a/up-oxc.md b/up-oxc.md deleted file mode 100644 index 7a26f222d..000000000 --- a/up-oxc.md +++ /dev/null @@ -1,703 +0,0 @@ -# OXC 迁移计划 - -> 本文档记录将项目中可替代的工具链逐步迁移到 [oxc](https://oxc.rs/) 生态的计划。 -> -> 说明:本文档已按当前仓库状态校准。第一阶段已完成大部分工作,第二阶段的 formatter 迁移也已大部分落地。 - -## 当前现状 - -当前仓库的 lint / format 体系已经从“纯 ESLint + Prettier”演进为 “oxlint + ESLint 共存,oxfmt 替换 Prettier”。 - -当前与 lint / format 直接相关的核心依赖包括: - -- `eslint` ^10.0.3 -- `oxlint` ^1.55.0 -- `oxfmt` ^0.40.0 -- `eslint-plugin-oxlint` ^1.55.0 -- `@typescript-eslint/parser` ^8.57.0 -- `@typescript-eslint/eslint-plugin` ^8.57.0 -- `eslint-plugin-unicorn` ^63.0.0 -- `eslint-plugin-unused-imports` ^4.4.1 -- `eslint-plugin-n` ^17.24.0 -- `eslint-plugin-perfectionist` ^5.6.0 -- `eslint-plugin-vue` ^10.8.0 -- `eslint-plugin-better-tailwindcss` ^4.3.2 -- `eslint-plugin-jsonc` ^3.1.2 -- `eslint-plugin-yml` ^3.3.1 -- `eslint-plugin-command` ^3.5.2 -- `eslint-plugin-pnpm` ^1.6.0 -- `@eslint-community/eslint-plugin-eslint-comments` ^4.7.1 -- `vue-eslint-parser` ^10.4.0 -- `yaml-eslint-parser` ^2.0.0 -- `globals` ^17.4.0 -- `esbuild` ^0.27.4 -- `html-minifier-terser` ^7.2.0 - -以下依赖已不再存在于当前仓库的 lint / format 链路中: - -- `eslint-plugin-import-x` -- `eslint-plugin-regexp` -- `eslint-plugin-jsdoc` -- `eslint-plugin-no-only-tests` -- `@vitest/eslint-plugin` -- `eslint-plugin-prettier` -- `stylelint-prettier` -- `prettier` - ---- - -## 第一阶段:引入 oxlint,与 ESLint 共存 - -**目标**:将通用 JS/TS lint 规则交给 oxlint,ESLint 仅保留 oxlint 无法覆盖的特殊规则,减少依赖数量并提升 lint 速度。 - -### 1.1 安装 oxlint - -```bash -pnpm add -Dw oxlint -``` - -### 1.2 已迁出或已移除的 ESLint 插件 - -以下插件与规则已经完成迁移,或者已从当前仓库移除: - -| 插件 | 当前状态 | 说明 | -| --- | --- | --- | -| `eslint-plugin-regexp` | 已移除 | 由 oxlint 内建能力承接 | -| `eslint-plugin-jsdoc` | 已移除 | 由 oxlint 内建能力承接 | -| `eslint-plugin-no-only-tests` | 已移除 | 测试规则已迁到 oxlint / vitest 分类 | -| `eslint-plugin-import-x` | 已移除 | `import` 规则已集中迁入 `@vben/oxlint-config` | -| `@vitest/eslint-plugin` | 已移除 | Vitest 规则已迁入 `@vben/oxlint-config` | -| `eslint-plugin-prettier` | 已移除 | formatter 已切换到 oxfmt | -| `eslint-plugin-better-tailwindcss` | 已迁出 ESLint | 仍保留依赖,但已通过 oxlint `jsPlugins` 运行 | -| `@typescript-eslint/eslint-plugin` | 仍需保留 | 还有一批 TS 规则未迁移 | -| `@typescript-eslint/parser` | 仍需保留 | ESLint 侧 TS / Vue 规则仍依赖它 | -| `eslint-plugin-unicorn` | 仍需保留 | ESLint 侧仍使用其 recommended 规则补充 | -| `eslint-plugin-unused-imports` | 仍需保留 | `no-unused-imports` 仍由 ESLint 负责 | -| `eslint-plugin-n` | 仍需保留 | 多条 Node 规则在 oxlint 中暂无等价承接 | -| `eslint-plugin-perfectionist` | 仍需保留 | 排序规则策略不同,不建议强迁 | -| `@eslint-community/eslint-plugin-eslint-comments` | 仍需保留 | 当前尚未迁移 | - -### 1.3 当前仍需保留在 ESLint 侧的插件 / 能力 - -以下插件或能力当前仍需继续由 ESLint 处理: - -| 插件 / 能力 | 原因 | -| --- | --- | -| `eslint-plugin-vue` + `vue-eslint-parser` | Vue SFC template lint,oxlint Vue 支持尚未完善 | -| `@typescript-eslint/eslint-plugin` + `@typescript-eslint/parser` | 仍有一批 TS strict / type-aware 规则保留在 ESLint 侧 | -| `eslint-plugin-unused-imports` | `no-unused-imports` 仍由 ESLint 负责 | -| `eslint-plugin-n` | 多条 Node 规则尚无等价承接 | -| `eslint-plugin-perfectionist` | 当前仍负责排序策略 | -| `eslint-plugin-jsonc` + `eslint-plugin-yml` + `yaml-eslint-parser` | JSON / YAML 文件 lint 仍在 ESLint 侧 | -| `eslint-plugin-pnpm` | pnpm workspace 规则,oxlint 无对应 | -| `eslint-plugin-command` | 魔法注释命令,oxlint 无对应 | -| `@eslint-community/eslint-plugin-eslint-comments` | 当前尚未迁移 | - -### 1.4 配置 oxlint - -当前实现已经调整为与 ESLint 一致的 workspace 包组织方式: - -- 根目录使用 [oxlint.config.ts](./oxlint.config.ts) 作为薄入口 -- 实际规则配置位于 `internal/lint-configs/oxlint-config` -- ESLint 兼容层通过 `eslint-plugin-oxlint` 直接消费 `@vben/oxlint-config` 导出的配置对象,确保 oxlint 与 ESLint 共用同一份规则源 - -示例结构: - -```ts -// oxlint.config.ts -import { defineConfig } from '@vben/oxlint-config'; - -export default defineConfig(); -``` - -```ts -// internal/lint-configs/oxlint-config/src/index.ts -import { defineConfig as defineOxlintConfig } from 'oxlint'; -import { mergeOxlintConfigs, oxlintConfig } from './configs'; - -export function defineConfig(config = {}) { - const { extends: extendedConfigs = [], ...restConfig } = config; - return defineOxlintConfig( - mergeOxlintConfigs(oxlintConfig, ...extendedConfigs, restConfig), - ); -} -``` - -不再使用根目录 `.oxlintrc.json`。 - -### 1.5 当前已完成项 - -截至当前仓库状态,第一阶段与其配套的 formatter 迁移已完成以下工作: - -1. 根 `lint` 已统一委托给 `vsh lint` -2. 保留 `lint:oxc`、`lint:oxc:type-aware`、`lint:eslint`、`lint:style` 作为独立入口 -3. `lefthook` 已接入 `oxfmt`、`oxlint --fix`、`eslint --cache --fix`、`stylelint --fix` -4. 已新增 `@vben/oxlint-config`,并将 oxlint 规则集中到 `internal/lint-configs/oxlint-config` -5. 已新增 `@vben/oxfmt-config`,并使用根级 `oxfmt.config.ts` 作为格式化配置入口 -6. `eslint-plugin-oxlint` 已接入 `@vben/eslint-config` -7. 已移除 `eslint-plugin-jsdoc`、`eslint-plugin-regexp`、`eslint-plugin-no-only-tests` -8. `import` 与 `vitest` 规则已迁入 oxlint,相关 ESLint 插件已移除 -9. `better-tailwindcss` 已迁移到 `@vben/oxlint-config` 的 `jsPlugins` 方案 -10. `unicorn` 插件已在 oxlint 侧显式启用,并补齐仓库内所需的 override -11. Prettier 相关根配置与 ESLint / Stylelint 集成已移除 -12. `internal/node-utils` 已改为调用 `oxfmt` - -### 1.6 当前 oxlint 基线策略 - -当前 `@vben/oxlint-config` 采用“先收敛噪音,再逐步接管规则”的策略: - -- 启用 `correctness` 和 `suspicious` -- 显式启用 `import`、`node`、`oxc`、`typescript`、`unicorn`、`vitest`、`vue` 插件 -- 通过 `jsPlugins` 在 oxlint 侧承接 `better-tailwindcss` -- 对当前仓库内高噪音且不准备立即批量整改的规则先显式关闭 -- 通过 `overrides` 为 `.d.ts`、测试文件、脚本目录等特殊场景保留例外配置 -- `overrides.files` 已避免继续使用 ESLint 风格的 extglob,改为显式文件后缀列表 - -### 1.7 当前已迁入 oxlint 的规则 - -以下规则已在当前仓库的 `@vben/oxlint-config` 中落地: - -#### JavaScript / core - -- `eqeqeq` -- `no-alert` -- `no-array-constructor` -- `no-caller` -- `no-case-declarations` -- `no-debugger` -- `no-eval` -- `no-iterator` -- `no-new-wrappers` -- `no-shadow-restricted-names` -- `no-unused-expressions` -- `prefer-const` -- 以及一批额外的 core 规则,例如 `no-console`、`no-template-curly-in-string`、`prefer-template`、`object-shorthand` - -#### import - -- `import/consistent-type-specifier-style` -- `import/first` -- `import/no-duplicates` -- `import/no-mutable-exports` -- `import/no-named-default` -- `import/no-self-import` -- `import/no-webpack-loader-syntax` - -#### TypeScript - -- `typescript/ban-ts-comment` -- `typescript/no-non-null-assertion` -- `typescript/no-var-requires` -- `typescript/triple-slash-reference` - -> 当前仓库已开始为 type-aware 规则预留位置,但 `no-floating-promises`、`await-thenable` 等高噪音规则仍显式关闭,等待后续逐步接管。 - -#### Vitest - -- `vitest/consistent-test-it` -- `vitest/no-focused-tests` -- `vitest/no-identical-title` -- `vitest/no-import-node-test` -- `vitest/prefer-hooks-in-order` -- `vitest/prefer-lowercase-title` - -#### Node - -- `node/no-exports-assign` -- `node/no-new-require` -- `node/no-path-concat` - -#### Unicorn - -- `unicorn/no-process-exit` -- `unicorn/prefer-module` - -#### Tailwind CSS - -- `better-tailwindcss/enforce-consistent-class-order` - -> `better-tailwindcss/enforce-consistent-line-wrapping` 与 `better-tailwindcss/no-unknown-classes` 当前仍因噪音 / 与 formatter 冲突而关闭。 - -#### Vue - -- `vue/prefer-import-from-vue` - -### 1.8 暂时仍需保留在 ESLint 的部分 - -以下内容当前不建议从 ESLint 侧移除: - -1. Vue SFC / template 主体规则 -2. `perfectionist` -3. `jsonc` / `yml` -4. `pnpm` -5. `command` -6. `eslint-comments` -7. `unused-imports` -8. `node.ts` 中尚未被 oxlint 覆盖的规则 -9. `typescript.ts` 中暂不适合直接迁移的 strict / type-aware 规则 - -其中 Vue 相关规则尤其需要保留,至少包括: - -- `vue/block-order` -- `vue/component-name-in-template-casing` -- `vue/component-options-name-casing` -- `vue/custom-event-name-casing` -- `vue/define-macros-order` -- `vue/no-unused-refs` -- `vue/no-useless-v-bind` -- `vue/require-default-prop` -- `vue/require-explicit-emits` -- `vue/v-on-event-hyphenation` -- `vue/prefer-separate-static-class` -- `vue/prefer-template` - -### 1.9 推荐的下一步执行顺序 - -为降低回归风险,建议按当前真实代码结构推进: - -1. 验证 `oxcCompat()` 是否正确关闭 ESLint 重复规则 -2. 继续清理 `eslint-config/src/configs/javascript.ts` 中已被 oxlint 明确覆盖的低风险规则 -3. 继续从 `eslint-config/src/configs/typescript.ts` 向 `@vben/oxlint-config` 下沉规则,并结合 `lint:oxc:type-aware` 逐步启用 type-aware 规则 -4. 评估 `eslint-config/src/configs/unicorn.ts` 中剩余规则是否值得继续保留 -5. 保留并持续观察 `eslint-config/src/configs/node.ts`、`vue.ts`、`perfectionist.ts`、`jsonc.ts`、`yaml.ts`、`pnpm.ts`、`command.ts` -6. 最后再评估是否要重新启用 tailwind 的 wrapping / unknown classes 规则 - -每迁移一组后都执行: - -```bash -pnpm run lint:oxc -pnpm run lint:eslint -pnpm run lint -``` - -### 1.10 当前 scripts - -```jsonc -// package.json -{ - "scripts": { - "format": "vsh lint --format", - "lint": "vsh lint", - "lint:oxc": "oxlint .", - "lint:oxc:type-aware": "oxlint . --type-aware", - "lint:eslint": "eslint . --cache", - "lint:style": "stylelint \"**/*.{vue,css,less,scss}\" --cache", - }, -} -``` - -### 1.11 当前 lefthook - -当前 `pre-commit` 已包含如下链路: - -```yaml -pre-commit: - parallel: true - commands: - code-workspace: - run: pnpm vsh code-workspace --auto-commit - lint-md: - run: pnpm oxfmt {staged_files} - glob: '*.md' - lint-vue: - run: pnpm oxfmt {staged_files} && pnpm oxlint --fix {staged_files} && pnpm eslint --cache --fix {staged_files} && pnpm stylelint --fix --allow-empty-input {staged_files} - glob: '*.vue' - lint-js: - run: pnpm oxfmt {staged_files} && pnpm oxlint --fix {staged_files} && pnpm eslint --cache --fix {staged_files} - glob: '*.{js,jsx,ts,tsx}' - lint-style: - run: pnpm oxfmt {staged_files} && pnpm stylelint --fix --allow-empty-input {staged_files} - glob: '*.{scss,less,styl,html,vue,css}' - lint-package: - run: pnpm oxfmt {staged_files} - glob: 'package.json' - lint-json: - run: pnpm oxfmt {staged_files} - glob: '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}' -``` - -### 1.12 验证步骤 - -1. 全量运行 `pnpm run lint:oxc`,记录 oxlint 报告 -2. 对比当前 ESLint 规则覆盖情况,调整 oxlint 配置使两者对齐 -3. 逐个移除可替代的 ESLint 插件或规则组,每次移除后运行完整 lint 验证 -4. CI 中同时运行 oxlint 和 ESLint,确保双重覆盖期间无回归 - -### 1.13 待修复问题与改进项 - -> 以下问题按当前仓库状态重新整理。 - -#### [高] `unicorn` 插件启用后要同时收敛默认规则与 override - -这个问题已经修复,但需要保留经验: - -- `plugins` 一旦显式声明,必须手动包含 `unicorn` -- 启用后不只会打开我们手写的 `unicorn/no-process-exit`、`unicorn/prefer-module` -- 还会带出 oxlint 默认启用的一部分 `unicorn` 规则,需要按仓库现状显式关闭噪音项 -- OXC `overrides.files` 不要继续使用 `?([cm])[jt]s?(x)` 这类 ESLint 风格的 extglob - -#### [高] 使用 `@oxlint/migrate` 仅做审计,不直接落地配置 - -官方提供了 [`@oxlint/migrate`](https://github.com/oxc-project/oxlint-migrate) 工具,可自动读取 ESLint flat config 生成对应 oxlint 配置。 - -对于当前仓库,`@oxlint/migrate` 更适合做“审计工具”,不适合直接生成或合并为最终配置,原因是: - -1. 当前仓库已经不是简单的 `.oxlintrc.json` 形态,而是 workspace 包 + 模块化 `configs/*` -2. `@vben/oxlint-config` 依赖自定义 `mergeOxlintConfigs(...)` 来保证 `settings`、`ignorePatterns`、`jsPlugins` 正确合并 -3. Tailwind 规则依赖手写 `jsPlugins` 和 `settings` -4. 现有迁移流程还包含 ESLint 兼容层 `eslint-plugin-oxlint` - -更合理的用法是: - -```bash -npx @oxlint/migrate --details -``` - -不建议直接使用 `--merge` 覆盖当前仓库的真实配置结构。 - -#### [中] `mergeOxlintConfigs` 函数重复定义 - -这个问题已经修复。ESLint 侧的 `oxlint.ts` 已直接导入 `@vben/oxlint-config` 的 `mergeOxlintConfigs`,并在传入 `buildFromOxlintConfig()` 前剥离 `extends`: - -```ts -import { mergeOxlintConfigs, oxlintConfig } from '@vben/oxlint-config'; -import oxlint from 'eslint-plugin-oxlint'; - -export async function oxcCompat(): Promise { - const { extends: _extends, ...config } = mergeOxlintConfigs(oxlintConfig); - - return oxlint.buildFromOxlintConfig( - config as Parameters[0], - ); -} -``` - -#### [中] 验证 `oxcCompat()` 是否正确关闭 ESLint 重复规则 - -ESLint 侧 `javascript.ts` 仍有较多规则,而其中很多已被 oxlint 的 `correctness` / `suspicious` category 覆盖。 - -`eslint-plugin-oxlint` 的 `buildFromOxlintConfig()` 理论上会自动关闭 ESLint 中被 oxlint 覆盖的规则。仍需验证 `oxcCompat()` 确实生效。如果正常工作,则 ESLint 侧无需手动清理这批重复规则。 - -建议验证方法: - -```bash -# 临时在 oxlint 中启用一个 ESLint 也有的规则(如 no-debugger) -# 确认 ESLint 不再重复报告该规则 -``` - -#### [中] `eslint-plugin-import-x` 已从当前仓库移除 - -`eslint-plugin-import-x` 相关迁移已经落地,当前仓库不再保留该依赖,`import` 规则集中定义在 `internal/lint-configs/oxlint-config/src/configs/import.ts`。 - -当前未再单独保留 `import/newline-after-import`。如未来仍需这类纯风格规则,应单独评估是否值得重新引入。 - -#### [中] `eslint-plugin-n` 仍不能完全移除 - -当前 ESLint 侧 `node.ts` 仍保留以下规则,尚未被 oxlint 接管: - -| 规则 | 备注 | -| --- | --- | -| `n/handle-callback-err` | oxlint 未支持 | -| `n/no-deprecated-api` | oxlint 未支持 | -| `n/no-extraneous-import` | 有自定义 `allowModules`,oxlint 未支持 | -| `n/no-unsupported-features/es-syntax` | oxlint 未支持 | -| `n/prefer-global/buffer` | oxlint 未支持 | -| `n/prefer-global/process` | oxlint 未支持 | -| `n/process-exit-as-throw` | oxlint 未支持 | - -**结论**:`eslint-plugin-n` 当前仍需保留在 ESLint 侧。 - -#### [低] 已增加 `lint:oxc:type-aware` 入口,后续逐步启用规则 - -当前根 `package.json` 已提供: - -```bash -pnpm run lint:oxc:type-aware -``` - -当前 `@vben/oxlint-config` 已显式保留一批关闭状态的 type-aware 规则,例如: - -- `typescript/no-floating-promises` -- `typescript/await-thenable` -- `typescript/no-base-to-string` -- `typescript/no-unnecessary-type-assertion` - -后续建议基于实际报告量逐条开启,而不是一次性打开全部 type-aware 规则。 - -#### [低] `--replace-eslint-comments` 批量转换注释 - -代码中存在的 `// eslint-disable` 注释虽然 oxlint 兼容,但在第四阶段移除 ESLint 后会变得语义不清。官方迁移工具提供了批量转换选项: - -```bash -npx @oxlint/migrate --replace-eslint-comments -``` - -建议在第一阶段完成后或第四阶段开始前执行。 - -#### [低] `jsPlugins` 已在仓库中使用,后续可继续减少 ESLint 依赖 - -当前仓库已经通过 `jsPlugins` 在 oxlint 侧接入 `eslint-plugin-better-tailwindcss`。对于 `eslint-plugin-pnpm`、`eslint-plugin-command` 等 oxlint 不内置的插件,未来仍可评估采用同样方式进一步减少对 ESLint 的依赖: - -```json -{ - "jsPlugins": ["eslint-plugin-pnpm"], - "rules": { - "pnpm/some-rule": "warn" - } -} -``` - ---- - -## 第二阶段:oxfmt 替换 Prettier(大部分已完成) - -**当前状态**:第二阶段的大部分工作已经落地,下面记录的是“当前仓库真实状态”和仍需继续验证的事项,而不是最初的待办清单。 - -> 参考文档:[oxfmt CLI](https://oxc.rs/docs/guide/usage/formatter/cli.html) | [Config Reference](https://oxc.rs/docs/guide/usage/formatter/config-file-reference.html) - -### 2.1 当前 formatter 触点全景 - -| 位置 | 当前状态 | 说明 | -| --- | --- | --- | -| `internal/lint-configs/oxfmt-config/` | 已完成 | 新增 `@vben/oxfmt-config` workspace 包 | -| `oxfmt.config.ts` | 已完成 | 根级 formatter 配置入口,负责追加 `ignorePatterns` | -| `.prettierrc.mjs` | 已移除 | 不再作为根入口 | -| `.prettierignore` | 已移除 | 忽略模式已迁入 `oxfmt.config.ts` | -| `eslint-config/src/configs/prettier.ts` | 已移除 | ESLint 不再集成 Prettier | -| `eslint-config/src/index.ts` | 已完成 | 已无 `prettier()` 调用 | -| `eslint-config/package.json` | 已完成 | 已移除 `eslint-plugin-prettier` 依赖 | -| `stylelint-config/index.mjs` | 已完成 | 已移除 `stylelint-prettier` 插件和规则 | -| `stylelint-config/package.json` | 已完成 | 已移除 `prettier` / `stylelint-prettier` 依赖 | -| `internal/node-utils/src/formatter.ts` | 已完成 | 格式化工具已改为调用 `oxfmt` | -| `scripts/vsh/src/lint/index.ts` | 已完成 | 已改为调用 `oxfmt` | -| `lefthook.yml` | 已完成 | 已统一切换为 `pnpm oxfmt` | -| `pnpm-workspace.yaml` catalog | 已完成 | 已移除 `prettier`、`eslint-plugin-prettier`、`stylelint-prettier`,并新增 `oxfmt` | -| `package.json` 根 | 已完成 | 已依赖 `@vben/oxfmt-config` 与 `oxfmt` | -| `vben-admin.code-workspace` | 已完成 | 已更新 workspace 引用 | - -### 2.2 当前实际配置 - -当前仓库并未使用 `.oxfmtrc.json`,而是采用 “共享包 + 根入口” 的组织方式。 - -共享配置位于 `internal/lint-configs/oxfmt-config/src/index.ts`: - -```ts -import { defineConfig as defineOxfmtConfig } from 'oxfmt'; - -const oxfmtConfig = defineOxfmtConfig({ - printWidth: 80, - proseWrap: 'never', - semi: true, - singleQuote: true, - sortPackageJson: false, - trailingComma: 'all', -}); -``` - -根级入口位于 `oxfmt.config.ts`: - -```ts -import { defineConfig } from '@vben/oxfmt-config'; - -export default defineConfig({ - ignorePatterns: [ - 'dist', - 'dev-dist', - '.local', - '.claude', - '.agent', - '.agents', - '.codex', - '.output.js', - 'node_modules', - '.nvmrc', - 'coverage', - 'CODEOWNERS', - '.nitro', - '.output', - '**/*.svg', - '**/*.sh', - 'public', - '.npmrc', - '*-lock.yaml', - 'skills-lock.json', - ], -}); -``` - -需要注意两点: - -1. 当前 formatter 的 `printWidth` 明确设为 `80` -2. `.editorconfig` 的 `max_line_length` 仍为 `100` - -也就是说,当前仓库实际上采用的是“oxfmt 显式配置优先于 `.editorconfig`”的策略,这一点需要在后续验证中保持一致。 - -### 2.3 `@vben/oxfmt-config` workspace 包 - -当前包结构与其他 lint-config 包保持一致: - -```text -internal/lint-configs/oxfmt-config/ - package.json - src/index.ts -``` - -```json -{ - "name": "@vben/oxfmt-config", - "version": "5.6.0", - "private": true, - "type": "module", - "files": ["dist"], - "main": "./dist/index.mjs", - "module": "./dist/index.mjs", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "import": "./dist/index.mjs" - } - }, - "dependencies": { - "oxfmt": "catalog:" - } -} -``` - -这个包当前承担三件事: - -1. 集中管理 `oxfmt` 版本依赖 -2. 导出共享格式化配置对象 -3. 供根级 `oxfmt.config.ts` 和其他程序化场景复用 - -### 2.4 已完成的替换范围 - -| 原方案 | 当前状态 | -| ------------------------ | ----------------------------- | -| `prettier` | 已移除,当前统一使用 `oxfmt` | -| `eslint-plugin-prettier` | 已移除 | -| `stylelint-prettier` | 已移除 | -| `@vben/prettier-config` | 已替换为 `@vben/oxfmt-config` | - -### 2.5 已完成的操作 - -以下动作已在当前仓库完成: - -1. 创建 `@vben/oxfmt-config` workspace 包 -2. 新增根级 `oxfmt.config.ts` -3. 将 `scripts/vsh/src/lint/index.ts` 切换到 `oxfmt` -4. 将 `lefthook.yml` 切换到 `pnpm oxfmt` -5. 删除 ESLint 中的 Prettier 集成 -6. 删除 Stylelint 中的 Prettier 集成 -7. 将 `internal/node-utils` 中的格式化能力切换到 `oxfmt` -8. 删除 `.prettierrc.mjs`、`.prettierignore` 和旧的 `@vben/prettier-config` -9. 更新根 `package.json`、`pnpm-workspace.yaml`、`vben-admin.code-workspace` - -### 2.6 下一步只保留验证项 - -第二阶段当前不再需要按“迁移步骤”执行,剩余工作主要是验证和收口: - -1. 重新全量运行 `pnpm run lint`,确认 `vsh lint` 当前默认行为与预期一致 -2. 明确 `oxfmt.config.ts` 是否作为 CLI 与编辑器共同入口;如团队工具链存在兼容性差异,再决定是否需要补 `.oxfmtrc.json` -3. 决定 `printWidth: 80` 与 `.editorconfig` 的 `max_line_length = 100` 是否继续并存 -4. 评估是否启用 oxfmt 的额外能力,例如 `sortImports`、`sortTailwindcss` - -### 2.7 oxfmt 额外能力评估 - -oxfmt 提供了 Prettier 没有的扩展特性,可选启用: - -| 特性 | 说明 | 当前状态 / 建议 | -| --- | --- | --- | -| `sortImports` | import 语句排序,灵感来自 `eslint-plugin-perfectionist/sort-imports` | 可评估是否替代 ESLint 侧部分排序职责 | -| `sortTailwindcss` | 替代 `prettier-plugin-tailwindcss` | 当前仓库仍优先使用 oxlint `jsPlugins` 方案 | -| `sortPackageJson` | 自动排序 `package.json` 字段 | 当前共享配置显式设为 `false` | -| `insertFinalNewline` | 文件末尾添加换行 | 与 `.editorconfig` 的 `insert_final_newline=true` 一致 | - -### 2.8 文件类型覆盖说明 - -oxfmt 对不同文件类型的处理方式: - -| 文件类型 | 格式化方式 | -| ------------------------- | --------------------------------------------- | -| JS / TS / JSX / TSX | oxfmt 原生格式化 | -| Vue SFC | oxfmt 原生格式化(`