diff --git a/CLAUDE.md b/CLAUDE.md index c8d0b9f7..57a6bc9c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -90,7 +90,7 @@ Umi Max (`@umijs/max`) is the meta-framework. It wraps the build pipeline and pr - **@tanstack/react-query** for complex server state (e.g., table-list uses `useMutation` + `useQuery`) - Most pages use ProTable's built-in `request` prop for data loading -### Styling: Three Systems Coexist +### Styling Systems 1. **Tailwind CSS v4** — entry: `src/tailwind.css`, PostCSS plugin in `postcss.config.js`. Best for layout utilities 2. **antd-style v4** (`createStyles`) — CSS-in-JS with design token access (`{ token }`). Preferred when consuming theme tokens @@ -117,6 +117,12 @@ Each page directory contains its own index.tsx, optional service.ts, _mock.ts, d `cloudflare-worker/` is a separate deployable (Hono framework, own `package.json`/`tsconfig.json`). Not an npm workspace — manage independently. Provides the production demo API. +```bash +cd cloudflare-worker +npm run dev # Local dev (wrangler dev) +npm run deploy # Deploy to Cloudflare (wrangler deploy) +``` + ## Ant Design CLI `@ant-design/cli` (antd) is installed as a dev dependency. It provides offline antd component metadata and project analysis. Run via `npx antd`. @@ -142,4 +148,13 @@ The CLI also supports MCP server mode: `npx antd mcp` (for IDE integrations). - **Auto-generated code in `src/services/`** is excluded from Biome linting. Never edit manually — regenerate with `npm run openapi`. - **Adding a new page**: 1) Create component in `src/pages/` 2) Add route in `config/routes.ts` 3) Add menu translation in `src/locales/` (route `name` maps to `menu.xxx` i18n key) - **Adding global state**: Create a file in `src/models/` exporting a custom Hook, use `useModel('filename')` in components -- **Access control**: Route-level via `access` field in routes; component-level via `` or `useAccess()` hook from `@umijs/max` \ No newline at end of file +- **Access control**: Route-level via `access` field in routes; component-level via `` or `useAccess()` hook from `@umijs/max` + +## Gotchas & Troubleshooting + +- **Umi cache issues**: If dev server behaves unexpectedly, delete `src/.umi` and restart. This directory is auto-generated and safe to remove. +- **Port 8000 in use**: Umi defaults to port 8000. Use `PORT=3000 npm start` to change it. +- **Mock not updating**: Restart dev server after adding new mock files; Umi auto-discovers `mock/` and `src/pages/**/_mock.ts` on startup only. +- **`npm run simple` is irreversible**: Always commit before running it — it deletes demo pages and replaces routes. +- **Biome + ESLint conflict**: This project uses Biome only. Do not install ESLint or Prettier plugins. +- **Lock file**: Uses `package-lock.json`. If deps break, delete `node_modules` and reinstall. \ No newline at end of file diff --git a/docs/cheatsheet.en-US.md b/docs/cheatsheet.en-US.md index d017a0da..9dc6f76f 100644 --- a/docs/cheatsheet.en-US.md +++ b/docs/cheatsheet.en-US.md @@ -100,6 +100,7 @@ npm install # Update dependencies **Route config** is in `config/routes.ts`: ```ts +// File: config/routes.ts export default [ { path: '/welcome', @@ -143,6 +144,7 @@ const location = useLocation(); // current route info **ProLayout config** is in `config/defaultSettings.ts`: ```ts +// File: config/defaultSettings.ts export default { navTheme: 'light', // nav theme: light / dark colorPrimary: '#1890ff', // primary color @@ -181,7 +183,7 @@ const Page = () => ( **useModel — lightweight global state:** Create a file in `src/models/` to auto-register: ```ts -// src/models/counter.ts +// File: src/models/counter.ts import { useState } from 'react'; export default function useCounter() { @@ -229,7 +231,7 @@ const mutation = useMutation({ **Initial state — getInitialState:** Define in `src/app.tsx`, accessible globally: ```tsx -// src/app.tsx +// File: src/app.tsx export async function getInitialState() { const currentUser = await fetchUserInfo(); return { currentUser }; @@ -249,6 +251,7 @@ const { initialState } = useModel('@@initialState'); **Request config** is in `src/app.tsx`: ```ts +// File: src/app.tsx export const request: RequestConfig = { baseURL: 'https://api.example.com', timeout: 10000, @@ -288,6 +291,7 @@ Auto-generates API calling code under `src/services/` based on `config/oneapi.js **Define permissions** in `src/access.ts`: ```ts +// File: src/access.ts export default function access(initialState: { currentUser?: API.CurrentUser }) { const { currentUser } = initialState; return { @@ -441,7 +445,7 @@ Test files go next to the component, named `*.test.ts(x)`. **Mock data:** Create files in `mock/`: ```ts -// mock/user.ts +// File: mock/user.ts export default { 'GET /api/currentUser': { name: 'Serati Ma', access: 'admin' }, 'POST /api/login': (req, res) => { res.end('ok'); }, @@ -453,6 +457,7 @@ Umi auto-registers mocks, active in dev mode. **Proxy config** is in `config/proxy.ts`: ```ts +// File: config/proxy.ts export default { dev: { '/api/': { @@ -488,3 +493,71 @@ Create a file in `src/models/` exporting a custom Hook, then use `useModel('file 1. Configure `openAPI` in `config/config.ts` 2. Run `npm run openapi` 3. Code is auto-generated under `src/services/` → See [umi FAQ](https://umijs.org/en-US/docs/introduce/faq) + +## Common Tasks + +### Add a New Page + +```bash +# 1. Create the page component +# File: src/pages/my-page/index.tsx + +# 2. Register in route config +# File: config/routes.ts +# { path: '/my-page', name: 'myPage', icon: 'file', component: './my-page' } + +# 3. Add i18n translations (for menu display) +# File: src/locales/zh-CN/menu.ts → menu.myPage: '我的页面' +# File: src/locales/en-US/menu.ts → menu.myPage: 'My Page' +``` + +### Add Global State + +```bash +# 1. Create a model file (filename becomes the model key) +# File: src/models/myModel.ts +# Export a custom Hook: export default function useMyModel() { ... } + +# 2. Use in components +# import { useModel } from '@umijs/max'; +# const { data } = useModel('myModel'); // 'myModel' matches filename +``` + +### Add a Mock API + +```bash +# Global mock: mock/api.ts (applies to all environments) +# Page-level mock: src/pages/my-page/_mock.ts (auto-discovered by Umi) + +# Mock format: +# export default { 'GET /api/my-data': { data: [] } } +``` + +### Generate API Service Code + +```bash +# 1. Edit OpenAPI config: config/oneapi.json +# 2. Run generation (overwrites src/services/ant-design-pro/) +npm run openapi +# 3. Never edit generated code manually — modify oneapi.json and regenerate +``` + +### Switch to Simple Mode + +```bash +git add -A && git commit -m "chore: save before simple" # Must commit first +npm run simple # Irreversible +npm install # Update dependencies +``` + +## Constraints & Gotchas + +- **`src/services/ant-design-pro/`** is auto-generated code. Do NOT edit manually. Modify `config/oneapi.json` and run `npm run openapi` to regenerate. +- **`npm run simple` is irreversible**: It deletes demo pages and unused dependencies. Always commit before running. +- **`.umi` temp directory**: `src/.umi` is auto-generated by Umi. Delete it and restart the dev server if you encounter unexpected behavior. +- **Biome over ESLint**: This project uses Biome for linting and formatting. Do not install ESLint or Prettier plugins. +- **Commit convention**: Must follow [Conventional Commits](https://www.conventionalcommits.org/) (e.g., `feat:`, `fix:`, `chore:`). +- **`npx antd lint ./src`**: Must pass with zero errors and warnings before committing. +- **Mock priority**: `mock/` directory for global mocks, `src/pages/**/_mock.ts` for page-level mocks. Both are auto-registered by Umi. +- **Styling priority**: Tailwind (layout) > antd-style (theme tokens) > CSS Modules (component styles) > Less (legacy global styles only). +- **Path aliases**: `@/*` → `./src/*`, `@@/*` → `./src/.umi/*` diff --git a/docs/cheatsheet.zh-CN.md b/docs/cheatsheet.zh-CN.md index f640e875..b990e6ca 100644 --- a/docs/cheatsheet.zh-CN.md +++ b/docs/cheatsheet.zh-CN.md @@ -100,6 +100,7 @@ npm install # 更新依赖 **路由配置** 位于 `config/routes.ts`: ```ts +// File: config/routes.ts export default [ { path: '/welcome', @@ -143,6 +144,7 @@ const location = useLocation(); // 当前路由信息 **ProLayout 配置** 位于 `config/defaultSettings.ts`: ```ts +// File: config/defaultSettings.ts export default { navTheme: 'light', // 导航主题:light / dark colorPrimary: '#1890ff', // 主题色 @@ -181,7 +183,7 @@ const Page = () => ( **useModel — 轻量全局状态:** 在 `src/models/` 下创建文件即自动注册: ```ts -// src/models/counter.ts +// File: src/models/counter.ts import { useState } from 'react'; export default function useCounter() { @@ -229,7 +231,7 @@ const mutation = useMutation({ **初始状态 — getInitialState:** 在 `src/app.tsx` 中定义,全局可访问: ```tsx -// src/app.tsx +// File: src/app.tsx export async function getInitialState() { const currentUser = await fetchUserInfo(); return { currentUser }; @@ -249,6 +251,7 @@ const { initialState } = useModel('@@initialState'); **请求配置** 位于 `src/app.tsx`: ```ts +// File: src/app.tsx export const request: RequestConfig = { baseURL: 'https://api.example.com', timeout: 10000, @@ -288,6 +291,7 @@ npm run openapi **定义权限** 在 `src/access.ts`: ```ts +// File: src/access.ts export default function access(initialState: { currentUser?: API.CurrentUser }) { const { currentUser } = initialState; return { @@ -441,7 +445,7 @@ npm run test:update # 更新快照 **Mock 数据:** 在 `mock/` 目录下创建文件: ```ts -// mock/user.ts +// File: mock/user.ts export default { 'GET /api/currentUser': { name: 'Serati Ma', access: 'admin' }, 'POST /api/login': (req, res) => { res.end('ok'); }, @@ -453,6 +457,7 @@ Umi 自动注册 mock,开发模式下生效。 **代理配置** 位于 `config/proxy.ts`: ```ts +// File: config/proxy.ts export default { dev: { '/api/': { @@ -488,3 +493,71 @@ export default { 1. 在 `config/config.ts` 配置 `openAPI` 2. 运行 `npm run openapi` 3. 自动生成 `src/services/` 下的代码 → 更多内容见 [umi FAQ](https://umijs.org/docs/introduce/faq) + +## 常见任务 + +### 添加新页面 + +```bash +# 1. 创建页面组件 +# 文件路径:src/pages/my-page/index.tsx + +# 2. 在路由配置中注册 +# 文件路径:config/routes.ts +# { path: '/my-page', name: 'myPage', icon: 'file', component: './my-page' } + +# 3. 添加国际化翻译(如需菜单显示) +# 文件路径:src/locales/zh-CN/menu.ts → menu.myPage: '我的页面' +# 文件路径:src/locales/en-US/menu.ts → menu.myPage: 'My Page' +``` + +### 添加全局状态 + +```bash +# 1. 创建 model 文件(文件名即 model key) +# 文件路径:src/models/myModel.ts +# 导出自定义 Hook:export default function useMyModel() { ... } + +# 2. 在组件中使用 +# import { useModel } from '@umijs/max'; +# const { data } = useModel('myModel'); // 'myModel' 对应文件名 +``` + +### 添加 Mock 接口 + +```bash +# 全局 Mock:mock/api.ts(匹配所有环境) +# 页面级 Mock:src/pages/my-page/_mock.ts(Umi 自动发现) + +# Mock 格式: +# export default { 'GET /api/my-data': { data: [] } } +``` + +### 生成 API 服务代码 + +```bash +# 1. 编辑 OpenAPI 配置:config/oneapi.json +# 2. 运行生成命令(覆盖 src/services/ant-design-pro/) +npm run openapi +# 3. 不要手动编辑生成代码,改 oneapi.json 重新生成 +``` + +### 切换到精简模式 + +```bash +git add -A && git commit -m "chore: save before simple" # 必须先提交 +npm run simple # 不可逆操作 +npm install # 更新依赖 +``` + +## 注意事项 + +- **`src/services/ant-design-pro/`** 为自动生成代码,禁止手动编辑。修改 `config/oneapi.json` 后执行 `npm run openapi` 重新生成 +- **`npm run simple` 不可逆**:会删除示例页面和多余依赖,执行前务必提交代码 +- **`.umi` 临时目录**:`src/.umi` 由 Umi 自动生成,遇到异常可删除后重启开发服务器 +- **Biome 代替 ESLint**:项目使用 Biome 进行 lint 和格式化,不要安装 ESLint 或 Prettier 插件 +- **Commit 规范**:必须遵循 [Conventional Commits](https://www.conventionalcommits.org/),如 `feat:`, `fix:`, `chore:` 等 +- **`npx antd lint ./src`**:提交前必须零错误零警告 +- **Mock 优先级**:`mock/` 目录为全局 Mock,`src/pages/**/_mock.ts` 为页面级 Mock,两者都会被 Umi 自动注册 +- **样式优先级**:Tailwind(布局)> antd-style(主题 token)> CSS Modules(组件样式)> Less(仅遗留全局样式) +- **路径别名**:`@/*` → `./src/*`,`@@/*` → `./src/.umi/*`