@gadmin2n/schematics 0.0.122 → 0.0.124

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 (25) hide show
  1. package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/Event.ts +2 -0
  2. package/dist/lib/application/files/gadmin2-game-angle-demo/gitignore +5 -1
  3. package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +1 -0
  4. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/notify-dev-servers.js +106 -0
  5. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agendaJob/agendaJob.controller.ts +2 -2
  6. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/audit/audit.controller.ts +2 -2
  7. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/game/game.controller.ts +2 -2
  8. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.controller.ts +2 -2
  9. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/pageResource/pageResource.controller.ts +2 -2
  10. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.controller.ts +2 -2
  11. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.controller.ts +2 -2
  12. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/rolePages/rolePages.controller.ts +2 -2
  13. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/roleResource/roleResource.controller.ts +2 -2
  14. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.controller.ts +2 -2
  15. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.ts +2 -2
  16. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.controller.ts +2 -2
  17. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeType/workflowNodeType.controller.ts +2 -2
  18. package/dist/lib/application/files/gadmin2-game-angle-demo/web/.vite-restart +1 -0
  19. package/dist/lib/application/files/gadmin2-game-angle-demo/web/package.json +1 -1
  20. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +0 -1
  21. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agenda/index.tsx +0 -6
  22. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/index.ts +0 -7
  23. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/list.tsx +2 -0
  24. package/dist/lib/application/files/gadmin2-game-angle-demo/web/vite.config.ts +101 -3
  25. package/package.json +1 -1
@@ -35,6 +35,8 @@ export const Event: ModelConfig = {
35
35
  "!creator",
36
36
  "!updatedAt",
37
37
  "!startDate",
38
+ "!oitOwner",
39
+ "!snSysId",
38
40
  ],
