@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.
- package/README.md +28 -0
- package/lib/add-page/input-page-router.js +1 -0
- package/lib/add-page/main.js +1 -0
- package/lib/add-page/select-page-template.js +1 -0
- package/lib/api/api-pull-ui.js +1 -0
- package/lib/api/format-dataset.js +1 -0
- package/lib/api/generate-api-file.js +1 -0
- package/lib/api/main.js +1 -0
- package/lib/api/pull-silent.js +1 -0
- package/lib/api/pull.js +1 -0
- package/lib/api/types.js +1 -0
- package/lib/auth/auth-server-ui.js +1 -0
- package/lib/auth/auth-server.js +1 -0
- package/lib/auth/constant.js +1 -0
- package/lib/auth/get-cookie.js +1 -0
- package/lib/auth/is-session-valid.js +1 -0
- package/lib/auth/logout.js +1 -0
- package/lib/cli.js +2 -0
- package/lib/cmd/build-watch.js +1 -0
- package/lib/cmd/build.js +1 -0
- package/lib/cmd/logs.js +1 -0
- package/lib/cmd/preview.js +1 -0
- package/lib/cmd/start.js +1 -0
- package/lib/config/config-help.js +1 -0
- package/lib/config/main.js +1 -0
- package/lib/constant/domain.js +1 -0
- package/lib/constant/env.js +1 -0
- package/lib/create-app/enhanced-guided-create.js +1 -0
- package/lib/create-app/format-elapsed.js +1 -0
- package/lib/create-app/main.js +1 -0
- package/lib/create-app/task-finished.js +1 -0
- package/lib/create-app/task-loading.js +1 -0
- package/lib/create-app/task-running.js +1 -0
- package/lib/create-app/task-time.js +1 -0
- package/lib/create-app/use-copy-project-template.js +1 -0
- package/lib/create-app/use-format-code.js +1 -0
- package/lib/create-app/use-install-dependencies.js +1 -0
- package/lib/help.js +1 -0
- package/lib/utils/config.js +1 -0
- package/lib/utils/copy-directory.js +1 -0
- package/lib/utils/logger.js +1 -0
- package/lib/utils/router-updater.js +1 -0
- package/lib/utils/template-replacer.js +1 -0
- package/package.json +41 -0
- package/templates/README.md +115 -0
- package/templates/generate-api/api.ts.tpl +42 -0
- package/templates/generate-api/client.ts.tpl +64 -0
- package/templates/pages/blank/index.tsx.tpl +13 -0
- package/templates/pages/sdk-fetch/index.tsx.tpl +82 -0
- package/templates/projects/sub-app-react-demo/.prettierrc +1 -0
- package/templates/projects/sub-app-react-demo/.vscode/extensions.json +3 -0
- package/templates/projects/sub-app-react-demo/.vscode/settings.json +57 -0
- package/templates/projects/sub-app-react-demo/CHANGELOG.md +37 -0
- package/templates/projects/sub-app-react-demo/README.md +209 -0
- package/templates/projects/sub-app-react-demo/bun.lock +600 -0
- package/templates/projects/sub-app-react-demo/docs/API_RULE_CHANGE.md +212 -0
- package/templates/projects/sub-app-react-demo/docs/quick-start.md +526 -0
- package/templates/projects/sub-app-react-demo/index.html +39 -0
- package/templates/projects/sub-app-react-demo/package.json +34 -0
- package/templates/projects/sub-app-react-demo/public/vite.svg +1 -0
- package/templates/projects/sub-app-react-demo/src/api/api.ts +66 -0
- package/templates/projects/sub-app-react-demo/src/api/client.ts +63 -0
- package/templates/projects/sub-app-react-demo/src/components/ApiUrlDisplay.tsx +111 -0
- package/templates/projects/sub-app-react-demo/src/layouts/MainLayout.tsx +116 -0
- package/templates/projects/sub-app-react-demo/src/main.tsx +48 -0
- package/templates/projects/sub-app-react-demo/src/pages/chart-fetch/index.tsx +137 -0
- package/templates/projects/sub-app-react-demo/src/pages/dashboard/index.tsx +572 -0
- package/templates/projects/sub-app-react-demo/src/pages/index.tsx +129 -0
- package/templates/projects/sub-app-react-demo/src/pages/sdk-demo/index.tsx +182 -0
- package/templates/projects/sub-app-react-demo/src/pages/table-display.tsx +130 -0
- package/templates/projects/sub-app-react-demo/src/router/index.tsx +30 -0
- package/templates/projects/sub-app-react-demo/src/style.css +47 -0
- package/templates/projects/sub-app-react-demo/src/utils/api.ts +12 -0
- package/templates/projects/sub-app-react-demo/src/vite-env.d.ts +2 -0
- package/templates/projects/sub-app-react-demo/tsconfig.json +26 -0
- package/templates/projects/sub-app-react-demo/vite.config.ts +88 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { Button, Table, Card, Typography, Space, message } from "antd";
|
|
3
|
+
import { ApiOutlined } from "@ant-design/icons";
|
|
4
|
+
import { lovrabetClient } from "../../api/client";
|
|
5
|
+
|
|
6
|
+
const { Title, Paragraph } = Typography;
|
|
7
|
+
|
|
8
|
+
export default function SdkDemo() {
|
|
9
|
+
const [loading, setLoading] = useState(false);
|
|
10
|
+
const [data, setData] = useState<any[]>([]);
|
|
11
|
+
const [columns, setColumns] = useState<any[]>([]);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 语法糖模式 - 最优雅的调用方式
|
|
15
|
+
*/
|
|
16
|
+
const loadDataWithSyntaxSugar = async () => {
|
|
17
|
+
setLoading(true);
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// 1. 直接通过模型名访问 - 最优雅的方式
|
|
21
|
+
const response = await lovrabetClient.models.Requirements.getList({
|
|
22
|
+
currentPage: 1,
|
|
23
|
+
pageSize: 10,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
processResponse(response, "语法糖模式调用成功!");
|
|
27
|
+
} catch (error: any) {
|
|
28
|
+
handleError(error, "语法糖模式");
|
|
29
|
+
} finally {
|
|
30
|
+
setLoading(false);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 正常调用模式 - 编程式调用方式
|
|
36
|
+
*/
|
|
37
|
+
const loadDataWithNormalMode = async () => {
|
|
38
|
+
setLoading(true);
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
// 1. 先获取模型实例
|
|
42
|
+
const model = lovrabetClient.getModel('Requirements');
|
|
43
|
+
|
|
44
|
+
// 2. 调用模型方法
|
|
45
|
+
const response = await model.getList({
|
|
46
|
+
currentPage: 1,
|
|
47
|
+
pageSize: 10,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
processResponse(response, "正常模式调用成功!");
|
|
51
|
+
} catch (error: any) {
|
|
52
|
+
handleError(error, "正常模式");
|
|
53
|
+
} finally {
|
|
54
|
+
setLoading(false);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 处理响应数据
|
|
60
|
+
*/
|
|
61
|
+
const processResponse = (response: any, successMessage: string) => {
|
|
62
|
+
// 处理返回的数据
|
|
63
|
+
setData(response.tableData || []);
|
|
64
|
+
|
|
65
|
+
// 动态生成表格列
|
|
66
|
+
if (response.tableColumns) {
|
|
67
|
+
const tableColumns = response.tableColumns.map((column: any) => ({
|
|
68
|
+
title: column.title || column.dataIndex,
|
|
69
|
+
dataIndex: column.dataIndex,
|
|
70
|
+
key: column.dataIndex,
|
|
71
|
+
}));
|
|
72
|
+
setColumns(tableColumns);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
message.success(successMessage);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 处理错误
|
|
80
|
+
*/
|
|
81
|
+
const handleError = (error: any, mode: string) => {
|
|
82
|
+
console.error(`${mode}加载失败:`, error);
|
|
83
|
+
message.error(`${mode}加载失败: ${error.message}`);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<div style={{ padding: "24px" }}>
|
|
88
|
+
{/* 标题 */}
|
|
89
|
+
<Title level={2}>
|
|
90
|
+
<ApiOutlined /> Lovrabet SDK 简单演示
|
|
91
|
+
</Title>
|
|
92
|
+
|
|
93
|
+
<Paragraph style={{ color: "#666", marginBottom: 24 }}>
|
|
94
|
+
演示 Lovrabet SDK 的两种调用方式。对比体验语法糖模式和正常模式的差异。
|
|
95
|
+
</Paragraph>
|
|
96
|
+
|
|
97
|
+
{/* 操作按钮 */}
|
|
98
|
+
<Space style={{ marginBottom: 16 }}>
|
|
99
|
+
<Button
|
|
100
|
+
type="primary"
|
|
101
|
+
loading={loading}
|
|
102
|
+
onClick={loadDataWithSyntaxSugar}
|
|
103
|
+
icon={<ApiOutlined />}
|
|
104
|
+
>
|
|
105
|
+
🍬 语法糖模式
|
|
106
|
+
</Button>
|
|
107
|
+
<Button
|
|
108
|
+
loading={loading}
|
|
109
|
+
onClick={loadDataWithNormalMode}
|
|
110
|
+
icon={<ApiOutlined />}
|
|
111
|
+
>
|
|
112
|
+
🔧 正常模式
|
|
113
|
+
</Button>
|
|
114
|
+
</Space>
|
|
115
|
+
|
|
116
|
+
{/* 代码示例 */}
|
|
117
|
+
<Card title="两种调用方式对比" size="small" style={{ marginBottom: 16 }}>
|
|
118
|
+
<div style={{ display: 'flex', gap: '16px' }}>
|
|
119
|
+
{/* 语法糖模式 */}
|
|
120
|
+
<div style={{ flex: 1 }}>
|
|
121
|
+
<div style={{ fontWeight: 'bold', marginBottom: '8px', color: '#1890ff' }}>
|
|
122
|
+
🍬 语法糖模式(推荐)
|
|
123
|
+
</div>
|
|
124
|
+
<pre style={{
|
|
125
|
+
background: "#f0f8ff",
|
|
126
|
+
padding: "12px",
|
|
127
|
+
borderRadius: "4px",
|
|
128
|
+
margin: 0,
|
|
129
|
+
fontSize: "13px",
|
|
130
|
+
border: "1px solid #1890ff"
|
|
131
|
+
}}>
|
|
132
|
+
{`// 一行代码搞定!
|
|
133
|
+
const response = await lovrabetClient
|
|
134
|
+
.models.Requirements.getList({
|
|
135
|
+
currentPage: 1,
|
|
136
|
+
pageSize: 10
|
|
137
|
+
});`}
|
|
138
|
+
</pre>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
{/* 正常模式 */}
|
|
142
|
+
<div style={{ flex: 1 }}>
|
|
143
|
+
<div style={{ fontWeight: 'bold', marginBottom: '8px', color: '#666' }}>
|
|
144
|
+
🔧 正常模式
|
|
145
|
+
</div>
|
|
146
|
+
<pre style={{
|
|
147
|
+
background: "#f5f5f5",
|
|
148
|
+
padding: "12px",
|
|
149
|
+
borderRadius: "4px",
|
|
150
|
+
margin: 0,
|
|
151
|
+
fontSize: "13px",
|
|
152
|
+
border: "1px solid #d9d9d9"
|
|
153
|
+
}}>
|
|
154
|
+
{`// 分步骤调用
|
|
155
|
+
const model = lovrabetClient
|
|
156
|
+
.getModel('Requirements');
|
|
157
|
+
|
|
158
|
+
const response = await model.getList({
|
|
159
|
+
currentPage: 1,
|
|
160
|
+
pageSize: 10
|
|
161
|
+
});`}
|
|
162
|
+
</pre>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
</Card>
|
|
166
|
+
|
|
167
|
+
{/* 数据表格 */}
|
|
168
|
+
{data.length > 0 && (
|
|
169
|
+
<Card title="数据结果" size="small">
|
|
170
|
+
<Table
|
|
171
|
+
columns={columns}
|
|
172
|
+
dataSource={data}
|
|
173
|
+
rowKey={(_, index) => index?.toString() || "0"}
|
|
174
|
+
pagination={false}
|
|
175
|
+
size="small"
|
|
176
|
+
scroll={{ x: true }}
|
|
177
|
+
/>
|
|
178
|
+
</Card>
|
|
179
|
+
)}
|
|
180
|
+
</div>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
|
2
|
+
import { Card, Spin, Alert, Typography, Table } from "antd";
|
|
3
|
+
import ApiUrlDisplay from "../components/ApiUrlDisplay";
|
|
4
|
+
import { apiRequest } from "../utils/api";
|
|
5
|
+
|
|
6
|
+
const { Title, Paragraph } = Typography;
|
|
7
|
+
|
|
8
|
+
const API_URL = "/api/app-c4055413/76a873945291498498737bc85677983d/getList";
|
|
9
|
+
|
|
10
|
+
function TableDisplay() {
|
|
11
|
+
const [loading, setLoading] = useState(true);
|
|
12
|
+
const [error, setError] = useState<string | null>(null);
|
|
13
|
+
const [tableData, setTableData] = useState([]);
|
|
14
|
+
const [columns, setColumns] = useState([]);
|
|
15
|
+
const [pagination, setPagination] = useState({
|
|
16
|
+
current: 1,
|
|
17
|
+
pageSize: 20,
|
|
18
|
+
total: 0,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const fetchData = async (page: number = 1, size: number = 20) => {
|
|
22
|
+
try {
|
|
23
|
+
setLoading(true);
|
|
24
|
+
// 数据表格接口
|
|
25
|
+
const data = await apiRequest(API_URL, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
body: JSON.stringify({ pageSize: size, currentPage: page }),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (data.success) {
|
|
31
|
+
// 设置表格数据
|
|
32
|
+
setTableData(data.data.tableData || []);
|
|
33
|
+
|
|
34
|
+
// 设置分页信息
|
|
35
|
+
setPagination({
|
|
36
|
+
current: data.data.paging?.currentPage || page,
|
|
37
|
+
pageSize: data.data.paging?.pageSize || size,
|
|
38
|
+
total: data.data.paging?.totalCount || 0,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// 根据 tableColumns 动态生成表格列配置
|
|
42
|
+
if (data.data.tableColumns && data.data.tableColumns.length > 0) {
|
|
43
|
+
const tableColumns = data.data.tableColumns.map((column: any) => ({
|
|
44
|
+
title: column.title || column.dataIndex,
|
|
45
|
+
dataIndex: column.dataIndex,
|
|
46
|
+
key: column.dataIndex,
|
|
47
|
+
width: 150,
|
|
48
|
+
ellipsis: true,
|
|
49
|
+
render: (text: any) => {
|
|
50
|
+
// 处理复杂数据类型的显示
|
|
51
|
+
if (Array.isArray(text) && text.length > 0 && text[0]?.label) {
|
|
52
|
+
return text.map((item: any) => item.label).join(", ");
|
|
53
|
+
}
|
|
54
|
+
if (typeof text === "object" && text !== null) {
|
|
55
|
+
return JSON.stringify(text);
|
|
56
|
+
}
|
|
57
|
+
return text;
|
|
58
|
+
},
|
|
59
|
+
}));
|
|
60
|
+
setColumns(tableColumns);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
} catch (err: any) {
|
|
64
|
+
console.error("数据获取失败:", err);
|
|
65
|
+
setError(err.message || "表格数据加载失败");
|
|
66
|
+
} finally {
|
|
67
|
+
setLoading(false);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
fetchData();
|
|
73
|
+
}, []);
|
|
74
|
+
|
|
75
|
+
const handleTableChange = (paginationConfig: any) => {
|
|
76
|
+
fetchData(paginationConfig.current, paginationConfig.pageSize);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<div style={{ padding: "24px" }}>
|
|
81
|
+
<Card>
|
|
82
|
+
<Title level={2}>数据表格展示</Title>
|
|
83
|
+
<Paragraph>
|
|
84
|
+
这是一个从真实API获取数据并展示的表格示例,展示了接口返回的tableData中的所有数据。
|
|
85
|
+
</Paragraph>
|
|
86
|
+
<Paragraph>数据来源:{API_URL}</Paragraph>
|
|
87
|
+
<Paragraph>
|
|
88
|
+
访问请先确保:1. app.lovrabet.com已登录 2.应用有权限 3. 接口有权限
|
|
89
|
+
</Paragraph>
|
|
90
|
+
</Card>
|
|
91
|
+
|
|
92
|
+
<Card style={{ marginTop: "24px" }}>
|
|
93
|
+
{loading ? (
|
|
94
|
+
<div style={{ textAlign: "center", padding: "50px" }}>
|
|
95
|
+
<Spin size="large" tip="正在加载表格数据..." />
|
|
96
|
+
</div>
|
|
97
|
+
) : error ? (
|
|
98
|
+
<Alert
|
|
99
|
+
message="表格数据加载失败,请检查接口权限,可以替换为自己有权限的接口"
|
|
100
|
+
description={error}
|
|
101
|
+
type="error"
|
|
102
|
+
showIcon
|
|
103
|
+
/>
|
|
104
|
+
) : (
|
|
105
|
+
<>
|
|
106
|
+
<Table
|
|
107
|
+
dataSource={tableData}
|
|
108
|
+
columns={columns}
|
|
109
|
+
pagination={{
|
|
110
|
+
...pagination,
|
|
111
|
+
showSizeChanger: true,
|
|
112
|
+
showQuickJumper: true,
|
|
113
|
+
showTotal: (total, range) =>
|
|
114
|
+
`第 ${range[0]}-${range[1]} 条/共 ${total} 条`,
|
|
115
|
+
pageSizeOptions: ["10", "20", "50", "100"],
|
|
116
|
+
}}
|
|
117
|
+
scroll={{ x: 1200 }}
|
|
118
|
+
onChange={handleTableChange}
|
|
119
|
+
rowKey={(record, index) => `${record.id || index}`}
|
|
120
|
+
size="middle"
|
|
121
|
+
/>
|
|
122
|
+
<ApiUrlDisplay apiUrl={API_URL} />
|
|
123
|
+
</>
|
|
124
|
+
)}
|
|
125
|
+
</Card>
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export default TableDisplay;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
|
3
|
+
import { getBasename } from "@ice/stark-app";
|
|
4
|
+
import MainLayout from "../layouts/MainLayout";
|
|
5
|
+
import routes from "~react-pages";
|
|
6
|
+
|
|
7
|
+
const router = createBrowserRouter(
|
|
8
|
+
[
|
|
9
|
+
{
|
|
10
|
+
path: "/",
|
|
11
|
+
element: <MainLayout />,
|
|
12
|
+
children: routes,
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
{
|
|
16
|
+
// 可选:通过getBasename()获取到微应用运行时的basename并传入
|
|
17
|
+
basename: getBasename() || "/",
|
|
18
|
+
},
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
console.log("MicroAppRouter:", {
|
|
22
|
+
routes: router.routes,
|
|
23
|
+
basename: router.basename,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const AppRouter: React.FC = () => {
|
|
27
|
+
return <RouterProvider router={router} />;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default AppRouter;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
* {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 0;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
body {
|
|
8
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
|
9
|
+
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
|
10
|
+
sans-serif;
|
|
11
|
+
-webkit-font-smoothing: antialiased;
|
|
12
|
+
-moz-osx-font-smoothing: grayscale;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#root {
|
|
16
|
+
width: 100%;
|
|
17
|
+
height: 100vh;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* 自定义滚动条样式 */
|
|
21
|
+
::-webkit-scrollbar {
|
|
22
|
+
width: 6px;
|
|
23
|
+
height: 6px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
::-webkit-scrollbar-track {
|
|
27
|
+
background: #f1f1f1;
|
|
28
|
+
border-radius: 3px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
::-webkit-scrollbar-thumb {
|
|
32
|
+
background: #c1c1c1;
|
|
33
|
+
border-radius: 3px;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
::-webkit-scrollbar-thumb:hover {
|
|
37
|
+
background: #a8a8a8;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* 响应式设计 */
|
|
41
|
+
@media (max-width: 768px) {
|
|
42
|
+
.ant-layout-sider {
|
|
43
|
+
position: fixed !important;
|
|
44
|
+
height: 100vh;
|
|
45
|
+
z-index: 999;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// 简单封装 apiRequest
|
|
2
|
+
export const apiRequest = async (path: string, options: RequestInit = {}) => {
|
|
3
|
+
const response = await fetch(`https://runtime.lovrabet.com${path}`, {
|
|
4
|
+
credentials: "include", // 关键配置:跨域请求携带Cookie
|
|
5
|
+
headers: {
|
|
6
|
+
"Content-Type": "application/json",
|
|
7
|
+
...(options.headers || {}),
|
|
8
|
+
},
|
|
9
|
+
...options,
|
|
10
|
+
});
|
|
11
|
+
return response.json();
|
|
12
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"experimentalDecorators": true,
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"importHelpers": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"target": "es2017",
|
|
8
|
+
"module": "es2022",
|
|
9
|
+
"strict": false,
|
|
10
|
+
"moduleResolution": "node",
|
|
11
|
+
"allowSyntheticDefaultImports": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"lib": ["ESNext", "DOM"],
|
|
15
|
+
"jsx": "react",
|
|
16
|
+
"declaration": true,
|
|
17
|
+
"downlevelIteration": true,
|
|
18
|
+
"resolveJsonModule": true,
|
|
19
|
+
"baseUrl": ".",
|
|
20
|
+
"paths": {
|
|
21
|
+
"@": ["./src"],
|
|
22
|
+
"@/*": ["./src/*"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"include": ["src", "types"]
|
|
26
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { defineConfig, loadEnv } from "vite";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import react from "@vitejs/plugin-react";
|
|
5
|
+
import htmlPlugin from "vite-plugin-index-html";
|
|
6
|
+
import pluginExternal from "vite-plugin-external";
|
|
7
|
+
import Pages from "vite-plugin-pages";
|
|
8
|
+
import pkgJson from "./package.json";
|
|
9
|
+
|
|
10
|
+
const version = pkgJson.version;
|
|
11
|
+
const appName = pkgJson.name.split("/").pop();
|
|
12
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
|
|
14
|
+
// https://vitejs.dev/config/
|
|
15
|
+
export default defineConfig(async ({ mode }) => {
|
|
16
|
+
const env = loadEnv(mode, __dirname);
|
|
17
|
+
const isDev = mode === "development";
|
|
18
|
+
const port = Number(env.PORT) || 5173;
|
|
19
|
+
const isCdn = !isDev && Boolean(process.env.CDN_DOMAIN);
|
|
20
|
+
const outDir = isCdn ? `dist/${appName}/${version}` : "dist";
|
|
21
|
+
const base = isCdn ? `${process.env.CDN_DOMAIN}${outDir}/` : "/";
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
base,
|
|
25
|
+
envDir: __dirname,
|
|
26
|
+
plugins: [
|
|
27
|
+
react(),
|
|
28
|
+
Pages({
|
|
29
|
+
dirs: "src/pages",
|
|
30
|
+
extensions: ["tsx"],
|
|
31
|
+
routeStyle: "remix", // 使用 remix 风格,更好兼容 React Router v6
|
|
32
|
+
importMode: "sync", // 使用同步导入避免 Suspense 问题
|
|
33
|
+
}),
|
|
34
|
+
htmlPlugin({
|
|
35
|
+
input: "/src/main.tsx", // 使用绝对路径避免嵌套路由问题
|
|
36
|
+
preserveEntrySignatures: "exports-only",
|
|
37
|
+
}),
|
|
38
|
+
pluginExternal({
|
|
39
|
+
externals: {
|
|
40
|
+
react: "React",
|
|
41
|
+
"react-dom": "ReactDOM",
|
|
42
|
+
antd: "antd",
|
|
43
|
+
dayjs: "dayjs",
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
],
|
|
47
|
+
resolve: {
|
|
48
|
+
alias: {
|
|
49
|
+
"@": "/src",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
// 可选配置:提供https自签名证书及跨域访问能力
|
|
53
|
+
// 因为接口域名为 runtime.lovrabet.com 存在跨域,服务端配置了允许 dev.lovrabet.com 的跨域请求,从而实现本地开发能够正常请求接口
|
|
54
|
+
// 这些配置不是必须的,你也可以使用 proxy 等任意手段自行处理跨域问题
|
|
55
|
+
server: isDev
|
|
56
|
+
? {
|
|
57
|
+
port,
|
|
58
|
+
open: `https://dev.lovrabet.com:${port}`,
|
|
59
|
+
strictPort: true,
|
|
60
|
+
host: "0.0.0.0",
|
|
61
|
+
https: await (
|
|
62
|
+
await fetch("https://g.yuntooai.com/cert/lovrabet-dev.json")
|
|
63
|
+
).json(),
|
|
64
|
+
headers: {
|
|
65
|
+
"Access-Control-Allow-Origin": "*",
|
|
66
|
+
"Access-Control-Allow-Methods":
|
|
67
|
+
"GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
|
68
|
+
"Access-Control-Allow-Headers":
|
|
69
|
+
"X-Requested-With, Content-Type, Authorization",
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
: undefined,
|
|
73
|
+
build: {
|
|
74
|
+
outDir,
|
|
75
|
+
target: "esnext",
|
|
76
|
+
rollupOptions: {
|
|
77
|
+
output: {
|
|
78
|
+
format: "es" as const,
|
|
79
|
+
entryFileNames: `assets/[name].js`,
|
|
80
|
+
assetFileNames: `assets/[name].css`,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
optimizeDeps: {
|
|
85
|
+
include: ["react", "react-dom", "antd", "dayjs"],
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
});
|