内部配置包

@skyroc/config

共享 Oxlint 预设(base / react / next / react-native)+ Vitest 共享常量与配置对象

概览

包名@skyroc/config
目录internal/config
版本1.0.0
private
构建tsdown(entry src/vitest/index.ts,ESM + dts)→ dist/
内容oxlint/ 4 个 JSON 预设 + src/vitest/ 共享配置

两种工具的接入形式不同:Oxlint 走 JSON extends(相对路径)Vitest 走 TS 模块 import(包名子路径)

快速上手

// apps/admin/.oxlintrc.json
{ "extends": ["../../internal/config/oxlint/react.json"] }
// packages/@core/service/vitest.config.ts
import { COVERAGE_EXCLUDE, baseCoverageConfig, baseTestConfig } from '@skyroc/config/vitest';
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    ...baseTestConfig,
    coverage: {
      ...baseCoverageConfig,
      exclude: [...COVERAGE_EXCLUDE, 'src/cli/**']
    }
  }
});

子入口

{
  "files": ["dist", "oxlint"],
  "exports": {
    "./oxlint/base.json": "./oxlint/base.json",
    "./oxlint/next.json": "./oxlint/next.json",
    "./oxlint/react.json": "./oxlint/react.json",
    "./package.json": "./package.json",
    "./vitest": {
      "types": "./dist/index.d.mts",
      "default": "./dist/index.mjs"
    }
  }
}

JSON 暴露源路径,TS 模块只暴露 dist(避免应用层意外编译 TS 源)。

仓库内所有 .oxlintrc.json 用的都是相对路径 ../../internal/config/oxlint/*.json——oxlint 自己解析 extends,不走 Node 的 exports 字段,所以 exports 里漏掉的 ./oxlint/react-native.json 并不影响使用。

Oxlint 预设

文件extends新增 plugins适用
oxlint/base.jsonnode / import / unicorn / typescript / eslint / oxc / vitest(+ jsPlugin eslint-plugin-sort所有 TS / JS 包
oxlint/react.jsonbasereactReact 应用 / 组件库
oxlint/next.jsonreactjsx-a11y、nextjsNext.js 应用(文档站、playground)
oxlint/react-native.jsonreact— (加 RN 全局变量)RN 包与 Expo 应用

预设详解

base.json

类别开关是理解这份配置的前提:

{
  "categories": {
    "correctness": "off",
    "suspicious": "error"
  }
}

correctness 整类被关掉,改为在 rules逐条显式开启——这样规则集是白名单,升级 oxlint 时不会凭空多出一批报错。

关键规则(节选):

规则级别说明
eqeqeqerror强制 === / !==
no-var / prefer-consterrorprefer-constdestructuring: "all"
no-unused-varserror^_ 前缀的变量与参数豁免
no-shadow / no-param-reassignerror禁变量遮蔽与参数重赋值
complexity / max-depth / max-params / max-nested-callbackserror复杂度、嵌套、参数、回调层数上限
no-nested-ternary / no-lonely-if / no-else-returnerror控制流可读性
no-plusplus / no-bitwise / no-continueerror风格性禁令
prefer-template / object-shorthand / prefer-object-spreaderror现代语法
no-await-in-looperror循环内 await 一律报错
no-warning-commentserrorTODO / FIXME 留在代码里会失败
unicorn/prefer-node-protocolerrorNode 内置模块必须写 node:fs
import/first / import/no-duplicateserrorimport 组织

jsPlugins: ["eslint-plugin-sort"] 额外接入了一组排序规则,这是仓库里最容易撞到的一类:

规则级别作用
sort/import-memberserror单条 import 的具名成员按自然序、区分大小写
sort/string-unions / sort/string-enumserror字符串联合类型、字符串枚举成员排序
sort/exportswarnexport 语句按分组顺序(依赖 → 其他 → 相对路径 → 无源 → default)
sort/export-members / sort/type-properties / sort/destructuring-propertieswarn导出成员、类型属性、解构属性排序

overrides 分四组:

files作用
**/scripts/****/cli.*关掉 no-console(CLI 需要输出)
__tests__/***.test.**.spec.**.bench.*关掉 no-unused-expressions(断言写法)
**/*.?([cm])[jt]s?(x)打开全部 typescript/* 规则;同时关掉一批被 TS 编译器覆盖的 ESLint 规则no-const-assignno-dupe-keysconstructor-superno-this-before-superno-obj-calls 等)——类型检查已经报错,无需 lint 重复报
**/*.js**/*.cjs放开 typescript/no-require-imports

TypeScript 相关的关键取舍:

规则级别说明
typescript/consistent-type-importserrorprefer: "type-imports",与 tsconfig 的 verbatimModuleSyntax 配套
typescript/no-explicit-anyoff允许 any,不硬限
typescript/no-non-null-assertionoff允许 !
typescript/ban-ts-commenterror@ts-expect-error 必须写至少 10 个字符的理由
typescript/no-namespaceerror全局类型用 .d.ts 声明而非 namespace
typescript/consistent-type-definitionsofftypeinterface 不强制二选一

react.json

在 base 之上加 react 插件。最重要的一条是禁用 useCallback

{
  "no-restricted-imports": [
    "error",
    {
      "paths": [
        {
          "name": "react",
          "importNames": ["useCallback"],
          "message": "useCallback is forbidden — see AGENTS.md §2. Hoist the function, use a ref, or re-draw the component boundary instead."
        }
      ]
    }
  ]
}

这条规则把 AGENTS.md 的组件规范落成了 lint 错误,详见 编码规范

其余:

规则级别说明
react/hook-use-stateerroruseState 返回值命名必须成对(允许解构)
react/self-closing-comperror空组件与空 html 标签必须自闭合
react/jsx-curly-brace-presencewarn字符串 props / children 不写多余大括号
react/jsx-fragmentswarn<> 语法而非 <Fragment>
react/jsx-no-useless-fragmentwarn无意义 Fragment
react/only-export-componentswarn允许额外导出 loader / action / handle / shouldRevalidate(React Router 约定)
react/react-in-jsx-scopeoff新 JSX transform

**/*.jsx**/*.tsx 的 override 里再开 react/rules-of-hooks(error)、react/exhaustive-deps(error)、react/jsx-keyreact/display-name 等。

next.json

extends react,追加 jsx-a11ynextjs 插件,打开整套 nextjs/* 规则(no-html-link-for-pagesno-document-import-in-pageinline-script-id 等为 error,其余多为 warn),并把 react/only-export-components 关掉——Next.js 的 page.tsx 需要同时导出 metadatagenerateStaticParams

react-native.json

extends react,主要做三件事:

  • 注入 RN 全局变量:__DEV__ErrorUtilsHermesInternal__turboModuleProxynativeFabricUIManager_WORKLET(Reanimated worklet);
  • 关掉 unicorn/no-array-reverseunicorn/no-array-sortreact/no-unescaped-entities(RN 文本节点没有 HTML 转义问题);
  • react/exhaustive-deps 降为 warn,no-use-before-define 放开 variables(RN 里 StyleSheet.create 常写在组件下方)。

Vitest 共享配置

src/vitest/index.ts 经 tsdown 构建为 ESM,通过 @skyroc/config/vitest 引用:

import {
  COVERAGE_EXCLUDE,
  COVERAGE_PROVIDER,
  SOURCE_PATTERNS,
  TEST_ENVIRONMENT,
  TEST_PATTERNS,
  baseCoverageConfig,
  baseTestConfig
} from '@skyroc/config/vitest';

导出常量

常量
TEST_ENVIRONMENT'happy-dom'
COVERAGE_PROVIDER'v8'
TEST_PATTERNS['__tests__/**/*.test.ts', '__tests__/**/*.test.tsx']
SOURCE_PATTERNS['src/**/*.ts', 'src/**/*.tsx']
COVERAGE_EXCLUDE['**/*.test.ts', '**/*.test.tsx', '**/index.ts', '**/*.d.ts', '**/vitest.setup.ts']