39
41
  rowSelection: {
40
42
  actions: [
@@ -18,6 +18,9 @@ lerna-debug.log*
18
18
  .env.local
19
19
  keys.txt
20
20
 
21
+ # gadmin g prisma restart sentinel(vite dev server 监听)
22
+ web/.vite-restart
23
+
21
24
  # OS
22
25
  .DS_Store
23
26
 
@@ -53,4 +56,5 @@ settings.local.json
53
56
  docs/
54
57
  .frontend-slides/
55
58
  .agent
56
- agent-eval/runs/
59
+ agent-eval/runs/
60
+ agent-eval/baseline/
@@ -29,6 +29,7 @@
29
29
  "postgenerate:dev": "dotenv -e .env.local -e .env -- ts-node seed/data-mngt.seed.ts",
30
30
  "generate:web": "dotenv -e .env.local -e .env -- npx prisma generate --generator react",
31
31
  "generate:server": "dotenv -e .env.local -e .env -- npx prisma generate --generator client --generator nestjs",
32
+ "postgadminGenerate": "node scripts/notify-dev-servers.js",
32
33
  "push:db": "dotenv -e .env.local -e .env -- prisma db push --skip-generate",
33
34
  "seed": "dotenv -e .env.local -e .env -- ts-node seed/index.ts",
34
35
  "prisma:studio": "dotenv -e .env.local -e .env -- prisma studio"
@@ -0,0 +1,106 @@
1
+ /* eslint-disable */
2
+ /**
3
+ * postgadminGenerate hook —— 由 gadmin2 CLI 在生成+分发全部完成后触发。
4
+ *
5
+ * 目的:
6
+ * 1. 释放 Vite dev server 内存(server.restart() 会清空 module graph)
7
+ * 2. 让浏览器自动 full-reload,无需手工刷新
8
+ *
9
+ * 时序:
10
+ * nest --watch 会因为 server/src/modules/{model} 变化自动重启,
11
+ * 此脚本先 poll 它的 /api/health/live 直到 ready,再 touch web/.vite-restart,
12
+ * 保证浏览器恢复时后端 API 已就绪,避免 502/ECONNREFUSED。
13
+ *
14
+ * 环境变量(由 CLI 注入):
15
+ * GADMIN_MODE = full | web | server
16
+ *
17
+ * 与 CLI 通信约定:
18
+ * - CWD 是 server/(CLI shell.cd('server/') 后调用)
19
+ * - 前端 sentinel 位于 ../web/.vite-restart
20
+ */
21
+ const fs = require('fs');
22
+ const http = require('http');
23
+ const path = require('path');
24
+
25
+ const MODE = process.env.GADMIN_MODE || 'full';
26
+ const shouldWaitNest = MODE === 'full' || MODE === 'server';
27
+ const shouldTouchWeb = MODE === 'full' || MODE === 'web';
28
+
29
+ const NEST_PORT = Number(process.env.NEST_PORT) || 8000;
30
+ const DEPLOY_NAME = process.env.DEPLOY_NAME || '';
31
+ const HEALTH_URL = `http://127.0.0.1:${NEST_PORT}${DEPLOY_NAME}/api/health/live`;
32
+ const WEB_SENTINEL = path.resolve(process.cwd(), '..', 'web', '.vite-restart');
33
+
34
+ function log(msg) {
35
+ process.stdout.write(`[postgadminGenerate] ${msg}\n`);
36
+ }
37
+
38
+ function pingOnce(url) {
39
+ return new Promise((resolve) => {
40
+ const req = http.get(url, { timeout: 1000 }, (res) => {
41
+ resolve(res.statusCode === 200);
42
+ res.resume();
43
+ });
44
+ req.on('error', () => resolve(false));
45
+ req.on('timeout', () => {
46
+ req.destroy();
47
+ resolve(false);
48
+ });
49
+ });
50
+ }
51
+
52
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
53
+
54
+ async function waitForNestReady() {
55
+ const initiallyAlive = await pingOnce(HEALTH_URL);
56
+ if (!initiallyAlive) {
57
+ log(`nest not running at ${HEALTH_URL}, skip waiting.`);
58
+ return;
59
+ }
60
+ log(`waiting for nest restart at ${HEALTH_URL} ...`);
61
+
62
+ // Phase 1: 等 nest --watch 检测到文件变化并开始重编译(服务短暂 down)
63
+ const started = Date.now();
64
+ const observeDownTimeoutMs = 15_000;
65
+ let observedDown = false;
66
+ while (Date.now() - started < observeDownTimeoutMs) {
67
+ if (!(await pingOnce(HEALTH_URL))) {
68
+ observedDown = true;
69
+ break;
70
+ }
71
+ await sleep(300);
72
+ }
73
+ if (!observedDown) {
74
+ log('nest did not restart within 15s (maybe not in --watch mode); continue.');
75
+ return;
76
+ }
77
+
78
+ // Phase 2: 等 nest 重新起来
79
+ const totalTimeoutMs = 60_000;
80
+ while (Date.now() - started < totalTimeoutMs) {
81
+ if (await pingOnce(HEALTH_URL)) {
82
+ log('nest ready.');
83
+ return;
84
+ }
85
+ await sleep(500);
86
+ }
87
+ log(`nest not ready within ${totalTimeoutMs}ms, continue anyway.`);
88
+ }
89
+
90
+ function touchViteSentinel() {
91
+ try {
92
+ fs.mkdirSync(path.dirname(WEB_SENTINEL), { recursive: true });
93
+ fs.writeFileSync(WEB_SENTINEL, `${Date.now()}\n`);
94
+ log(`notified vite via ${WEB_SENTINEL}`);
95
+ } catch (e) {
96
+ log(`failed to touch ${WEB_SENTINEL}: ${e && e.message ? e.message : e}`);
97
+ }
98
+ }
99
+
100
+ (async () => {
101
+ if (shouldWaitNest) await waitForNestReady();
102
+ if (shouldTouchWeb) touchViteSentinel();
103
+ })().catch((e) => {
104
+ log(`unexpected error: ${e && e.stack ? e.stack : e}`);
105
+ // 非致命,不 throw 避免影响 CLI 退出码
106
+ });
@@ -32,7 +32,7 @@ import {
32
32
  AgendaJobFindManyArgs,
33
33
  AgendaJobWhereSelect,
34
34
  EffectedCount,
35
- UploudResponse,
35
+ UploadResponse,
36
36
  } from '../../generated/agendaJob/dto/agendaJob-types.dto';
37
37
  import { AgendaJobEntity } from '../../generated/agendaJob/entities/agendaJob.entity';
38
38
  import { AgendaJobService } from './agendaJob.service';
@@ -137,7 +137,7 @@ export class AgendaJobController {
137
137
  action: 'create',
138
138
  possession: 'any',
139
139
  })
140
- @ApiCreatedResponse({ type: UploudResponse })
140
+ @ApiCreatedResponse({ type: UploadResponse })
141
141
  async uploadFile() {
142
142
  // 该资源为只读,上传接口已禁用
143
143
  throw new NotFoundException();
@@ -38,7 +38,7 @@ import {
38
38
  AuditFindManyArgs,
39
39
  AuditWhereSelect,
40
40
  EffectedCount,
41
- UploudResponse,
41
+ UploadResponse,
42
42
  } from '../../generated/audit/dto/audit-types.dto';
43
43
  import { CreateAuditDto } from '../../generated/audit/dto/create-audit.dto';
44
44
  import { UpdateAuditDto } from '../../generated/audit/dto/update-audit.dto';
@@ -173,7 +173,7 @@ export class AuditController {
173
173
  action: 'create',
174
174
  possession: 'any',
175
175
  })
176
- @ApiCreatedResponse({ type: UploudResponse })
176
+ @ApiCreatedResponse({ type: UploadResponse })
177
177
  @UseInterceptors(FileInterceptor('file'))
178
178
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
179
179
  const fileName = await diskStorage(
@@ -39,7 +39,7 @@ import {
39
39
  EffectedCount,
40
40
  GameFindManyArgs,
41
41
  GameWhereSelect,
42
- UploudResponse,
42
+ UploadResponse,
43
43
  } from '../../generated/game/dto/game-types.dto';
44
44
  import { UpdateGameDto } from '../../generated/game/dto/update-game.dto';
45
45
  import { GameEntity } from '../../generated/game/entities/game.entity';
@@ -171,7 +171,7 @@ export class GameController {
171
171
  action: 'create',
172
172
  possession: 'any',
173
173
  })
174
- @ApiCreatedResponse({ type: UploudResponse })
174
+ @ApiCreatedResponse({ type: UploadResponse })
175
175
  @UseInterceptors(FileInterceptor('file'))
176
176
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
177
177
  const fileName = await diskStorage(
@@ -39,7 +39,7 @@ import {
39
39
  EffectedCount,
40
40
  PageFindManyArgs,
41
41
  PageWhereSelect,
42
- UploudResponse,
42
+ UploadResponse,
43
43
  } from '../../generated/page/dto/page-types.dto';
44
44
  import { UpdatePageDto } from '../../generated/page/dto/update-page.dto';
45
45
  import { PageEntity } from '../../generated/page/entities/page.entity';
@@ -233,7 +233,7 @@ export class PageController {
233
233
  action: 'create',
234
234
  possession: 'any',
235
235
  })
236
- @ApiCreatedResponse({ type: UploudResponse })
236
+ @ApiCreatedResponse({ type: UploadResponse })
237
237
  @UseInterceptors(FileInterceptor('file'))
238
238
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
239
239
  const fileName = await diskStorage(
@@ -39,7 +39,7 @@ import {
39
39
  EffectedCount,
40
40
  PageResourceFindManyArgs,
41
41
  PageResourceWhereSelect,
42
- UploudResponse,
42
+ UploadResponse,
43
43
  } from '../../generated/pageResource/dto/pageResource-types.dto';
44
44
  import { UpdatePageResourceDto } from '../../generated/pageResource/dto/update-pageResource.dto';
45
45
  import { PageResourceEntity } from '../../generated/pageResource/entities/pageResource.entity';
@@ -179,7 +179,7 @@ export class PageResourceController {
179
179
  action: 'create',
180
180
  possession: 'any',
181
181
  })
182
- @ApiCreatedResponse({ type: UploudResponse })
182
+ @ApiCreatedResponse({ type: UploadResponse })
183
183
  @UseInterceptors(FileInterceptor('file'))
184
184
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
185
185
  const fileName = await diskStorage(
@@ -39,7 +39,7 @@ import {
39
39
  EffectedCount,
40
40
  ResourceFindManyArgs,
41
41
  ResourceWhereSelect,
42
- UploudResponse,
42
+ UploadResponse,
43
43
  } from '../../generated/resource/dto/resource-types.dto';
44
44
  import { UpdateResourceDto } from '../../generated/resource/dto/update-resource.dto';
45
45
  import { ResourceEntity } from '../../generated/resource/entities/resource.entity';
@@ -179,7 +179,7 @@ export class ResourceController {
179
179
  action: 'create',
180
180
  possession: 'any',
181
181
  })
182
- @ApiCreatedResponse({ type: UploudResponse })
182
+ @ApiCreatedResponse({ type: UploadResponse })
183
183
  @UseInterceptors(FileInterceptor('file'))
184
184
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
185
185
  const fileName = await diskStorage(
@@ -39,7 +39,7 @@ import {
39
39
  EffectedCount,
40
40
  RoleFindManyArgs,
41
41
  RoleWhereSelect,
42
- UploudResponse,
42
+ UploadResponse,
43
43
  } from '../../generated/role/dto/role-types.dto';
44
44
  import { UpdateRoleDto } from '../../generated/role/dto/update-role.dto';
45
45
  import { RoleEntity } from '../../generated/role/entities/role.entity';
@@ -193,7 +193,7 @@ export class RoleController {
193
193
  action: 'create',
194
194
  possession: 'any',
195
195
  })
196
- @ApiCreatedResponse({ type: UploudResponse })
196
+ @ApiCreatedResponse({ type: UploadResponse })
197
197
  @UseInterceptors(FileInterceptor('file'))
198
198
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
199
199
  const fileName = await diskStorage(
@@ -39,7 +39,7 @@ import {
39
39
  EffectedCount,
40
40
  RolePagesFindManyArgs,
41
41
  RolePagesWhereSelect,
42
- UploudResponse,
42
+ UploadResponse,
43
43
  } from '../../generated/rolePages/dto/rolePages-types.dto';
44
44
  import { UpdateRolePagesDto } from '../../generated/rolePages/dto/update-rolePages.dto';
45
45
  import { RolePagesEntity } from '../../generated/rolePages/entities/rolePages.entity';
@@ -179,7 +179,7 @@ export class RolePagesController {
179
179
  action: 'create',
180
180
  possession: 'any',
181
181
  })
182
- @ApiCreatedResponse({ type: UploudResponse })
182
+ @ApiCreatedResponse({ type: UploadResponse })
183
183
  @UseInterceptors(FileInterceptor('file'))
184
184
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
185
185
  const fileName = await diskStorage(
@@ -39,7 +39,7 @@ import {
39
39
  EffectedCount,
40
40
  RoleResourceFindManyArgs,
41
41
  RoleResourceWhereSelect,
42
- UploudResponse,
42
+ UploadResponse,
43
43
  } from '../../generated/roleResource/dto/roleResource-types.dto';
44
44
  import { UpdateRoleResourceDto } from '../../generated/roleResource/dto/update-roleResource.dto';
45
45
  import { RoleResourceEntity } from '../../generated/roleResource/entities/roleResource.entity';
@@ -179,7 +179,7 @@ export class RoleResourceController {
179
179
  action: 'create',
180
180
  possession: 'any',
181
181
  })
182
- @ApiCreatedResponse({ type: UploudResponse })
182
+ @ApiCreatedResponse({ type: UploadResponse })
183
183
  @UseInterceptors(FileInterceptor('file'))
184
184
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
185
185
  const fileName = await diskStorage(
@@ -38,7 +38,7 @@ import { CreateUserDto } from '../../generated/user/dto/create-user.dto';
38
38
  import { UpdateUserDto } from '../../generated/user/dto/update-user.dto';
39
39
  import {
40
40
  EffectedCount,
41
- UploudResponse,
41
+ UploadResponse,
42
42
  UserFindManyArgs,
43
43
  UserWhereSelect,
44
44
  } from '../../generated/user/dto/user-types.dto';
@@ -181,7 +181,7 @@ export class UserController {
181
181
  action: 'create',
182
182
  possession: 'any',
183
183
  })
184
- @ApiCreatedResponse({ type: UploudResponse })
184
+ @ApiCreatedResponse({ type: UploadResponse })
185
185
  @UseInterceptors(FileInterceptor('file'))
186
186
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
187
187
  const fileName = await diskStorage(
@@ -30,7 +30,7 @@ import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
30
30
  import { Logger } from 'winston';
31
31
  import {
32
32
  EffectedCount,
33
- UploudResponse,
33
+ UploadResponse,
34
34
  WorkflowEventOutboxFindManyArgs,
35
35
  WorkflowEventOutboxWhereSelect,
36
36
  } from '../../generated/workflowEventOutbox/dto/workflowEventOutbox-types.dto';
@@ -139,7 +139,7 @@ export class WorkflowEventOutboxController {
139
139
  action: 'create',
140
140
  possession: 'any',
141
141
  })
142
- @ApiCreatedResponse({ type: UploudResponse })
142
+ @ApiCreatedResponse({ type: UploadResponse })
143
143
  async uploadFile() {
144
144
  // 该资源为只读,上传接口已禁用
145
145
  throw new NotFoundException();
@@ -38,7 +38,7 @@ import { CreateWorkflowNodeInstanceDto } from '../../generated/workflowNodeInsta
38
38
  import { UpdateWorkflowNodeInstanceDto } from '../../generated/workflowNodeInstance/dto/update-workflowNodeInstance.dto';
39
39
  import {
40
40
  EffectedCount,
41
- UploudResponse,
41
+ UploadResponse,
42
42
  WorkflowNodeInstanceFindManyArgs,
43
43
  WorkflowNodeInstanceWhereSelect,
44
44
  } from '../../generated/workflowNodeInstance/dto/workflowNodeInstance-types.dto';
@@ -196,7 +196,7 @@ export class WorkflowNodeInstanceController {
196
196
  action: 'create',
197
197
  possession: 'any',
198
198
  })
199
- @ApiCreatedResponse({ type: UploudResponse })
199
+ @ApiCreatedResponse({ type: UploadResponse })
200
200
  @UseInterceptors(FileInterceptor('file'))
201
201
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
202
202
  const fileName = await diskStorage(
@@ -38,7 +38,7 @@ import { CreateWorkflowNodeTypeDto } from '../../generated/workflowNodeType/dto/
38
38
  import { UpdateWorkflowNodeTypeDto } from '../../generated/workflowNodeType/dto/update-workflowNodeType.dto';
39
39
  import {
40
40
  EffectedCount,
41
- UploudResponse,
41
+ UploadResponse,
42
42
  WorkflowNodeTypeFindManyArgs,
43
43
  WorkflowNodeTypeWhereSelect,
44
44
  } from '../../generated/workflowNodeType/dto/workflowNodeType-types.dto';
@@ -181,7 +181,7 @@ export class WorkflowNodeTypeController {
181
181
  action: 'create',
182
182
  possession: 'any',
183
183
  })
184
- @ApiCreatedResponse({ type: UploudResponse })
184
+ @ApiCreatedResponse({ type: UploadResponse })
185
185
  @UseInterceptors(FileInterceptor('file'))
186
186
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
187
187
  const fileName = await diskStorage(
@@ -78,7 +78,7 @@
78
78
  "vite-tsconfig-paths": "^5.1.4"
79
79
  },
80
80
  "scripts": {
81
- "dev": "vite --port 3000",
81
+ "dev": "NODE_OPTIONS='--max-old-space-size=4096' vite --port 3000",
82
82
  "build": "tsc && vite build",
83
83
  "preview": "vite preview",
84
84
  "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx}\"",
@@ -3,7 +3,6 @@ import type { IResourceItem, ResourceProps } from '@refinedev/core';
3
3
  import { DashboardOutlined, SettingOutlined } from '@ant-design/icons';
4
4
  import { getRoutePath } from 'config/routeRegistry';
5
5
  import { useUserPageAccess } from './useUserPageAccess';
6
- import generatedResources from 'generated/resources';
7
6
 
8
7
  /**
9
8
  * Dynamic Resources Hook for erp-backend/web
@@ -217,7 +217,6 @@ export default function AgendaJobsPage() {
217
217
  );
218
218
 
219
219
  // Auto-refresh
220
- const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
221
220
  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
222
221
 
223
222
  const fetchJobs = useCallback(async () => {
@@ -248,13 +247,8 @@ export default function AgendaJobsPage() {
248
247
  }
249
248
  }, [page, filterState, filterToggle, filterName, filterModule]);
250
249
 
251
- // Initial fetch + auto-refresh every 5s
252
250
  useEffect(() => {
253
251
  fetchJobs();
254
- timerRef.current = setInterval(fetchJobs, 5000);
255
- return () => {
256
- if (timerRef.current) clearInterval(timerRef.current);
257
- };
258
252
  }, [fetchJobs]);
259
253
 
260
254
  // ─── Row actions ───────────────────────────────────────────────────────────
@@ -1,8 +1 @@
1
1
  export * from './list';
2
-
3
- // Stub exports for generated/resources.tsx compatibility (gadmin2 generated imports)
4
- const EmptyComponent = () => null;
5
- export const AuditCreate = EmptyComponent;
6
- export const AuditEdit = EmptyComponent;
7
- export const AuditList = EmptyComponent;
8
- export const AuditShow = EmptyComponent;
@@ -218,3 +218,5 @@ export const AuditLogPage = () => {
218
218
  </div>
219
219
  );
220
220
  };
221
+
222
+ export const AuditList = AuditLogPage;
@@ -1,10 +1,34 @@
1
+ import path from 'node:path';
1
2
  import react from '@vitejs/plugin-react';
2
- import { defineConfig, loadEnv } from 'vite';
3
+ import { defineConfig, loadEnv, type Plugin } from 'vite';
3
4
  import tsconfigPaths from 'vite-tsconfig-paths';
4
5
  import { devShellPlugin } from './src/plugins/devShellPlugin';
5
6
 
7
+ // gadmin g prisma 生成完毕后触发:CLI 会 touch 本文件,
8
+ // 插件监听变更后调用 server.restart() —— 清空 module graph 释放内存,
9
+ // 并通过 HMR ws 广播 full-reload,浏览器自动刷新。
10
+ function gadminRestartPlugin(): Plugin {
11
+ const sentinel = path.resolve(__dirname, '.vite-restart');
12
+ return {
13
+ name: 'gadmin-restart-on-generate',
14
+ configureServer(server) {
15
+ server.watcher.add(sentinel);
16
+ server.watcher.on('change', (file) => {
17
+ if (path.resolve(file) === sentinel) {
18
+ server.config.logger.info(
19
+ '[gadmin] generated code changed, restarting vite...',
20
+ { timestamp: true },
21
+ );
22
+ server.restart();
23
+ }
24
+ });
25
+ },
26
+ };
27
+ }
28
+
6
29
  export default defineConfig(({ mode }) => {
7
30
  const env = loadEnv(mode, process.cwd(), '');
31
+ const isDev = mode !== 'production';
8
32
 
9
33
  const backendUrl = env.VITE_API_PORT
10
34
  ? `http://localhost:${env.VITE_API_PORT}`
@@ -20,14 +44,43 @@ export default defineConfig(({ mode }) => {
20
44
  : undefined;
21
45
 
22
46
  return {
23
- plugins: [tsconfigPaths({ root: __dirname }), react(), devShellPlugin()],
47
+ plugins: [
48
+ tsconfigPaths({ root: __dirname }),
49
+ react(),
50
+ devShellPlugin(),
51
+ gadminRestartPlugin(),
52
+ ],
24
53
  define: {
25
54
  'process.env': {},
26
55
  'process.argv': [],
27
56
  'process.version': JSON.stringify(''),
28
57
  'process.platform': JSON.stringify(''),
29
58
  },
59
+ css: { devSourcemap: false },
60
+ esbuild: {
61
+ sourcemap: !isDev,
62
+ },
30
63
  optimizeDeps: {
64
+ include: [
65
+ 'antd',
66
+ '@ant-design/icons',
67
+ 'echarts',
68
+ '@xyflow/react',
69
+ 'lodash',
70
+ 'dayjs',
71
+ '@refinedev/core',
72
+ '@refinedev/antd',
73
+ '@refinedev/react-router-v6',
74
+ '@refinedev/kbar',
75
+ 'react',
76
+ 'react-dom',
77
+ 'react-router-dom',
78
+ 'react-i18next',
79
+ 'i18next',
80
+ '@monaco-editor/react',
81
+ 'vanilla-jsoneditor',
82
+ 'json-source-map',
83
+ ],
31
84
  esbuildOptions: {
32
85
  loader: { '.js': 'jsx' },
33
86
  },
@@ -36,13 +89,58 @@ export default defineConfig(({ mode }) => {
36
89
  host: true,
37
90
  allowedHosts: true,
38
91
  proxy: proxyConfig,
92
+ watch: {
93
+ ignored: [
94
+ '**/node_modules/**',
95
+ '**/dist/**',
96
+ '**/.git/**',
97
+ '**/coverage/**',
98
+ '**/logs/**',
99
+ '**/*.log',
100
+ '**/.vite/**',
101
+ // 生成物不参与 HMR:分发期间会有几百个 add/change 事件,
102
+ // 若不 ignore 会触发大量级联失效。改由 gadminRestartPlugin
103
+ // 在分发全部完成后一次性 server.restart() 加载最新内容。
104
+ '**/src/generated/**',
105
+ ],
106
+ awaitWriteFinish: {
107
+ stabilityThreshold: 200,
108
+ pollInterval: 50,
109
+ },
110
+ },
39
111
  },
