Skyroc Admin Docs
工程化

开发约定

组件、Hook、命名、提交、目录的核心代码风格规范

React 组件硬性规范

这些规则在 CLAUDE.md / AGENTS.md 中定义,违反视为代码错误,CodeReview 不通过。

1. 组件必须是箭头函数

const Portal = (props: PortalProps) => {
  // ...
};

❌ 不允许函数声明:

function Portal(props: PortalProps) {}

2. Props 类型必须独立 interface,每个字段必须有注释

interface PortalProps {
  /** 是否在容器不存在时自动创建 */
  autoCreate?: boolean;

  /** 传送门内容 */
  children: ReactNode;

  /** 容器 ID 或 CSS 选择器 */
  container: string | HTMLElement;
}

注释要解释意图,而不是重复 TS 类型。

3. Props 必须在函数体内解构(不能写在参数里)

const Portal = (props: PortalProps) => {
  const {
    autoCreate = false,
    children,
    container
  } = props;
  // ...
};

❌ 禁止:

const Portal = ({ autoCreate, children }: PortalProps) => {};

理由:

  • 单一可预测的入口;
  • 调试 / 重构更稳定;
  • 避免 props 名意外被遮蔽。

4. 内部辅助函数必须是函数声明

const Portal = (props: PortalProps) => {
  function findTargetElement() {
    // ...
  }
  // ...
};

理由:清晰的执行意图、避免闭包污染、栈追踪更友好。

Hook 使用规范

useCallback —— 禁止使用

useCallback 不应该出现在 React 组件代码中。理由

  • React 不是「防止重渲染」的游戏,Hook 是语义工具不是性能工具;
  • 99% 的 useCallback 是过度优化;
  • 真有性能问题应通过架构改造或 React.memo 解决;
  • 项目启用了 React Compiler,绝大多数手工 memo 都是浪费。

useMemo —— 仅允许两种场景

  1. 从逻辑派生一个值(非函数),逻辑非平凡;
  2. 官方建议的昂贵计算(demonstrably expensive,不是预防性)。

其他都禁止。详见 Vercel React 最佳实践 §5.3

react-hooks/exhaustive-deps —— 默认禁止 disable

仅在以下条件同时满足时可禁用:

  • 完全理解依赖模型;
  • 行为是有意为之并已记录。

禁用必须放在文件顶部:

/* eslint-disable react-hooks/exhaustive-deps */

useState vs useRef

用途选择
影响渲染useState
不影响渲染(命令式 / 生命周期 / 可变状态)useRef

不要混用。如果一个值变化频繁但不应触发重绘(如鼠标位置追踪),用 useRef

useEffect 必须有明确意图

Effect 表示:

  • 生命周期绑定;
  • 外部系统同步;
  • DOM / 命令式集成。

读到 Effect 时其目的必须显而易见,副作用必须本地化,创建的资源必须有 cleanup。

不要用 Effect 去模拟「事件回调」或「派生状态」——前者放到 handler,后者直接在 render 里算。

包命名

Scope用法
@skyroc/*所有新包默认使用
@sa/*历史遗留,仅 @sa/uno-config 保留,不再新增

命名风格表

类别风格示例
包名@skyroc/<kebab-case>@skyroc/web-ui
文件kebab-case.tsuse-table.ts
组件文件PascalCase.tsxAdminLayout.tsx
组件PascalCase<AdminLayout />
HookuseXxx 驼峰useAdminState
TypesPascalCaseUserInfo
常量UPPER_SNAKE_CASEDEFAULT_THEME_COLOR

详见 命名规范

TypeScript 风格

约定
interface vs type数据结构 / props 用 interface;联合 / 工具类型用 type
import type启用 verbatimModuleSyntax,强制
全局命名空间Api.*Router.*App.*Theme.*,不要重复 import
严格度全仓库 strict + noUncheckedIndexedAccess
禁用 any工具未禁,但 review 不放过

目录约定

路径含义
apps/<name>/端应用(admin / app / playground 等)
packages/@core/<name>/跨平台无 UI 核心包
packages/shared/<name>/跨平台共享层(types / tokens / hooks)
packages/web/<name>/Web 专属
packages/native/<name>/RN 专属
packages/miniapp/<name>/小程序专属
packages/primitives/<name>/平台无关的「能力原语」(如 form)
internal/<name>/不发布的内部配置
docs/<name>/Fumadocs 文档站

每个包内部强烈建议:

<pkg>/
├── src/
│   ├── index.ts           # 主入口
│   ├── <subentry>.ts      # 子入口(如有)
│   ├── components/        # 组件
│   ├── hooks/             # hooks
│   ├── utils/             # 工具
│   └── types/             # 类型
├── __tests__/
├── README.md
├── package.json
└── tsconfig.json

提交规范

<type>(<scope>): <subject>

<body?>

<footer?>
type含义
feat新功能
fixBug 修复
docs文档
style仅格式(不影响行为)
refactor重构(非新功能 / 非修复)
perf性能
test测试
chore杂项(构建 / 依赖 / 配置)
build构建系统
ciCI 配置
revert回滚

提交工具:pnpm commit(在 apps/admin 等包内),由 sa git-commit 提供交互式表单。详见 Git 提交与发版

通用风格

  • 中文优先:本仓库 commit / PR 描述 / 注释 都允许且鼓励使用中文;
  • 行宽 120;
  • 单引号、分号、空格 2、LF;
  • import 按行组分组(partitionByNewline: true);
  • 不允许 console.log(scripts 包豁免,logger 包用 console.* 是实现)。

与代码风格冲突的来源

优先级内容
1(最高)用户直接指令
2CLAUDE.md / AGENTS.md / Project Rules
3本文档
4工具默认行为

底层冲突以本文档为准;本文档与项目 Rules 冲突以 Rules 为准。

On this page