|
1 | 1 | # NaiveTab 开发规范 |
2 | 2 |
|
3 | | -NaiveTab 是一个浏览器新标签页扩展项目。本文档是 AI 开发入口,详情见 `.claude/rules/` 和 `docs/`。 |
| 3 | +浏览器新标签页扩展(Vue 3 + Vite + Reka UI)。详情见 `.claude/rules/` 和 `docs/`。 |
| 4 | + |
| 5 | +## 命令速查 |
| 6 | + |
| 7 | +```bash |
| 8 | +pnpm dev # 开发模式(clear → prepare → background + web + js 并行) |
| 9 | +pnpm build # 生产构建(chrome + firefox) |
| 10 | +pnpm build:debug # 不压缩的 chrome 构建 |
| 11 | +pnpm typecheck # vue-tsc --noEmit |
| 12 | +pnpm test # vitest(测试文件在 src/logic/__tests__/) |
| 13 | +pnpm lint:fix # ESLint --fix |
| 14 | +pnpm check-patterns # CSS 模式检查(v-bind()、&--modifier、Reka z-index) |
| 15 | +``` |
| 16 | + |
| 17 | +**pre-commit 自动执行**:`lint-staged → typecheck → test --run → validate-registries → check-patterns`。提交前务必全部通过。 |
| 18 | + |
| 19 | +## 核心规则 |
4 | 20 |
|
5 | | -**核心规则**: |
6 | | -- 所有输出**必须中文**。遇到不清楚的**先问再动手**。改代码前**先给方案**。 |
| 21 | +- **输出必须中文**。不清楚先问再动手。改代码前先给方案。 |
7 | 22 | - 代码改动后**主动更新**受影响的文档、注释、单测(见 [documentation-sync.md](.claude/rules/documentation-sync.md))。 |
8 | 23 | - 编码行为准则见 [coding-principles.md](.claude/rules/coding-principles.md)。 |
9 | | -- **新增 Reka 组件必须先对照标杆**(shadcn/ui + Radix Themes),再写代码。步骤见 [reka-ui.md 检查清单](docs/architecture/reka-ui.md#新增-reka-组件检查清单)。 |
| 24 | +- **新增 Reka 组件必须先对照标杆**(shadcn/ui + Radix Themes),步骤见 [reka-ui.md](docs/architecture/reka-ui.md#新增-reka-组件检查清单)。 |
| 25 | + |
| 26 | +## 行为规则(`.claude/rules/`,通过 `opencode.json` 自动注入) |
| 27 | + |
| 28 | +| 文件 | 内容 | |
| 29 | +|------|------| |
| 30 | +| [coding-principles.md](.claude/rules/coding-principles.md) | 编码行为准则(思考优先、简单至上、手术式改动、目标驱动) | |
| 31 | +| [communication.md](.claude/rules/communication.md) | 中文输出、不猜测、先给方案 | |
| 32 | +| [documentation-sync.md](.claude/rules/documentation-sync.md) | 代码改动后主动同步文档 | |
| 33 | +| [no-hardcode.md](.claude/rules/no-hardcode.md) | 禁止硬编码图标(ICONS)和文本(i18n) | |
| 34 | +| [workflow.md](.claude/rules/workflow.md) | 不启动 dev server、不改版本号、不重复造轮子 | |
| 35 | +| [pitfalls.md](.claude/rules/pitfalls.md) | 踩坑索引 → [CSS](.claude/rules/pitfalls-css.md) / [Vue](.claude/rules/pitfalls-vue.md) / [配置](.claude/rules/pitfalls-config.md) / [快捷键](.claude/rules/pitfalls-keyboard.md) / [后台](.claude/rules/pitfalls-background.md) | |
| 36 | + |
| 37 | +## 架构要点 |
| 38 | + |
| 39 | +### 4 个执行上下文 |
| 40 | + |
| 41 | +| 上下文 | 入口 | 限制 | |
| 42 | +|--------|------|------| |
| 43 | +| **newtab** | `src/newtab/` | Vue 页面,完整 DOM/BOM API | |
| 44 | +| **CS** | `src/contentScripts/` | 注入普通网页,不可用 `localStorage` | |
| 45 | +| **SW** | `src/background/` | Service Worker,不可用 DOM API | |
| 46 | +| **popup** | `src/popup/` | 扩展弹窗 | |
| 47 | + |
| 48 | +修改 `config/`、`keyboard/`、`shortcut/`、`utils/` 等共享代码时,必须逐一验证 4 个上下文。 |
| 49 | + |
| 50 | +### 构建系统 |
10 | 51 |
|
11 | | -技能:`/add-widget` 新增 Widget、`/add-command` 新增命令快捷键。 |
| 52 | +3 个 Vite 配置,分别构建不同入口: |
12 | 53 |
|
13 | | ---- |
| 54 | +| 配置 | 入口 | 产物 | |
| 55 | +|------|------|------| |
| 56 | +| `vite.config.ts` | `src/newtab/`、`src/popup/`、`src/options/` | 主 web 页面 | |
| 57 | +| `vite.config.content.ts` | `src/contentScripts/index.ts` | CS(IIFE) | |
| 58 | +| `vite.config.background.ts` | `src/background/main.ts` | SW(ES module) | |
14 | 59 |
|
15 | | -# src/logic/ 目录结构 |
| 60 | +`src/manifest.ts` 动态生成 `manifest.json`,非静态文件。 |
| 61 | + |
| 62 | +### 自动注入(禁止手动 import) |
| 63 | + |
| 64 | +- `vue` 全家桶(`ref`、`computed`、`watch` 等)— 全局自动导入 |
| 65 | +- `webextension-polyfill` → `browser` 变量 — 全局可用 |
| 66 | +- `dayjs` → `dayjs` 函数 — 全局可用 |
| 67 | +- `src/components/` 下所有组件 — 自动注册,直接用 `<NtXxx />` |
| 68 | +- 路径别名 `@/` → `src/` |
| 69 | + |
| 70 | +## 全局状态速查 |
| 71 | + |
| 72 | +```ts |
| 73 | +// src/logic/config/state.ts |
| 74 | +localConfig // Widget 配置(响应式,自动持久化,云同步) |
| 75 | +localState // 本地状态(currAppearanceCode 等,持久化) |
16 | 76 |
|
17 | | -| 目录 | 职责 | 核心文件 | |
18 | | -|------|------|----------| |
19 | | -| `config/` | 配置系统:默认值、合并、迁移、压缩、版本比较、Widget 配置重置、响应式存储 | `state.ts`(`localConfig`/`localState`)、`update.ts`(版本迁移)、`reset.ts` | |
20 | | -| `config/sync/` | 云端同步:上传/下载/合并/导入导出、同步状态 computed、跨上下文监听、防竞态 | `upload.ts`、`loader.ts`、`manage.ts`、`state.ts`、`pending-writes.ts` | |
21 | | -| `constants/` | 纯常量:应用、字体、图标、搜索、URL、天气单位 | `icons.ts`(`ICONS`/`WIDGET_ICON_META`)、`weather.ts` | |
22 | | -| `image/` | 背景图系统:状态、图库、渲染、工具、来源常量 | `state.ts`、`gallery.ts`、`service.ts`、`utils.ts`、`constants.ts` | |
23 | | -| `keyboard/` | 键盘系统:布局转换、键帽主题、常量、书签状态/导出、19 种布局定义 | `keyboard-layout.ts`、`themes/`(80+ 主题)、`layouts/`(19 种布局) | |
24 | | -| `bookmark/` | 纯书签:浏览器书签 API 封装、书签树解析、书签变更操作 | `api.ts`、`parser.ts`、`mutations.ts` | |
25 | | -| `shortcut/` | 全局快捷键:命令定义、匹配核心、Port 连接、newtab 页面执行器 | `shortcut-command.ts`、`matcher.ts`、`port.ts`、`shortcut-executor.ts` | |
26 | | -| `store/` | 运行时状态:全局状态、样式工具、主题切换、DOM 副作用监听 | `state.ts`(`globalState`)、`style.ts`、`theme.ts`、`dom.ts` | |
27 | | -| `utils/` | 基础设施:数据库、GA 上报、权限、通用工具 | `database.ts`、`gtag.ts`、`permission.ts`、`common.ts` | |
28 | | -| `task/` | 任务调度:keydown 事件分发、rAF 定时器、页面可见性/focus 监听、事件总线 | `index.ts`、`keydown.ts`、`timer.ts`、`events.ts` | |
| 77 | +// src/logic/store/state.ts |
| 78 | +globalState // 运行时全局状态(不持久化,不云同步) |
| 79 | +``` |
29 | 80 |
|
30 | | -根目录独立子系统:`moveable.ts`(拖拽定位)、`guide.ts`(引导)、`poetry.ts`(诗词)。 |
| 81 | +## src/logic/ 目录结构 |
31 | 82 |
|
32 | | ---- |
| 83 | +| 目录 | 职责 | |
| 84 | +|------|------| |
| 85 | +| `config/` | 配置系统:默认值、合并、迁移、压缩、版本比较、响应式存储 | |
| 86 | +| `config/sync/` | 云端同步:上传/下载/合并/导入导出、跨上下文监听 | |
| 87 | +| `constants/` | 纯常量:图标(`ICONS`/`WIDGET_ICON_META`)、天气单位 | |
| 88 | +| `image/` | 背景图系统:状态、图库、渲染、来源常量 | |
| 89 | +| `keyboard/` | 键盘系统:布局转换、键帽主题(80+)、19 种布局定义 | |
| 90 | +| `bookmark/` | 浏览器书签 API 封装、书签树解析 | |
| 91 | +| `shortcut/` | 全局快捷键:命令定义、匹配核心、Port 连接 | |
| 92 | +| `store/` | 运行时状态:全局状态、主题切换、DOM 副作用监听 | |
| 93 | +| `utils/` | 基础设施:数据库、GA 上报、权限、通用工具 | |
| 94 | +| `task/` | 任务调度:keydown 分发、rAF 定时器、事件总线 | |
33 | 95 |
|
34 | | -# 文档索引 |
| 96 | +## 文档索引 |
35 | 97 |
|
36 | | -开发时**必须先查阅对应文档**,确认既有设计后再动手。 |
| 98 | +开发时**先查对应文档**,确认既有设计后再动手。 |
37 | 99 |
|
38 | 100 | | 文档 | 主题 | |
39 | 101 | |------|------| |
40 | 102 | | [config.md](docs/architecture/config.md) | 三层配置架构、配置迁移、主题系统 | |
41 | | -| [storage.md](docs/architecture/storage.md) | 存储与同步、Gzip 压缩、版本感知同步 | |
| 103 | +| [storage.md](docs/architecture/storage.md) | 存储与同步、Gzip 压缩 | |
42 | 104 | | [development.md](docs/conventions/development.md) | 编码风格(CSS/Vue/TS)+ 测试架构 | |
43 | 105 | | [messaging.md](docs/architecture/messaging.md) | 背景脚本消息传递 | |
44 | 106 | | [background.md](docs/architecture/background.md) | 背景图系统 | |
45 | 107 | | [global-shortcut.md](docs/features/global-shortcut.md) | 全局命令快捷键 | |
46 | | -| [bookmark.md](docs/features/bookmark.md) | 书签系统、双模式、同步、权限 | |
| 108 | +| [bookmark.md](docs/features/bookmark.md) | 书签系统 | |
47 | 109 | | [keyboard.md](docs/features/keyboard.md) | 键盘布局、拖拽、主题 | |
48 | 110 | | [widget-dev.md](docs/widgets/widget-dev.md) | Widget 生命周期、WidgetWrap、定时任务 | |
49 | 111 | | [setting.md](docs/architecture/setting.md) | Setting 面板、注册、字段组件 | |
50 | 112 | | [task.md](docs/architecture/task.md) | 定时任务系统 | |
51 | 113 | | [background-modules.md](docs/architecture/background-modules.md) | SW 内部模块 | |
52 | | -| [moveable.md](docs/architecture/moveable.md) | Widget 拖拽定位系统 | |
53 | | -| [api.md](docs/architecture/api.md) | 外部 API 封装(天气、图片、搜索、诗词) | |
54 | | -| [reka-ui.md](docs/architecture/reka-ui.md) | Reka UI 组件开发规范(封装模式、CSS 命名、状态模板、Token)+ **设计参考与标杆** | |
| 114 | +| [moveable.md](docs/architecture/moveable.md) | Widget 拖拽定位 | |
| 115 | +| [api.md](docs/architecture/api.md) | 外部 API 封装 | |
| 116 | +| [reka-ui.md](docs/architecture/reka-ui.md) | Reka UI 封装规范 + 设计标杆 | |
55 | 117 | | [pitfalls.md](.claude/rules/pitfalls.md) | 踩坑索引(CSS/Vue/配置/快捷键/后台) | |
56 | 118 |
|
57 | | -## 行为规则(`.claude/rules/` 自动加载) |
58 | | - |
59 | | -| 文件 | 内容 | |
60 | | -|------|------| |
61 | | -| [coding-principles.md](.claude/rules/coding-principles.md) | 编码行为准则(思考优先、简单至上、手术式改动、目标驱动) | |
62 | | -| [communication.md](.claude/rules/communication.md) | 中文输出、不猜测、先给方案 | |
63 | | -| [documentation-sync.md](.claude/rules/documentation-sync.md) | 代码改动后主动同步文档 | |
64 | | -| [no-hardcode.md](.claude/rules/no-hardcode.md) | 禁止硬编码图标(ICONS)和文本(i18n) | |
65 | | -| [workflow.md](.claude/rules/workflow.md) | 不启动 dev server、不改版本号、不重复造轮子 | |
66 | | -| [pitfalls.md](.claude/rules/pitfalls.md) | 踩坑索引 → [CSS](.claude/rules/pitfalls-css.md) / [Vue](.claude/rules/pitfalls-vue.md) / [配置](.claude/rules/pitfalls-config.md) / [快捷键](.claude/rules/pitfalls-keyboard.md) / [后台](.claude/rules/pitfalls-background.md) | |
67 | | - |
68 | | ---- |
69 | | - |
70 | | -# 全局状态速查 |
71 | | - |
72 | | -```ts |
73 | | -// src/logic/config/state.ts(localConfig / localState) |
74 | | -// src/logic/store/state.ts(globalState) |
75 | | -localConfig // Widget 配置(响应式,自动持久化,云同步) |
76 | | -localState // 本地状态(currAppearanceCode 等,持久化) |
77 | | -globalState // 运行时全局状态(不持久化,不云同步) |
78 | | -``` |
79 | | - |
80 | | -完整字段说明见 [config.md](docs/architecture/config.md#三层配置架构)。 |
81 | | - |
82 | | ---- |
83 | | - |
84 | | -# 核心开发要点 |
| 119 | +## 核心开发要点 |
85 | 120 |
|
86 | | -- **配置兼容性**:任何持久化配置修改不能破坏老用户数据,必须走 `handleAppUpdate` 迁移 → [pitfalls-config.md](.claude/rules/pitfalls-config.md) |
| 121 | +- **配置兼容性**:任何持久化配置修改必须走 `handleAppUpdate` 迁移,不能破坏老用户数据 → [pitfalls-config.md](.claude/rules/pitfalls-config.md) |
87 | 122 | - **后台脚本**:`onChanged` 监听器必须返回 `Promise`;修改 keyboard 配置时同步改 `config/cache.ts` → [pitfalls-background.md](.claude/rules/pitfalls-background.md) |
88 | | -- **Reka UI 组件**:Vue 封装模式、CSS 状态模板、Token 体系 → [reka-ui.md](docs/architecture/reka-ui.md) |
89 | | -- **样式 & 主题**:颜色用双元素数组 `[浅色, 深色]`;中性灰用 `--gray-alpha-xx` token → [pitfalls-css.md](.claude/rules/pitfalls-css.md) |
90 | | -- **Widget 规则**:用 `/add-widget` 技能或查 [REGISTRY-MAP.md](src/newtab/widgets/REGISTRY-MAP.md);定时任务用 `addTimerTask`;根组件用 `WidgetWrap` 包裹 → [pitfalls-vue.md](.claude/rules/pitfalls-vue.md) |
91 | | -- **Setting 面板**:在 `SETTING_GROUPS` 注册,用 `src/setting/fields` 原子组件,禁止自行封装 → [setting.md](docs/architecture/setting.md) |
92 | | -- **权限管理**:非核心权限放 `optional_permissions`,首次使用时请求 → [permission.ts](src/logic/utils/permission.ts) |
| 123 | +- **样式 & 主题**:颜色用双元素数组 `[浅色, 深色]`;中性灰用 `--gray-alpha-xx` token;禁止 `v-bind()` 和 `&--modifier` → [pitfalls-css.md](.claude/rules/pitfalls-css.md) |
| 124 | +- **图标 & 文本**:图标必须用 `ICONS` 常量,文本必须 i18n(`zh-CN.json` + `en-US.json` 同步更新)→ [no-hardcode.md](.claude/rules/no-hardcode.md) |
| 125 | +- **Widget 规则**:用 `/add-widget` 技能或查 [REGISTRY-MAP.md](src/newtab/widgets/REGISTRY-MAP.md);定时任务用 `addTimerTask`;根组件用 `WidgetWrap` 包裹 |
| 126 | +- **Setting 面板**:在 `SETTING_GROUPS` 注册,用 `src/setting/fields` 原子组件,禁止自行封装 |
| 127 | +- **权限管理**:非核心权限放 `optional_permissions`,首次使用时请求 |
93 | 128 | - **发布**:version 由用户手动改;同步更新 `CHANGELOG.md` |
94 | | -- **注册点校验**:pre-commit 自动运行 `scripts/check/validate-registries.ts` |
| 129 | +- **不启动 dev server**:浏览器扩展 CLI 环境无法查看页面,type-check 通过即可 |
| 130 | +- **不改版本号**:`package.json` 的 version 只能由用户手动修改 |
| 131 | +- **不留历史包袱**:重构时直接更新所有消费者,禁止 re-export 保持"向后兼容" |
| 132 | +- **禁止自动 Git 操作**:未经明确允许,禁止 `git commit/push/revert/reset` |
0 commit comments