测试文件只认 __tests__/ 目录——src/ 里的 *.test.ts 不会被匹配到。

预设对象

export const baseTestConfig: InlineConfig = {
  globals: true,
  environment: TEST_ENVIRONMENT,
  include: TEST_PATTERNS
};

export const baseCoverageConfig: CoverageOptions = {
  provider: COVERAGE_PROVIDER,
  enabled: true,
  include: SOURCE_PATTERNS,
  exclude: COVERAGE_EXCLUDE
};

baseTestConfig 不含 setupFiles,需要前置文件的包(packages/hookspackages/@core/utilspackages/@core/state)在自己的 vitest.config.ts 里加;baseCoverageConfig不含 reporter,用 vitest 默认值。

仓库内实际使用

Oxlint:

预设使用方
base.json仓库根 .oxlintrc.json
react.jsonapps/{admin,admin-example,ruoyi-plus-fast}packages/web/{admin,admin-layouts,admin-notification,admin-theme,materials}packages/web/ui/{shadcn,antd,compose}create-skyroc 构建时会展平到生成项目
next.jsonapps/web-ui-playgrounddocs/{project-docs,core-docs,web-kit-docs,web-ui-docs}
react-native.jsonpackages/native/uiapps/native-ui-playground

docs/docsdocs/admin-docsdocs/native-ui-docs 目前是各自独立的 .oxlintrc.json没有 extends 本包,属于待收敛项。

Vitest: 17 个子包的 vitest.config.ts 以及根 vitest.config.ts 都从 @skyroc/config/vitest 取值。根配置只复用常量(TEST_ENVIRONMENT / COVERAGE_PROVIDER / SOURCE_PATTERNS / COVERAGE_EXCLUDE),自己定义根视角的 includepackages/**/__tests__/**)、排除走 Jest 的 packages/native/**,并把覆盖率范围限定在已有测试的包上,避免无测试包刷出大量 0%。

lint 脚本:

位置脚本
仓库根turbo run lint
apps/*packages/web/ui/*packages/native/uioxlint --fix
docs/docsoxlint

升级影响范围

改预设会自动影响所有 extends / import 它的包,流程是:

  1. 修改预设 JSON 或 vitest 常量;
  2. 在仓库根跑 pnpm lintpnpm test 确认所有包通过;
  3. 一次性修完违规再提交。

规则集中带来的好处是治理简单,代价是引入新规则的成本一次性付清。

相关文档

Last updated on