@lovrabet/cli 1.1.0

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 (76) hide show
  1. package/README.md +28 -0
  2. package/lib/add-page/input-page-router.js +1 -0
  3. package/lib/add-page/main.js +1 -0
  4. package/lib/add-page/select-page-template.js +1 -0
  5. package/lib/api/api-pull-ui.js +1 -0
  6. package/lib/api/format-dataset.js +1 -0
  7. package/lib/api/generate-api-file.js +1 -0
  8. package/lib/api/main.js +1 -0
  9. package/lib/api/pull-silent.js +1 -0
  10. package/lib/api/pull.js +1 -0
  11. package/lib/api/types.js +1 -0
  12. package/lib/auth/auth-server-ui.js +1 -0
  13. package/lib/auth/auth-server.js +1 -0
  14. package/lib/auth/constant.js +1 -0
  15. package/lib/auth/get-cookie.js +1 -0
  16. package/lib/auth/is-session-valid.js +1 -0
  17. package/lib/auth/logout.js +1 -0
  18. package/lib/cli.js +2 -0
  19. package/lib/cmd/build-watch.js +1 -0
  20. package/lib/cmd/build.js +1 -0
  21. package/lib/cmd/logs.js +1 -0
  22. package/lib/cmd/preview.js +1 -0
  23. package/lib/cmd/start.js +1 -0
  24. package/lib/config/config-help.js +1 -0
  25. package/lib/config/main.js +1 -0
  26. package/lib/constant/domain.js +1 -0
  27. package/lib/constant/env.js +1 -0
  28. package/lib/create-app/enhanced-guided-create.js +1 -0
  29. package/lib/create-app/format-elapsed.js +1 -0
  30. package/lib/create-app/main.js +1 -0
  31. package/lib/create-app/task-finished.js +1 -0
  32. package/lib/create-app/task-loading.js +1 -0
  33. package/lib/create-app/task-running.js +1 -0
  34. package/lib/create-app/task-time.js +1 -0
  35. package/lib/create-app/use-copy-project-template.js +1 -0
  36. package/lib/create-app/use-format-code.js +1 -0
  37. package/lib/create-app/use-install-dependencies.js +1 -0
  38. package/lib/help.js +1 -0
  39. package/lib/utils/config.js +1 -0
  40. package/lib/utils/copy-directory.js +1 -0
  41. package/lib/utils/logger.js +1 -0
  42. package/lib/utils/router-updater.js +1 -0
  43. package/lib/utils/template-replacer.js +1 -0
  44. package/package.json +41 -0
  45. package/templates/README.md +115 -0
  46. package/templates/generate-api/api.ts.tpl +42 -0
  47. package/templates/generate-api/client.ts.tpl +64 -0
  48. package/templates/pages/blank/index.tsx.tpl +13 -0
  49. package/templates/pages/sdk-fetch/index.tsx.tpl +82 -0
  50. package/templates/projects/sub-app-react-demo/.prettierrc +1 -0
  51. package/templates/projects/sub-app-react-demo/.vscode/extensions.json +3 -0
  52. package/templates/projects/sub-app-react-demo/.vscode/settings.json +57 -0
  53. package/templates/projects/sub-app-react-demo/CHANGELOG.md +37 -0
  54. package/templates/projects/sub-app-react-demo/README.md +209 -0
  55. package/templates/projects/sub-app-react-demo/bun.lock +600 -0
  56. package/templates/projects/sub-app-react-demo/docs/API_RULE_CHANGE.md +212 -0
  57. package/templates/projects/sub-app-react-demo/docs/quick-start.md +526 -0
  58. package/templates/projects/sub-app-react-demo/index.html +39 -0
  59. package/templates/projects/sub-app-react-demo/package.json +34 -0
  60. package/templates/projects/sub-app-react-demo/public/vite.svg +1 -0
  61. package/templates/projects/sub-app-react-demo/src/api/api.ts +66 -0
  62. package/templates/projects/sub-app-react-demo/src/api/client.ts +63 -0
  63. package/templates/projects/sub-app-react-demo/src/components/ApiUrlDisplay.tsx +111 -0
  64. package/templates/projects/sub-app-react-demo/src/layouts/MainLayout.tsx +116 -0
  65. package/templates/projects/sub-app-react-demo/src/main.tsx +48 -0
  66. package/templates/projects/sub-app-react-demo/src/pages/chart-fetch/index.tsx +137 -0
  67. package/templates/projects/sub-app-react-demo/src/pages/dashboard/index.tsx +572 -0
  68. package/templates/projects/sub-app-react-demo/src/pages/index.tsx +129 -0
  69. package/templates/projects/sub-app-react-demo/src/pages/sdk-demo/index.tsx +182 -0
  70. package/templates/projects/sub-app-react-demo/src/pages/table-display.tsx +130 -0
  71. package/templates/projects/sub-app-react-demo/src/router/index.tsx +30 -0
  72. package/templates/projects/sub-app-react-demo/src/style.css +47 -0
  73. package/templates/projects/sub-app-react-demo/src/utils/api.ts +12 -0
  74. package/templates/projects/sub-app-react-demo/src/vite-env.d.ts +2 -0
  75. package/templates/projects/sub-app-react-demo/tsconfig.json +26 -0
  76. package/templates/projects/sub-app-react-demo/vite.config.ts +88 -0
