@lightfish/cli 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/create-lightfish.js +133 -60
  2. package/dist/lightfish.js +160 -87
  3. package/dist/templates/react-vite/.agents/skills/lightfish-server/SKILL.md +447 -0
  4. package/dist/templates/react-vite/.vscode/settings.json +42 -0
  5. package/dist/templates/react-vite/AGENTS.md +254 -0
  6. package/dist/templates/react-vite/README.md +150 -0
  7. package/dist/templates/react-vite/_gitignore +23 -0
  8. package/dist/templates/react-vite/eslint.config.js +25 -0
  9. package/dist/templates/react-vite/index.html +13 -0
  10. package/dist/templates/react-vite/lightfish-server.config.js +6 -0
  11. package/dist/templates/react-vite/package.json +41 -0
  12. package/dist/templates/react-vite/pnpm-lock.yaml +3649 -0
  13. package/dist/templates/react-vite/public/favicon.svg +1 -0
  14. package/dist/templates/react-vite/public/icons.svg +24 -0
  15. package/dist/templates/react-vite/server/router/hello/index.ts +20 -0
  16. package/dist/templates/react-vite/server/schema/index.ts +18 -0
  17. package/dist/templates/react-vite/src/assets/hero.png +0 -0
  18. package/dist/templates/react-vite/src/assets/react.svg +1 -0
  19. package/dist/templates/react-vite/src/assets/vite.svg +1 -0
  20. package/dist/templates/react-vite/src/main.css +1 -0
  21. package/dist/templates/react-vite/src/main.tsx +43 -0
  22. package/dist/templates/react-vite/src/pages/example/index.tsx +26 -0
  23. package/dist/templates/react-vite/src/pages/example/layout.tsx +31 -0
  24. package/dist/templates/react-vite/src/pages/example/model.ts +20 -0
  25. package/dist/templates/react-vite/src/pages/index.tsx +17 -0
  26. package/dist/templates/react-vite/src/pages/layout.tsx +15 -0
  27. package/dist/templates/react-vite/tsconfig.app.json +30 -0
  28. package/dist/templates/react-vite/tsconfig.json +7 -0
  29. package/dist/templates/react-vite/tsconfig.node.json +24 -0
  30. package/dist/templates/react-vite/vite.config.ts +61 -0
  31. package/package.json +3 -2