40
112
  build: {
41
113
  sourcemap: true,
42
114
  rollupOptions: {
43
115
  output: {
44
116
  manualChunks: {
45
- antd: ['antd'],
117
+ react: ['react', 'react-dom', 'react-router-dom'],
118
+ antd: ['antd', '@ant-design/icons'],
119
+ refine: [
120
+ '@refinedev/core',
121
+ '@refinedev/antd',
122
+ '@refinedev/react-router-v6',
123
+ '@refinedev/kbar',
124
+ ],
125
+ echarts: ['echarts'],
126
+ flow: ['@xyflow/react'],
127
+ editor: [
128
+ '@monaco-editor/react',
129
+ 'vanilla-jsoneditor',
130
+ '@uiw/react-md-editor',
131
+ ],
132
+ i18n: [
133
+ 'i18next',
134
+ 'react-i18next',
135
+ 'i18next-browser-languagedetector',
136
+ 'i18next-http-backend',
137
+ ],
138
+ lodash: [
139
+ 'lodash',
140
+ 'lodash.foreach',
141
+ 'lodash.groupby',
142
+ 'lodash.memoize',
143
+ ],
46
144
  },
47
145
  },
48
146
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gadmin2n/schematics",
3
- "version": "0.0.122",
3
+ "version": "0.0.124",
4
4
  "description": "Gadmin - modern, fast, powerful node.js web framework (@schematics)",
5
5
  "main": "dist/index.js",
6
6
  "files": [