@@ -0,0 +1,526 @@
1
+ # Lovrabet子应用接入指南 - React 18 + Vite 实操版
2
+
3
+ > 🎯 **目标**:通过实际操作完成React项目接入Lovrabet平台
4
+ > 📦 **官方代码**:https://github.com/lovrabet-ai/sub-app-react-demo
5
+ > ⏱️ **预计时间**:20min可以走通从本地开发到线上部署的完成流程,看到自定义页面在平台中的渲染效果
6
+
7
+ ---
8
+
9
+ ## 🚀 场景一:Hello World 实操(10min)
10
+
11
+ **目标**:下载官方代码,本地运行验证,构建部署,集成到主应用
12
+
13
+ ### Step 1: 下载GitHub仓库
14
+
15
+ ```bash
16
+ # 推荐使用SSH(需要配置GitHub SSH密钥)
17
+ git clone git@github.com:lovrabet-ai/sub-app-react-demo.git
18
+
19
+ # 或使用HTTPS(适合快速体验)
20
+ # git clone https://github.com/lovrabet-ai/sub-app-react-demo.git
21
+
22
+ cd sub-app-react-demo
23
+ git checkout main
24
+ ```
25
+
26
+ ### Step 2: 本地安装和运行
27
+
28
+ ```bash
29
+ # 安装依赖
30
+ npm i
31
+
32
+ # 本地运行查看效果
33
+ npm start
34
+ ```
35
+
36
+ **本地验证**:
37
+
38
+ - 浏览器打开 https://dev.lovrabet.com:5173/hello-world
39
+ - 确认Hello World页面正常显示
40
+ - 检查控制台无报错信息
41
+
42
+ ![本地终端运行](https://i.yuntooai.com/u/AZjq66VncACe2C_z8m9_Qg.png)
43
+
44
+ ### Step 3: 构建产物
45
+
46
+ ```bash
47
+ # 构建微前端产物
48
+ npm run build
49
+ ```
50
+
51
+ **构建验证**:
52
+
53
+ - 检查 `dist/` 目录生成
54
+ - 确认存在 `dist/assets/main.js` 文件(ES modules格式)
55
+ - 确认存在 `dist/assets/main.css` 样式文件
56
+
57
+ 本地构建成功
58
+ ![本地构建产物](https://i.yuntooai.com/u/AZjq8hJFcACYdK1TnupxaA.png)
59
+
60
+ 本地构建后生成的产物
61
+ ![本地构建后生成的产物](https://i.yuntooai.com/u/AZjrffaucACvb0HJGELOAQ.png)
62
+
63
+ ### Step 4: 上传构建产物到CDN
64
+
65
+ #### 选项A:使用业务方已有CDN
66
+
67
+ ```bash
68
+ # 将 dist/ 目录内容上传到您的CDN
69
+ # 例如:https://your-cdn.com/sub-app-react-demo/
70
+ ```
71
+
72
+ #### 选项B:使用Lovrabet临时CDN服务
73
+
74
+ ```bash
75
+ # 联系Lovrabet的技术支持 @风月 获取临时CDN上传地址,仅用于功能体验,3天后CDN链接会失效
76
+ ```
77
+
78
+ **CDN验证**:
79
+
80
+ - 确认JS文件可访问:
81
+ - 🔧 **您的CDN格式**:`https://your-cdn.com/sub-app-react-demo/dist/assets/main.js`
82
+ - 📌 **演示环境示例**:`https://g.yuntooai.com/dist/sub-app-react-demo/202508271755/main.js`
83
+ - 确认CSS文件可访问:
84
+ - 🔧 **您的CDN格式**:`https://your-cdn.com/sub-app-react-demo/dist/assets/main.css`
85
+ - 📌 **演示环境示例**:`https://g.yuntooai.com/dist/sub-app-react-demo/202508271755/main.css`
86
+
87
+ > 💡 **说明**:`your-cdn.com` 需替换为您实际的CDN域名
88
+
89
+ ### Step 5: 到Lovrabet主应用中集成Hello World页面
90
+
91
+ 在Lovrabet平台配置页面:
92
+
93
+ ```text
94
+ 页面配置:
95
+ ├── 页面名称: Hello World Demo # 🔧 可自定义:菜单中显示的名称
96
+ ├── 路由路径: /hello-world # ⚠️ 必须与 src/router/index.tsx 中的 path 保持一致
97
+ ├── 微应用唯一标识: react-hello-world # 🔧 可自定义:用于区分不同微应用
98
+ ├── 资源加载方式: import # ⚡ 固定值:Vite项目必须选择import
99
+ └── 资源加载列表: # 🔧 替换为您的CDN地址
100
+ ├── https://your-cdn.com/sub-app-react-demo/dist/assets/main.js
101
+ └── https://your-cdn.com/sub-app-react-demo/dist/assets/main.css
102
+ ```
103
+
104
+ > ⚠️ **重要提示**:路由路径必须与代码中定义的路径完全对应,否则页面无法正确加载
105
+
106
+ **集成验证**:
107
+
108
+ - 主应用菜单出现"Hello World Demo"
109
+ - 点击菜单能正常显示页面
110
+ - 页面功能与本地运行效果一致
111
+
112
+ #### 5.1 新增页面
113
+
114
+ 访问菜单配置链接:https://app.lovrabet.com/app/app-f4c03acb/pages/
115
+ ![](https://i.yuntooai.com/u/AZjrKSOvcACyPcNb4irCUA.png)
116
+
117
+ #### 5.2 配置路由
118
+
119
+ ![hello-world页面集成到主应用中](https://i.yuntooai.com/u/AZjq-EX5cACZF-TKk4EvTw.png)
120
+
121
+ ### step 6:验证页面运行效果
122
+
123
+ **✅ 场景一完成标志**:主应用中能正常访问Hello World页面
124
+
125
+ https://app-f4c03acb.app.lovrabet.com/hello-world
126
+ helloworld运行时页面: https://app-f4c03acb.app.lovrabet.com/hello-world
127
+ ![helloworld运行时页面](https://i.yuntooai.com/u/AZjq_pSDcACOdA8Me_CFFQ.png)
128
+
129
+ ---
130
+
131
+ ## 📊 场景二:真实API数据请求与图表展示(10min)
132
+
133
+ **目标**:体验调用真实业务接口、处理跨域请求、展示动态图表的完整功能
134
+
135
+ ### Step 1: 更新图表页面代码
136
+
137
+ ```bash
138
+ # 项目已包含 ChartFetch.tsx 页面
139
+ # 使用真实 API:https://runtime.lovrabet.com/dbapi/runtime/yuntoo/app-f4c03acb/6c6c94a6ef064fe898cfa895fe5a38f5/getList
140
+
141
+ cat src/pages/ChartFetch.tsx
142
+ ```
143
+
144
+ [https://github.com/lovrabet-ai/sub-app-react-demo/blob/26f5dd3981ed5ad955dc3949501e308678438fb7/src/pages/ChartFetch.tsx#L33](https://github.com/lovrabet-ai/sub-app-react-demo/blob/26f5dd3981ed5ad955dc3949501e308678438fb7/src/pages/ChartFetch.tsx#L33)
145
+
146
+ 注意:
147
+
148
+ - API地址的结构说明:https://runtime.lovrabet.com/${type}/runtime/${tenentCode}/${appCode}/${datasetCode}/getList
149
+ - 请将接口地址换成业务有权限的接口地址,就能运行看到自己负责业务的接口数据了,有权限的api地址请查看 https://app.lovrabet.com/app/${appCode}/admin/dataset,直接复制接口链接就能通过浏览器console控制验证接口请求的调用是否成功;
150
+
151
+ ### Step 2: 本地运行验证
152
+
153
+ ```bash
154
+ # 项目已安装echarts依赖
155
+ npm start
156
+ ```
157
+
158
+ **本地验证**:
159
+
160
+ - 浏览器访问 https://dev.lovrabet.com:5173/chart-fetch
161
+ - 确认饼图显示客户状态分布(活跃、正常、流失)
162
+
163
+ ### Step 3: 构建更新的产物
164
+
165
+ ```bash
166
+ # 重新构建包含图表功能的版本
167
+ npm run build
168
+ ```
169
+
170
+ **构建验证**:
171
+
172
+ - `dist/assets/main.js` 包含echarts
173
+ - `dist/assets/main.css` 样式文件更新
174
+ - 注意:React、Ant Design已外部化,体积较小
175
+
176
+ ### Step 4: 重新上传到CDN
177
+
178
+ ```bash
179
+ # 将更新后的 dist/ 内容重新上传
180
+ # 覆盖之前的文件或使用新的路径
181
+ ```
182
+
183
+ ### Step 5: 到Lovrabet主应用中集成ChartFetch页面
184
+
185
+ **页面2:数据图表入口**
186
+
187
+ ```text
188
+ 页面配置:
189
+ ├── 页面名称: 数据图表 # 🔧 可自定义:菜单中显示的名称
190
+ ├── 路由路径: /chart-fetch # ⚠️ 必须与 src/router/index.tsx 中的 path 保持一致
191
+ ├── 资源加载方式: import # ⚡ 固定值:Vite项目必须选择import
192
+ └── 资源加载列表: # 🔧 替换为您的CDN地址(与Hello World共享同一构建产物)
193
+ ├── https://your-cdn.com/sub-app-react-demo/dist/assets/main.js
194
+ └── https://your-cdn.com/sub-app-react-demo/dist/assets/main.css
195
+ ```
196
+
197
+ #### 5.1 配置
198
+
199
+ 访问链接:https://app.lovrabet.com/app/app-f4c03acb/preview
200
+ ![chart-fetch页面集成到主应用中](https://i.yuntooai.com/u/AZjq9nKvcACEawJpHIM4Gg.png)
201
+
202
+ **集成验证**:
203
+
204
+ - 主应用此时又多了一个菜单项,总计出现了2个菜单
205
+ - "Hello World"菜单 → 显示Hello World页面
206
+ - "数据图表"菜单 → 显示图表页面,数据正常加载
207
+
208
+ **✅ 场景二完成标志**:两个菜单都能正常工作,图表数据正常显示
209
+
210
+ ![](https://i.yuntooai.com/u/AZjrAvi8cACGVAKkuXXkkQ.png)
211
+
212
+ ---
213
+
214
+ ## 🔧 场景三:改造已有项目(20min)
215
+
216
+ **目标**:将您现有的React项目改造为微前端,直接请求真实的业务接口,实现无缝集成到Lovrabet平台
217
+
218
+ ### 改造已有项目流程
219
+
220
+ 1. **分析现有项目** → 确定改造范围和接口依赖
221
+ 2. **修改入口文件** → 添加微前端生命周期函数
222
+ 3. **配置构建工具** → 修改vite.config.js支持ES modules
223
+ 4. **封装API调用** → 统一请求方式,直接调用真实接口
224
+ 5. **本地开发测试** → 验证功能完整性
225
+ 6. **构建部署** → 生成ES modules格式产物
226
+ 7. **平台配置** → 配置多个页面入口
227
+ 8. **生产验证** → 确保集成效果符合预期
228
+
229
+ ### 官方配置参数详解
230
+
231
+ 根据Lovrabet官方文档,配置页面时需要理解以下关键参数:
232
+
233
+ #### 1. 路由路径 (path)
234
+
235
+ ```text
236
+ 说明:应用实际访问时链接URL中的path部分
237
+ 格式:https://${appcode}.app.lovrabet.com/${pagePath}
238
+
239
+ ⚠️ 重要:路由路径必须与 src/router/index.tsx 中定义的路径完全一致
240
+
241
+ 示例对应关系:
242
+ ```
243
+
244
+ ```typescript
245
+ // src/router/index.tsx 中的配置
246
+ {
247
+ path: "hello-world", // <- 这里定义的路径
248
+ element: <HelloWorld />,
249
+ }
250
+
251
+ // 平台配置中的路由路径
252
+ 路由路径: /hello-world // <- 必须保持一致(加上/前缀)
253
+ ```
254
+
255
+ ```text
256
+ 实际访问链接示例:
257
+ - 配置"/hello-world" → https://app-f4c03acb.app.lovrabet.com/hello-world
258
+ - 配置"/chart-fetch" → https://app-f4c03acb.app.lovrabet.com/chart-fetch
259
+
260
+ 其中:
261
+ - 🔧 appcode: 您的应用编码(创建应用时生成,如:app-f4c03acb)
262
+ - ⚠️ pagePath: 必须与代码中的路由配置一致
263
+
264
+ 要求:路径需要在整个应用中唯一
265
+ ```
266
+
267
+ #### 2. 微应用唯一标识
268
+
269
+ ```text
270
+ 说明:标记页面所属的源码微应用,多个页面可能属于同一个源码微应用
271
+ 默认:如不填写,则实际运行时会将"路由路径(path)"作为应用标识
272
+
273
+ 🔧 建议:使用有意义的名称,如:react-hello-world、customer-management 等
274
+ ```
275
+
276
+ #### 3. Basename
277
+
278
+ ```text
279
+ 说明:指定微应用接收的basename,微应用包含前端路由的场景下需要使用
280
+ 默认:如不填写,则默认"路由路径(path)"即作为basename
281
+
282
+ 💡 提示:本示例项目已自动处理 basename,通常无需手动配置
283
+ ```
284
+
285
+ #### 4. 资源加载方式
286
+
287
+ ```text
288
+ 可选值:
289
+ - script(默认):通过HTML <script /> 标签加载,适用于Angular CLI和Vue CLI
290
+ - fetch:通过window.fetch 加载并缓存脚本资源,沙箱模式下使用
291
+ - import:加载ES modules类型微应用
292
+
293
+ ⚡ 重要:Vite构建的项目必须选择 import
294
+ ```
295
+
296
+ ### Step 1: 改造现有项目结构
297
+
298
+ #### 1.1 修改入口文件
299
+
300
+ ```jsx
301
+ // src/main.jsx - 改造为微前端入口
302
+ import React from "react";
303
+ import { createRoot } from "react-dom/client";
304
+ import { isInIcestark } from "@ice/stark-app";
305
+ import { ConfigProvider } from "antd";
306
+ import zhCN from "antd/locale/zh_CN";
307
+ import App from "./router"; // 注意:App实际上是路由组件
308
+ import "./style.css";
309
+
310
+ // 判断是否在微前端环境中运行
311
+ if (!isInIcestark()) {
312
+ // 获取 index.html 中定义的根容器元素(id="root")
313
+ const container = document.getElementById("root");
314
+ if (container) {
315
+ const root = createRoot(container);
316
+ root.render(
317
+ <ConfigProvider locale={zhCN}>
318
+ <App />
319
+ </ConfigProvider>,
320
+ );
321
+ }
322
+ }
323
+
324
+ // 关键:暴露 mount 供主应用加载时调用
325
+ export function mount({ container, customProps }) {
326
+ const root = createRoot(container);
327
+ root.render(
328
+ <React.StrictMode>
329
+ <ConfigProvider locale={zhCN}>
330
+ <App {...customProps} />
331
+ </ConfigProvider>
332
+ </React.StrictMode>,
333
+ );
334
+ return root;
335
+ }
336
+
337
+ // 关键:暴露 unmount 供主应用卸载时调用
338
+ export function unmount({ container }) {
339
+ // React 18 中不再需要手动卸载,但为了兼容性保留
340
+ const root = container._reactRoot;
341
+ if (root) {
342
+ root.unmount();
343
+ }
344
+ }
345
+ ```
346
+
347
+ #### 1.2 配置Vite构建
348
+
349
+ ```javascript
350
+ // vite.config.ts - 微前端构建配置
351
+ import { defineConfig, loadEnv } from "vite";
352
+ import react from "@vitejs/plugin-react";
353
+ import htmlPlugin from "vite-plugin-index-html";
354
+ import pluginExternal from "vite-plugin-external";
355
+
356
+ export default defineConfig(async ({ mode }) => {
357
+ const env = loadEnv(mode, process.cwd());
358
+ const PORT = Number(env.VITE_APP_PORT) || 5173;
359
+
360
+ return {
361
+ plugins: [
362
+ react(),
363
+ // 关键配置:提供 vite lib 打包 + html plugin 能力
364
+ htmlPlugin({
365
+ input: "src/main.tsx",
366
+ preserveEntrySignatures: "exports-only",
367
+ }),
368
+ // 外部化依赖,减小打包体积
369
+ pluginExternal({
370
+ externals: {
371
+ react: "React",
372
+ "react-dom": "ReactDOM",
373
+ antd: "antd",
374
+ dayjs: "dayjs",
375
+ },
376
+ }),
377
+ ],
378
+
379
+ // 开发服务器配置
380
+ server: {
381
+ port: PORT,
382
+ host: "dev.lovrabet.com",
383
+ headers: {
384
+ "Access-Control-Allow-Origin": "*",
385
+ },
386
+ },
387
+
388
+ // 生产构建配置 - ES modules格式
389
+ build: {
390
+ outDir: "dist",
391
+ target: "esnext",
392
+ rollupOptions: {
393
+ output: {
394
+ format: "es",
395
+ entryFileNames: "assets/[name].js",
396
+ assetFileNames: "assets/[name].css",
397
+ },
398
+ },
399
+ },
400
+ };
401
+ });
402
+ ```
403
+
404
+ ### Step 2: API请求封装(核心配置)
405
+
406
+ **🔑 关键点:直接请求真实接口的跨域问题必须配置 `credentials: 'include'` 来携带Cookie**
407
+
408
+ ```javascript
409
+ // 简单封装 apiRequest - 这是最简单有效的实现
410
+ const apiRequest = async (path, options = {}) => {
411
+ const response = await fetch(`https://runtime.lovrabet.com${path}`, {
412
+ credentials: "include", // 关键配置:跨域请求携带Cookie
413
+ headers: {
414
+ "Content-Type": "application/json",
415
+ ...options.headers,
416
+ },
417
+ ...options,
418
+ });
419
+ return response.json();
420
+ };
421
+
422
+ // 使用示例
423
+ const fetchUserData = async () => {
424
+ try {
425
+ const data = await apiRequest(
426
+ "/dbapi/runtime/yuntoo/app-f4c03acb/6c6c94a6ef064fe898cfa895fe5a38f5/getList",
427
+ {
428
+ method: "POST",
429
+ body: JSON.stringify({ pageSize: 10, currentPage: 1 }),
430
+ },
431
+ );
432
+
433
+ if (data.success) {
434
+ console.log("数据获取成功:", data.data);
435
+ }
436
+ } catch (error) {
437
+ console.error("请求失败:", error);
438
+ }
439
+ };
440
+ ```
441
+
442
+ ### Step 3: 路由配置
443
+
444
+ ```jsx
445
+ // src/router/index.jsx - 路由配置文件
446
+ import React from "react";
447
+ import { createBrowserRouter, RouterProvider } from "react-router";
448
+ import { getBasename } from "@ice/stark-app";
449
+ import MainLayout from "../layouts/MainLayout";
450
+ import HelloWorld from "../pages/HelloWorld";
451
+ import ChartFetch from "../pages/ChartFetch";
452
+
453
+ const router = createBrowserRouter(
454
+ [
455
+ {
456
+ path: "/",
457
+ element: <MainLayout />,
458
+ children: [
459
+ {
460
+ index: true,
461
+ element: <HelloWorld />,
462
+ },
463
+ {
464
+ path: "hello-world",
465
+ element: <HelloWorld />,
466
+ },
467
+ {
468
+ path: "chart-fetch",
469
+ element: <ChartFetch />,
470
+ },
471
+ ],
472
+ },
473
+ ],
474
+ {
475
+ // 可选:通过getBasename()获取到微应用运行时的basename并传入
476
+ basename: getBasename() || "/",
477
+ },
478
+ );
479
+
480
+ console.log("MicroAppRouter:", {
481
+ routes: router.routes,
482
+ basename: router.basename,
483
+ });
484
+
485
+ const AppRouter: React.FC = () => {
486
+ return <RouterProvider router={router} />;
487
+ };
488
+
489
+ export default AppRouter;
490
+ ```
491
+
492
+ ### Step 4: 本地开发、测试、集成到主应用
493
+
494
+ 同场景一和场景二的操作
495
+
496
+ ## 🛠️ 常见问题和解决方案
497
+
498
+ ### 改造相关问题
499
+
500
+ **问题1:现有项目路由冲突**
501
+ **解决**:
502
+
503
+ - 使用正确的basename,确保在主应用中也是唯一的
504
+ - 检查路由配置与平台配置的路径匹配
505
+ - 使用相对路径而非绝对路径
506
+
507
+ **问题2:接口请求失败**
508
+ **解决**:
509
+
510
+ - 检查API地址配置是否正确
511
+ - 验证接口的CORS配置
512
+
513
+ ### 构建部署问题
514
+
515
+ **问题4:构建后资源加载失败**
516
+ **解决**:
517
+
518
+ - 确保选择import加载方式
519
+ - 检查CDN地址是否正确
520
+ - 验证资源文件是否完整上传
521
+
522
+ **问题5:我的业务工程能不能独立运行,仅调用Lovrabet的api接口**
523
+ **解决**:
524
+
525
+ - step1:子应用不挂载到主应用,也是支持独立运行的;
526
+ - step2:联系Lovrabet技术 @fengyue 独立配置业务自有域名来解决cors跨域;
@@ -0,0 +1,39 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>React SPA 应用</title>
8
+ <!-- React 18 CDN -->
9
+ <script
10
+ crossorigin
11
+ src="https://g.alicdn.com/code/lib/react/18.3.1/umd/react.production.min.js"
12
+ ></script>
13
+ <script
14
+ crossorigin
15
+ src="https://g.alicdn.com/code/lib/react-dom/18.3.1/umd/react-dom.production.min.js"
16
+ ></script>
17
+ <!-- React Router CDN -->
18
+ <!-- <script
19
+ crossorigin
20
+ src="https://g.alicdn.com/code/lib/react-router/6.30.1/react-router.production.min.js"
21
+ ></script> -->
22
+ <!-- Ant Design CDN -->
23
+ <script
24
+ crossorigin
25
+ src="https://g.alicdn.com/code/lib/dayjs/1.11.13/dayjs.min.js"
26
+ ></script>
27
+ <script
28
+ crossorigin
29
+ src="https://g.alicdn.com/code/lib/antd/5.26.5/antd.min.js"
30
+ ></script>
31
+ <link
32
+ rel="stylesheet"
33
+ href="https://g.alicdn.com/code/lib/antd/5.26.5/reset.min.css"
34
+ />
35
+ </head>
36
+ <body>
37
+ <div id="root"></div>
38
+ </body>
39
+ </html>
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "sub-app-react-demo",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "start": "vite",
8
+ "build": "vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "@ant-design/icons": "^6.0.0",
13
+ "@ice/stark-app": "^1.5.0",
14
+ "@lovrabet/sdk": "^1.1.3",
15
+ "antd": "^5.26.7",
16
+ "echarts": "^5.6.0",
17
+ "echarts-for-react": "^3.0.2",
18
+ "prettier": "latest",
19
+ "react": "^18.3.1",
20
+ "react-dom": "^18.3.1",
21
+ "react-router-dom": "^6.30.1"
22
+ },
23
+ "devDependencies": {
24
+ "@types/react": "^18.3.23",
25
+ "@types/react-dom": "^18.3.7",
26
+ "@vitejs/plugin-react": "^4.7.0",
27
+ "rollup-plugin-visualizer": "^6.0.3",
28
+ "typescript": "~5.8.3",
29
+ "vite": "^7.0.6",
30
+ "vite-plugin-external": "^6.2.2",
31
+ "vite-plugin-index-html": "^2.0.2",
32
+ "vite-plugin-pages": "^0.33.1"
33
+ }
34
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Generated by Lovrabet CLI
3
+ *
4
+ * 这个文件包含了项目的模型配置,并自动注册到 SDK 中
5
+ * CLI 工具会自动维护这个文件,通常不需要手动修改
6
+ */
7
+
8
+ import { registerModels, CONFIG_NAMES, type ModelsConfig } from "@lovrabet/sdk";
9
+
10
+ export const LOVRABET_APP_CODE = "app-c4c89304";
11
+
12
+ /**
13
+ * 项目的模型配置
14
+ * 包含所有数据表的映射关系
15
+ */
16
+ export const LOVRABET_MODELS_CONFIG: ModelsConfig = {
17
+ appCode: LOVRABET_APP_CODE,
18
+ models: {
19
+ // ProjectMembers: {
20
+ // tableName: "project_members",
21
+ // datasetId: "71494bcba13f4ec7858abe90794183ad",
22
+ // },
23
+ Requirements: {
24
+ tableName: "requirements",
25
+ datasetId: "d26ed512e878461ca97d287a47606fd3",
26
+ },
27
+ Projects: {
28
+ tableName: "projects",
29
+ datasetId: "c6e55d6720b84ffcb21698b0a04ccd23",
30
+ },
31
+ Iterations: {
32
+ tableName: "iterations",
33
+ datasetId: "a60f11c17c5344e7a26d5144212cf366",
34
+ },
35
+ RequirementTypes: {
36
+ tableName: "requirement_types",
37
+ datasetId: "f17f1ee941c1468e87e6a0ca655ce00e",
38
+ },
39
+ CustomerInterviews: {
40
+ tableName: "dataset_3c23",
41
+ datasetId: "3ff202af07164d0a9c5df7ddd8f83c23",
42
+ },
43
+ }
44
+ } as const;
45
+
46
+ /**
47
+ * 自动注册默认配置
48
+ * 这样 createClient() 就可以无参数调用
49
+ */
50
+ registerModels(LOVRABET_MODELS_CONFIG, CONFIG_NAMES.DEFAULT);
51
+
52
+ /**
53
+ * 如果需要支持多项目或多环境,可以注册额外的配置:
54
+ *
55
+ * // 开发环境配置
56
+ * registerModels({
57
+ * appCode: 'app-dev-123',
58
+ * models: { ... }
59
+ * }, 'dev');
60
+ *
61
+ * // 其他项目配置
62
+ * registerModels({
63
+ * appCode: 'other-project',
64
+ * models: { ... }
65
+ * }, 'project-b');
66
+ */