@@ -0,0 +1,254 @@
1
+ # AGENTS.md — template-vite-server
2
+
3
+ ## 项目概览
4
+
5
+ ### 模板项目开发约定
6
+
7
+ - `src/pages/index.tsx` 是**首页占位页**,仅用于项目初始化时展示,应替换为真实业务首页。
8
+ - `src/pages/example/` 是**示例路由模块**,仅用于演示 `layout + model + index` 的标准写法,新建项目时可直接删除或覆盖。
9
+ - 不要把示例代码当作已实现的业务功能去修改或补全。
10
+ - 新增功能时,遵循本文件约定的目录结构、命名规范和分层方式。
11
+
12
+ ## 全栈架构
13
+
14
+ 本项目是前端 + 后端一体化的全栈模板:
15
+
16
+ - **前端**:Vite + React + TypeScript + Tailwind CSS,使用 `@lightfish/router` 文件系统路由和 `@lightfish/react-model` 状态管理。
17
+ - **后端**:`@lightfish/server` 约定式路由 + Drizzle ORM + PostgreSQL,接口文件放在 `server/router/`。
18
+
19
+ ### 完整目录结构
20
+
21
+ ```
22
+ 项目根/
23
+ ├── src/ # 前端应用
24
+ ├── server/ # lightfish-server 后端
25
+ │ ├── schema/index.ts # Drizzle ORM 数据库 Schema
26
+ │ └── router/ # 约定式路由
27
+ │ └── <module>/index.ts
28
+ ├── lightfish-server.config.js # 后端配置
29
+ └── vite.config.ts # 前端构建配置
30
+ ```
31
+
32
+ ### 常用命令
33
+
34
+ | 命令 | 说明 |
35
+ | --------------- | --------------------------------- |
36
+ | `pnpm dev` | 启动前端开发服务器 |
37
+ | `pnpm build` | 构建前端生产包 |
38
+ | `pnpm lint` | 运行 ESLint |
39
+ | `pnpm db:push` | 同步数据库 schema(改 schema 后必做) |
40
+
41
+ ### 前后端协作流程
42
+
43
+ 1. 在 `server/schema/index.ts` 定义数据表。
44
+ 2. 执行 `pnpm db:push` 同步到数据库。
45
+ 3. 在 `server/router/<模块>/index.ts` 写接口 handler。
46
+ 4. 前端通过 `@lightfish/server/api` 的 `apiRequest` 调用接口。
47
+
48
+ 后端开发详细规范(schema、路由、handler、apiRequest、生产环境约束)见 `.agents/skills/lightfish-server/SKILL.md`。
49
+
50
+ ---
51
+
52
+ | 能力 | 方案 |
53
+ | ----------- | ----------------------------------------------- |
54
+ | 构建工具 | Vite 8 |
55
+ | UI 框架 | React 19 |
56
+ | 类型系统 | TypeScript 6 |
57
+ | 路由方案 | `@lightfish/router` — 文件系统路由 |
58
+ | 状态管理 | `@lightfish/react-model` — 桥接 hook 到 Context |
59
+ | 样式方案 | Tailwind CSS 4 |
60
+ | 代码规范 | ESLint 10 |
61
+ | 后端 / ORM | `@lightfish/server` + Drizzle ORM + PostgreSQL |
62
+
63
+ ---
64
+
65
+ ## 1. 路由 & 页面结构(文件系统路由)
66
+
67
+ ### 路由映射规则
68
+
69
+ | 文件路径 | 路由 |
70
+ | --------------------------------- | ----------------------------------------- |
71
+ | `src/pages/index.tsx` | `/` |
72
+ | `src/pages/example/index.tsx` | `/example` |
73
+ | `src/pages/example/layout.tsx` | `/example` 及其子路由的**布局壳** |
74
+ | `src/pages/example/404.tsx` | `/example/*`(未匹配兜底) |
75
+ | `src/pages/example/settings.tsx` | 页面元信息(用于设置 `document.title`) |
76
+ | `src/pages/blog/[id]/index.tsx` | `/blog/:id` |
77
+
78
+ > 注意:`@lightfish/router` 只识别 `index.tsx` 作为页面入口,单文件页面(如 `example.tsx`、`blog/[id].tsx`)不会生成路由;`settings.tsx` 也不是独立路由。
79
+
80
+ ### layout.tsx — 布局壳
81
+
82
+ `layout.tsx` 渲染**外围框架**(导航栏、侧边栏、Provider 包裹等),内部使用 `<Outlet />` 渲染子路由页面。
83
+
84
+ ```tsx
85
+ // src/pages/example/layout.tsx
86
+ export default function ExampleLayout() {
87
+ return (
88
+ <div className="flex h-screen">
89
+ <aside>侧边栏</aside>
90
+ <main className="flex-1">
91
+ <Outlet /> {/* ← 子路由在此渲染 */}
92
+ </main>
93
+ </div>
94
+ );
95
+ }
96
+ ```
97
+
98
+ **layout.tsx 的职责边界:**
99
+
100
+ - ✅ 渲染布局框架(flex、grid、导航等)
101
+ - ✅ 包裹 `<Outlet />` 渲染子页面
102
+ - ✅ 包裹 `<Provider>` 提供**该路由模块**的状态
103
+ - ❌ 不能写页面内容(内容在 index.tsx 或子路由中)
104
+ - ❌ 不能写请求逻辑或业务状态管理(在 model.ts 中)
105
+
106
+ ### layout + model + index 标准模式
107
+
108
+ ```
109
+ pages/example/
110
+ ├── model.ts ← ① 定义 hook + createCustomModel
111
+ ├── layout.tsx ← ② <Provider><Outlet /></Provider>
112
+ └── index.tsx ← ③ 取状态 + 渲染 UI
113
+ ```
114
+
115
+ ---
116
+
117
+ ## 2. 状态管理(@lightfish/react-model)
118
+
119
+ ### 基本原理
120
+
121
+ `createCustomModel(useHook)` 把自定义 hook 桥接到 React Context:
122
+
123
+ ```ts
124
+ import { createCustomModel } from "@lightfish/react-model";
125
+
126
+ function useMyHook(props: { count: number }) {
127
+ // 任意逻辑、useState、useEffect...
128
+ return { count, increment: () => {} };
129
+ }
130
+
131
+ export const { Provider, useModel } = createCustomModel(useMyHook);
132
+ ```
133
+
134
+ **Provider 的 value 会作为参数传给 hook:**
135
+
136
+ ```tsx
137
+ <Provider value={{ count: 0 }}>
138
+ <Child />
139
+ </Provider>
140
+ // → useMyHook({ count: 0 }) 在内部运行,返回值注入 Context
141
+ ```
142
+
143
+ ### 标准三层结构
144
+
145
+ ```ts
146
+ // model.ts — 定义状态 + hook
147
+ import { createCustomModel } from "@lightfish/react-model";
148
+
149
+ // 注意:hook 名用 useXxx,对应 useModel 会命名为 useXxxModel
150
+ function useExample(initial: { id: string }) {
151
+ const [messages, setMessages] = useState<UIMessage[]>([]);
152
+ const [collapsed, setCollapsed] = useState(false);
153
+
154
+ return {
155
+ messages,
156
+ collapsed,
157
+ setCollapsed,
158
+ send: (text: string) => {
159
+ /* ... */
160
+ },
161
+ };
162
+ }
163
+
164
+ export const { Provider: ExampleProvider, useModel: useExampleModel } =
165
+ createCustomModel(useExample);
166
+ // ↑ 命名规则:XxxProvider ↑ 命名规则:useXxxModel
167
+ ```
168
+
169
+ ```tsx
170
+ // layout.tsx — 注入状态
171
+ import { ExampleProvider } from "./model";
172
+
173
+ export default function ExampleLayout() {
174
+ return (
175
+ <ExampleProvider value={{ id: "default" }}>
176
+ <Outlet />
177
+ </ExampleProvider>
178
+ );
179
+ }
180
+ ```
181
+
182
+ ```tsx
183
+ // index.tsx — 消费状态
184
+ import { useExampleModel } from "./model";
185
+
186
+ export default function ExamplePage() {
187
+ const { messages, collapsed, send } = useExampleModel();
188
+ // ...
189
+ }
190
+ ```
191
+
192
+ ### 常见错误
193
+
194
+ | ❌ 错误写法 | ✅ 正确写法 |
195
+ | --------------------------------------------------- | -------------------------------------------------------------- |
196
+ | `layout.tsx` 里直接写页面 UI | `layout.tsx` 只写布局 + `<Outlet />` |
197
+ | `layout.tsx` 里用 `useExampleModel()` | `layout.tsx` 只包裹 `<Provider>`,子页面通过 `useModel()` 消费 |
198
+ | `model.ts` 里导出 hook 但不调用 `createCustomModel` | 必须调用 `createCustomModel` 生成 Provider + useModel |
199
+ | 把 Provider 放在 `index.tsx` 里 | Provider 放在 `layout.tsx` 里,确保**整个**路由模块共享 |
200
+
201
+ ---
202
+
203
+ ## 3. 组件 & 逻辑内聚原则
204
+
205
+ **默认策略:就近内聚,延迟抽离。全部写在一个文件里,直到被复用才抽离。**
206
+
207
+ - 页面组件、请求逻辑、UI 片段**先写在一个文件里**
208
+ - 1 处使用 → 就地写
209
+ - 2 处及以上 → 抽离到对应目录
210
+ - UI 组件 → `src/components/`
211
+ - hooks → `src/hooks/`
212
+ - 工具函数 → `src/utils/`
213
+ - 类型 → `src/types/`
214
+
215
+ **例外:** 只有 `model.ts` 必须独立文件(因为 createCustomModel 要求单独导出 Provider)。
216
+
217
+ ---
218
+
219
+ ## 4. 样式规范
220
+
221
+ - 使用 Tailwind CSS 4 utility classes
222
+ - 复杂样式用 `@utility` 指令在 `src/main.css` 中定义
223
+ - 不要用 `style={{}}` 内联 style(除非动态计算)
224
+
225
+ ---
226
+
227
+ ## 5. 代码组织
228
+
229
+ ```
230
+ src/
231
+ ├── pages/ # 页面组件(文件路由)
232
+ │ ├── index.tsx # /
233
+ │ ├── layout.tsx # 根布局
234
+ │ └── example/ # 示例模块(新项目可删除)
235
+ │ ├── model.ts # useExampleModel + createCustomModel → ExampleProvider + useExampleModel
236
+ │ ├── layout.tsx # <ExampleProvider><Outlet /></ExampleProvider>
237
+ │ └── index.tsx # /example — 示例 UI
238
+ ├── components/ # 共享组件(仅复用时抽离)
239
+ │ └── ai-elements/ # AI Elements CLI 生成的组件
240
+ ├── hooks/ # 共享 hooks(仅复用时抽离)
241
+ ├── models/ # 全局状态模型(跨路由共享)
242
+ ├── utils/ # 工具函数
243
+ ├── types/ # 共享类型定义
244
+ ├── main.css # 全局样式(Tailwind + @utility)
245
+ └── main.tsx # 应用入口
246
+ ```
247
+
248
+ ---
249
+
250
+ ## 6. 开发原则
251
+
252
+ - **默认一个文件** — UI、逻辑、状态写在同一个页面文件里,不复用就不抽离
253
+ - **类型安全** — 充分利用 TypeScript 6
254
+ - **可读性优先** — 代码清晰比聪明重要
@@ -0,0 +1,150 @@
1
+ # template-vite-server
2
+
3
+ 基于 Vite 8 + React 19 + TypeScript 6 的全栈项目模板,前端使用文件系统路由与轻量级状态管理,后端使用 `@lightfish/server` 约定式路由。
4
+
5
+ > 这是模板项目,所有示例代码均可放心修改或删除。
6
+
7
+ ## 技术栈
8
+
9
+ | 能力 | 方案 |
10
+ | ----------- | ----------------------------------------------- |
11
+ | 构建工具 | Vite 8 |
12
+ | UI 框架 | React 19 |
13
+ | 类型系统 | TypeScript 6 |
14
+ | 路由方案 | `@lightfish/router` — 文件系统路由 |
15
+ | 状态管理 | `@lightfish/react-model` — 桥接 hook 到 Context |
16
+ | 样式方案 | Tailwind CSS 4 |
17
+ | 代码规范 | ESLint 10 |
18
+ | 后端 / ORM | `@lightfish/server` + Drizzle ORM + PostgreSQL |
19
+
20
+ ## 快速开始
21
+
22
+ ```bash
23
+ # 安装依赖
24
+ pnpm install
25
+
26
+ # 启动前端开发服务器(默认 http://localhost:8000)
27
+ pnpm dev
28
+
29
+ # 构建生产版本
30
+ pnpm build
31
+
32
+ # 预览构建产物
33
+ pnpm preview
34
+
35
+ # 代码检查
36
+ pnpm lint
37
+
38
+ # 同步数据库 schema(修改 schema 后执行)
39
+ pnpm db:push
40
+ ```
41
+
42
+ ## 项目结构
43
+
44
+ ```
45
+ 项目根/
46
+ ├── src/ # 前端应用
47
+ │ ├── pages/ # 页面组件(文件系统路由)
48
+ │ │ ├── index.tsx # / 首页占位页(请替换为真实业务首页)
49
+ │ │ ├── layout.tsx # 根布局
50
+ │ │ └── example/ # 示例路由模块(可直接删除)
51
+ │ │ ├── model.ts # 局部状态模型
52
+ │ │ ├── layout.tsx # 布局壳(Provider + Outlet)
53
+ │ │ └── index.tsx # 示例页面 UI
54
+ │ ├── components/ # 共享组件(复用时抽离)
55
+ │ ├── hooks/ # 共享 hooks(复用时抽离)
56
+ │ ├── models/ # 全局状态模型(跨路由共享)
57
+ │ ├── utils/ # 工具函数
58
+ │ ├── types/ # 共享类型定义
59
+ │ ├── main.css # 全局样式(Tailwind + @utility)
60
+ │ └── main.tsx # 应用入口
61
+ ├── server/ # lightfish-server 后端
62
+ │ ├── schema/index.ts # Drizzle ORM 数据库 Schema
63
+ │ └── router/ # 约定式路由
64
+ │ └── <module>/index.ts
65
+ ├── lightfish-server.config.js # 后端配置
66
+ └── vite.config.ts # 前端构建配置
67
+ ```
68
+
69
+ ## 路由
70
+
71
+ 使用 `@lightfish/router` 实现文件系统路由,页面文件自动映射为路由:
72
+
73
+ | 文件路径 | 路由 |
74
+ | --------------------------------- | ----------------------------------------- |
75
+ | `src/pages/index.tsx` | `/` |
76
+ | `src/pages/example/index.tsx` | `/example` |
77
+ | `src/pages/example/layout.tsx` | `/example` 及其子路由的**布局壳** |
78
+ | `src/pages/example/404.tsx` | `/example/*`(未匹配兜底) |
79
+ | `src/pages/example/settings.tsx` | 页面元信息(用于设置 `document.title`) |
80
+ | `src/pages/blog/[id]/index.tsx` | `/blog/:id` |
81
+
82
+ > `@lightfish/router` 只识别 `index.tsx` 作为页面入口。
83
+
84
+ ## 状态管理
85
+
86
+ 使用 `@lightfish/react-model` 将自定义 hook 桥接到 React Context:
87
+
88
+ ```tsx
89
+ // model.ts
90
+ import { createCustomModel } from "@lightfish/react-model";
91
+ import { useState } from "react";
92
+
93
+ function useExample(initial: { id: string }) {
94
+ const [count, setCount] = useState(0);
95
+ return { count, increment: () => setCount((c) => c + 1) };
96
+ }
97
+
98
+ export const { Provider: ExampleProvider, useModel: useExampleModel } =
99
+ createCustomModel(useExample);
100
+ ```
101
+
102
+ ```tsx
103
+ // layout.tsx — 注入状态
104
+ import { ExampleProvider } from "./model";
105
+
106
+ export default function ExampleLayout() {
107
+ return (
108
+ <ExampleProvider value={{ id: "default" }}>
109
+ <Outlet />
110
+ </ExampleProvider>
111
+ );
112
+ }
113
+
114
+ // index.tsx — 消费状态
115
+ import { useExampleModel } from "./model";
116
+
117
+ export default function ExamplePage() {
118
+ const { count, increment } = useExampleModel();
119
+ // ...
120
+ }
121
+ ```
122
+
123
+ ## 后端开发
124
+
125
+ 后端接口写在 `server/router/<模块>/index.ts`,通过 `@lightfish/server/api` 的 `apiRequest` 在前端调用。详细规范见 `.agents/skills/lightfish-server/SKILL.md`。
126
+
127
+ 前后端协作流程:
128
+
129
+ 1. 在 `server/schema/index.ts` 定义数据表。
130
+ 2. 执行 `pnpm db:push` 同步到数据库。
131
+ 3. 在 `server/router/<模块>/index.ts` 写接口 handler。
132
+ 4. 前端通过 `apiRequest` 调用接口。
133
+
134
+ ## 样式
135
+
136
+ - 使用 Tailwind CSS 4 utility classes
137
+ - 复杂样式用 `@utility` 指令在 `src/main.css` 中定义
138
+ - 默认暗色主题,Inter Variable 字体
139
+
140
+ ## 开发原则
141
+
142
+ - **默认一个文件** — UI、逻辑、状态写在同一个页面文件里,不复用就不抽离
143
+ - **类型安全** — 充分利用 TypeScript 6
144
+ - **可读性优先** — 代码清晰比聪明重要
145
+
146
+ ## 重要提示
147
+
148
+ - `src/pages/index.tsx` 是**首页占位页**,请替换为真实业务首页。
149
+ - `src/pages/example/` 是**示例路由模块**,仅用于演示 `layout + model + index` 的标准写法,新建项目时可直接删除或覆盖。
150
+ - 不要把示例代码当作已实现的业务功能去修改或补全。
@@ -0,0 +1,23 @@
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ dist
12
+ dist-ssr
13
+ *.local
14
+
15
+ # Editor directories and files
16
+ !.vscode/extensions.json
17
+ .idea
18
+ .DS_Store
19
+ *.suo
20
+ *.ntvs*
21
+ *.njsproj
22
+ *.sln
23
+ *.sw?
@@ -0,0 +1,25 @@
1
+ import js from "@eslint/js";
2
+ import globals from "globals";
3
+ import reactHooks from "eslint-plugin-react-hooks";
4
+ import reactRefresh from "eslint-plugin-react-refresh";
5
+ import tseslint from "typescript-eslint";
6
+ import { defineConfig, globalIgnores } from "eslint/config";
7
+
8
+ export default defineConfig([
9
+ globalIgnores(["dist"]),
10
+ {
11
+ files: ["**/*.{ts,tsx}"],
12
+ extends: [
13
+ js.configs.recommended,
14
+ tseslint.configs.recommended,
15
+ reactHooks.configs.flat.recommended,
16
+ reactRefresh.configs.vite,
17
+ ],
18
+ languageOptions: {
19
+ globals: globals.browser,
20
+ },
21
+ rules: {
22
+ "@typescript-eslint/no-explicit-any": "off",
23
+ },
24
+ },
25
+ ]);
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>template-vite-server — 现代 Web 应用模板</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,6 @@
1
+ import { defineConfig } from '@lightfish/server';
2
+
3
+ export default defineConfig({
4
+ apiDir: './server/router',
5
+ appName: '__PROJECT_NAME__', // 应用名称,用于数据库schema前缀
6
+ });
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "__PROJECT_NAME__",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc -b && vite build",
9
+ "lint": "eslint .",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "@lightfish/react-model": "^0.0.1",
14
+ "@lightfish/router": "^0.0.1",
15
+ "@tailwindcss/vite": "^4.3.0",
16
+ "ahooks": "^3.9.7",
17
+ "react": "^19.2.6",
18
+ "react-dom": "^19.2.6",
19
+ "react-router-dom": "6.21.1",
20
+ "tailwindcss": "^4.3.0"
21
+ },
22
+ "devDependencies": {
23
+ "@eslint/js": "^10.0.1",
24
+ "@lightfish/server": "^0.0.24",
25
+ "@types/node": "^24.12.3",
26
+ "@types/react": "^19.2.14",
27
+ "@types/react-dom": "^19.2.3",
28
+ "@vitejs/plugin-react": "^6.0.1",
29
+ "code-inspector-plugin": "^1.5.1",
30
+ "drizzle-kit": "^0.31.10",
31
+ "drizzle-orm": "^0.45.2",
32
+ "eslint": "^10.3.0",
33
+ "eslint-plugin-react-hooks": "^7.1.1",
34
+ "eslint-plugin-react-refresh": "^0.5.2",
35
+ "globals": "^17.6.0",
36
+ "pg": "^8.22.0",
37
+ "typescript": "~6.0.2",
38
+ "typescript-eslint": "^8.59.2",
39
+ "vite": "^8.0.12"
40
+ }
41
+ }