@_tc/template-core 0.2.0-bate.0 → 0.2.0-bate.10

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 (164) hide show
  1. package/.skills/tc-component-usage-skills/reference/template-core-frontend.md +8 -1
  2. package/.skills/tc-generator/SKILL.md +3 -2
  3. package/.skills/tc-generator/reference/example.md +1 -1
  4. package/.skills/tc-generator/reference/model-schema.md +18 -0
  5. package/.skills/tc-generator/reference/project-template/index.js +1 -1
  6. package/.skills/tc-generator/reference/runtime-extensions.md +22 -2
  7. package/AGENT_README.md +35 -14
  8. package/README.md +238 -33
  9. package/cjs/app/controller/view.js +1 -1
  10. package/cjs/app/{extend → extends}/db.js +1 -1
  11. package/cjs/app/extends/localCacheHtmlEtag.js +1 -0
  12. package/cjs/app/extends/render-view.js +1 -0
  13. package/cjs/app/middleware.js +1 -1
  14. package/cjs/app/view/entry.tpl +0 -16
  15. package/cjs/bundler/buildFE.js +1 -0
  16. package/cjs/bundler/index.js +1 -1
  17. package/cjs/bundler/state.js +1 -1
  18. package/cjs/bundler/utils.js +3 -3
  19. package/cjs/packages/common/index.js +1 -1
  20. package/cjs/packages/common/rafTimer.js +1 -0
  21. package/cjs/packages/common/string/index.js +1 -1
  22. package/cjs/packages/core/index.js +1 -1
  23. package/cjs/packages/core/loader/controller.js +1 -1
  24. package/cjs/packages/core/loader/extend.js +1 -1
  25. package/cjs/packages/core/loader/middleware.js +1 -1
  26. package/cjs/packages/core/loader/router-schema.js +1 -1
  27. package/cjs/packages/core/loader/router.js +1 -1
  28. package/cjs/packages/core/loader/service.js +1 -1
  29. package/cjs/packages/utils/runFileFn.js +1 -1
  30. package/esm/app/controller/view.js +28 -15
  31. package/esm/app/{extend → extends}/$fetch.js +1 -1
  32. package/esm/app/{extend → extends}/crypto.js +1 -1
  33. package/esm/app/{extend → extends}/db.js +2 -2
  34. package/esm/app/{extend → extends}/generateErrorMessage.js +1 -1
  35. package/esm/app/extends/localCacheHtmlEtag.js +41 -0
  36. package/esm/app/{extend → extends}/logger.js +1 -1
  37. package/esm/app/{extend → extends}/parsingParamsOnUrl.js +1 -1
  38. package/esm/app/extends/render-view.js +18 -0
  39. package/esm/app/middleware.js +8 -12
  40. package/esm/app/view/entry.tpl +0 -16
  41. package/esm/bundler/buildFE.js +14 -0
  42. package/esm/bundler/index.js +2 -14
  43. package/esm/bundler/state.js +5 -1
  44. package/esm/bundler/utils.js +130 -104
  45. package/esm/packages/common/index.js +7 -6
  46. package/esm/packages/common/rafTimer.js +47 -0
  47. package/esm/packages/common/string/index.js +11 -2
  48. package/esm/packages/core/index.js +34 -28
  49. package/esm/packages/core/loader/controller.js +6 -6
  50. package/esm/packages/core/loader/extend.js +6 -6
  51. package/esm/packages/core/loader/middleware.js +6 -6
  52. package/esm/packages/core/loader/router-schema.js +7 -7
  53. package/esm/packages/core/loader/router.js +13 -13
  54. package/esm/packages/core/loader/service.js +6 -6
  55. package/esm/packages/utils/runFileFn.js +10 -10
  56. package/fe/frontend/apps/dash/Dashboard.js +6 -4
  57. package/fe/frontend/apps/dash/dash.entry.js +4 -0
  58. package/fe/frontend/src/common/generateMenuData.d.ts +4 -1
  59. package/fe/frontend/src/common/generateMenuData.js +3 -3
  60. package/fe/frontend/src/common/language.d.ts +12 -1
  61. package/fe/frontend/src/common/language.js +25 -4
  62. package/fe/frontend/src/common/rafTimer.d.ts +1 -0
  63. package/fe/frontend/src/common/rafTimer.js +2 -0
  64. package/fe/frontend/src/common/request.js +1 -0
  65. package/fe/frontend/src/common/theme.d.ts +7 -0
  66. package/fe/frontend/src/common/theme.js +33 -0
  67. package/fe/frontend/src/components/BasePage/HeaderView.js +2 -2
  68. package/fe/frontend/src/components/LanguageSwitch/LanguageSwitch.js +22 -6
  69. package/fe/frontend/src/components/ThemeSwitch/ThemeSwitch.d.ts +3 -2
  70. package/fe/frontend/src/components/ThemeSwitch/ThemeSwitch.js +6 -29
  71. package/fe/frontend/src/components/ThemeSwitch/index.d.ts +1 -0
  72. package/fe/frontend/src/components/ThemeSwitch/index.js +3 -2
  73. package/fe/frontend/src/components/index.js +2 -2
  74. package/fe/frontend/src/defaultPages/NotFoundPage/index.js +4 -3
  75. package/fe/frontend/src/defaultPages/SchemaPage/components/CallCom/DetailPanel.js +14 -9
  76. package/fe/frontend/src/defaultPages/SchemaPage/components/CallCom/PopFrom.js +8 -7
  77. package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaSearch/index.js +20 -24
  78. package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaTable/PreviewImage.d.ts +10 -0
  79. package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaTable/PreviewImage.js +17 -0
  80. package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaTable/data.d.ts +5 -0
  81. package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaTable/data.js +8 -0
  82. package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaTable/index.js +50 -32
  83. package/fe/frontend/src/defaultPages/SchemaPage/index.css +0 -4
  84. package/fe/frontend/src/defaultPages/SchemaPage/index.js +5 -3
  85. package/fe/frontend/src/defaultPages/SlotPage/index.js +6 -3
  86. package/fe/frontend/src/hooks/useText.d.ts +3 -0
  87. package/fe/frontend/src/hooks/useText.js +14 -0
  88. package/fe/frontend/src/index.d.ts +11 -3
  89. package/fe/frontend/src/index.js +8 -3
  90. package/fe/frontend/src/language/index.d.ts +0 -2
  91. package/fe/frontend/src/language/index.js +1 -7
  92. package/fe/frontend/src/language/resources.d.ts +2 -0
  93. package/fe/frontend/src/language/resources.js +9 -0
  94. package/fe/model/types/data/schema.d.ts +24 -2
  95. package/fe/model/types/index.d.ts +1 -0
  96. package/fe/packages/common/i18n/default.js +3 -0
  97. package/fe/packages/common/i18n/en-US.js +5 -2
  98. package/fe/packages/common/i18n/index.js +13 -0
  99. package/fe/packages/common/i18n/locales.js +7 -0
  100. package/fe/packages/common/index.d.ts +1 -0
  101. package/fe/packages/common/rafTimer.d.ts +7 -0
  102. package/fe/packages/common/rafTimer.js +168 -0
  103. package/fe/packages/common/string/index.d.ts +9 -0
  104. package/fe/packages/react/hooks/index.d.ts +9 -0
  105. package/fe/packages/react/hooks/index.js +8 -0
  106. package/fe/packages/react/hooks/useRefState.d.ts +4 -12
  107. package/fe/packages/react/hooks/useRefState.js +18 -8
  108. package/fe/packages/react/ui/components/DataTable/dataTableWidth.d.ts +12 -0
  109. package/fe/packages/react/ui/components/DataTable/dataTableWidth.js +33 -0
  110. package/fe/packages/react/ui/components/DataTable/dataTableWidth.test.js +39 -0
  111. package/fe/packages/react/ui/components/DataTable/index.d.ts +1 -1
  112. package/fe/packages/react/ui/components/DataTable/index.js +12 -32
  113. package/fe/packages/react/ui/components/Textarea/Textarea.d.ts +1 -1
  114. package/fe/packages/react/ui/components/Textarea/Textarea.js +1 -1
  115. package/fe/packages/react/ui/components/types/baseType.d.ts +21 -0
  116. package/fe/packages/react/ui/components/types/baseType.js +0 -0
  117. package/model/frontend/src/common/language.d.ts +12 -1
  118. package/model/frontend/src/hooks/useText.d.ts +3 -0
  119. package/model/frontend/src/language/index.d.ts +0 -2
  120. package/model/frontend/src/language/resources.d.ts +2 -0
  121. package/model/model/types/data/schema.d.ts +24 -2
  122. package/model/model/types/index.d.ts +1 -0
  123. package/model/packages/common/index.d.ts +1 -0
  124. package/model/packages/common/rafTimer.d.ts +7 -0
  125. package/model/packages/common/string/index.d.ts +9 -0
  126. package/model/packages/react/ui/components/DataTable/dataTableWidth.d.ts +12 -0
  127. package/model/packages/react/ui/components/DataTable/index.d.ts +1 -1
  128. package/model/packages/react/ui/components/Textarea/Textarea.d.ts +1 -1
  129. package/model/packages/react/ui/components/types/baseType.d.ts +21 -0
  130. package/package.json +5 -5
  131. package/types/app/extends/localCacheHtmlEtag.d.ts +10 -0
  132. package/types/app/{extend → extends}/render-view.d.ts +1 -1
  133. package/types/app/service/base.d.ts +1 -1
  134. package/types/app/service/project.d.ts +1 -1
  135. package/types/app/type.d.ts +2 -1
  136. package/types/app/typings.d.ts +10 -8
  137. package/types/bundler/buildFE.d.ts +2 -0
  138. package/types/bundler/index.d.ts +1 -2
  139. package/types/bundler/state.d.ts +4 -0
  140. package/types/bundler/utils.d.ts +5 -0
  141. package/types/index.d.ts +3 -3
  142. package/types/packages/common/i18n/default.d.ts +4 -0
  143. package/types/packages/common/i18n/en-US.d.ts +6 -2
  144. package/types/packages/common/i18n/index.d.ts +21 -0
  145. package/types/packages/common/i18n/locales.d.ts +10 -0
  146. package/types/packages/common/i18n/types.d.ts +40 -0
  147. package/types/packages/common/index.d.ts +1 -0
  148. package/types/packages/common/rafTimer.d.ts +44 -0
  149. package/types/packages/common/string/index.d.ts +16 -0
  150. package/types/packages/core/loader/extend.d.ts +1 -1
  151. package/types/packages/core/types.d.ts +4 -0
  152. package/cjs/app/extend/render-view.js +0 -1
  153. package/esm/app/extend/render-view.js +0 -25
  154. /package/cjs/app/{extend → extends}/$fetch.js +0 -0
  155. /package/cjs/app/{extend → extends}/crypto.js +0 -0
  156. /package/cjs/app/{extend → extends}/generateErrorMessage.js +0 -0
  157. /package/cjs/app/{extend → extends}/logger.js +0 -0
  158. /package/cjs/app/{extend → extends}/parsingParamsOnUrl.js +0 -0
  159. /package/types/app/{extend → extends}/$fetch.d.ts +0 -0
  160. /package/types/app/{extend → extends}/crypto.d.ts +0 -0
  161. /package/types/app/{extend → extends}/db.d.ts +0 -0
  162. /package/types/app/{extend → extends}/generateErrorMessage.d.ts +0 -0
  163. /package/types/app/{extend → extends}/logger.d.ts +0 -0
  164. /package/types/app/{extend → extends}/parsingParamsOnUrl.d.ts +0 -0
package/README.md CHANGED
@@ -116,9 +116,9 @@ export default {
116
116
  }
117
117
  ```
118
118
 
119
- `auth.ATKey` / `auth.RTKey` 用于约定业务鉴权中间件读取短 token 和刷新 token 的 header 名;默认分别为 `Authorization` 和 `RT`。
119
+ `auth.ATKey` / `auth.RTKey` 用于约定项目鉴权中间件读取短 token 和刷新 token 的 header 名;默认分别为 `Authorization` 和 `RT`。
120
120
 
121
- 静态资源挂载顺序为:框架 `app/public`、项目 `app/public`、`additionalPublicPaths`。Nunjucks 模板查找顺序为:框架 `app/public/dist`、项目 `app/public/dist`、`additionalPublicPaths`。当 `buildFE` 输出到自定义目录时,可以用 `additionalPublicPaths` 把该目录交给 Koa 提供静态资源访问和模板渲染;如果需要模板查找也命中追加目录,请传绝对路径数组。
121
+ 静态资源挂载顺序为:项目 `app/public`、框架 `app/public`、`additionalPublicPaths`。Nunjucks 模板查找顺序为:项目 `app/public/dist`、框架 `app/public/dist`、`additionalPublicPaths/dist`。这些目录由 `app.publicsPath` 统一维护。当 `buildFE` 输出到自定义目录时,可以用 `additionalPublicPaths` 把该目录交给 Koa 提供静态资源访问和模板渲染;如果需要模板查找也命中追加目录,请传绝对路径数组。
122
122
 
123
123
  ### buildFE 参数说明
124
124
 
@@ -127,7 +127,7 @@ buildFE(mode: 'dev' | 'prod', options?: BuildFEOptions)
127
127
  ```
128
128
 
129
129
  **mode**:构建模式
130
- - `'dev'`:开发模式,构建一次并监听业务 `frontend/` 变化后重建
130
+ - `'dev'`:开发模式,构建一次并监听项目 `frontend/` 变化后重建
131
131
  - `'prod'`:生产模式,构建优化后的静态资源
132
132
 
133
133
  **options.output**:构建输出位置
@@ -135,6 +135,10 @@ buildFE(mode: 'dev' | 'prod', options?: BuildFEOptions)
135
135
  - `'run'`:输出到项目根目录的 `app/public/dist`,适合 TypeScript 编译后的项目
136
136
  - `() => string`:自定义函数,返回输出目录;建议返回绝对路径
137
137
 
138
+ **options.minifyHtml**:是否压缩 Vite 输出的 HTML 内容后再写出最终 `.tpl` / `.html` 文件,默认 `false`
139
+
140
+ 构建完成后会在输出目录写入 `FEBuildKey`。服务端渲染 HTML 时会读取 `public/dist/FEBuildKey`,构建 key 变化后自动清空本地 HTML ETag 缓存。
141
+
138
142
  示例:
139
143
 
140
144
  ```ts
@@ -148,6 +152,9 @@ await buildFE('prod', { output: 'run' })
148
152
  await buildFE('prod', {
149
153
  output: () => join(__dirname, 'dist/public')
150
154
  })
155
+
156
+ // 压缩最终模板输出
157
+ await buildFE('prod', { minifyHtml: true })
151
158
  ```
152
159
 
153
160
  配置文件:
@@ -169,20 +176,23 @@ http://localhost:9000/dash?projk=demo
169
176
 
170
177
  ## 常用公开入口
171
178
 
172
- 完整 exports 以发布包内 `package.json` 为准,除下表外还包含 `./fe/main`、`./fe/*`、`./fe/rc/*`、`./fe/rc/hooks/*` 等子路径。
179
+ 完整 exports 以发布包内 `package.json` 为准,除下表外还包含 `./fe/main`、`./fe/common/request`、`./fe/*`、`./fe/rc/*`、`./fe/rc/hooks` 等子路径。
173
180
 
174
181
  | 入口 | 用途 |
175
182
  | --- | --- |
176
183
  | `@_tc/template-core` | 服务启动、基础 Controller/Service、Koa 类型 |
177
184
  | `@_tc/template-core/bundler` | 构建入口,提供前端资源构建 `buildFE` 和消费方 Node/backend 构建 `buildBE` |
178
- | `@_tc/template-core/fe` | 前端初始化、Dash 路由扩展、请求方法、SchemaPage 事件、共享状态和内置前端组件 |
185
+ | `@_tc/template-core/fe` | 前端初始化、动态组件渲染辅助、Dash 路由扩展、请求方法、SchemaPage 事件、token 工具、共享状态和内置前端组件 |
186
+ | `@_tc/template-core/fe/main` | 前端初始化入口 |
187
+ | `@_tc/template-core/fe/common/request` | 请求实例、请求方法和请求类型的显式子路径 |
179
188
  | `@_tc/template-core/fe/rc` | UI/SchemaForm 组件和类型 |
189
+ | `@_tc/template-core/fe/rc/hooks` | React hooks 汇总入口 |
180
190
  | `@_tc/template-core/fe/tailwind_ui.css` | 前端全局样式入口,源码对应 `frontend/src/main.css` |
181
191
  | `@_tc/template-core/model` | model 配置类型 |
182
192
 
183
193
  ### 后端类型
184
194
 
185
- `@_tc/template-core` 会导出常用 Node 侧类型,业务项目写 `app/*` 文件时建议优先复用这些类型。
195
+ `@_tc/template-core` 会导出常用 Node 侧类型,项目编写 `app/*` 文件时建议优先复用这些类型。
186
196
 
187
197
  | 类型 | 使用场景 |
188
198
  | --- | --- |
@@ -280,7 +290,7 @@ VS Code 建议安装官方 Tailwind CSS IntelliSense 插件,并在工作区 `.
280
290
  ## 内置功能
281
291
 
282
292
  - Koa 服务启动:`serverStart(options)`。
283
- - 约定式加载:自动加载 `config`、`extend`、`router-schema`、`service`、`controller`、`middlewares`、根级 `middleware`、`router`。
293
+ - 约定式加载:自动加载 `config`、`extends`、`router-schema`、`service`、`controller`、`middlewares`、根级 `middleware`、`router`。
284
294
  - 双层 app:框架内置 `app/` 和项目 `app/` 一起加载。
285
295
  - 默认项目接口:
286
296
  - `GET /api/project/model_list`
@@ -292,8 +302,8 @@ VS Code 建议安装官方 Tailwind CSS IntelliSense 插件,并在工作区 `.
292
302
  - Schema CRUD:根据 `model` 中的 `schemaConfig` 生成搜索、表格、新增、编辑、详情。
293
303
  - 内置 UI 组件:提供丰富的 React 组件库,详见下方"内置 UI 组件"章节。
294
304
  - API 中间件:错误处理、静态资源、body parser、项目上下文、接口签名、参数校验。
295
- - 前端构建:扫描框架和项目的 `frontend/**/*.entry.{ts,tsx,js,jsx}`,输出服务端可渲染的 `.entry.tpl` 和对应 `.entry.html`。
296
- - 类型扩展:支持扩展 SchemaForm、CallCom、KoaApp。
305
+ - 前端构建:扫描框架和项目的 `frontend/**/*.entry.{ts,tsx,js,jsx}`,输出服务端可渲染的 `.entry.tpl`,并写入 `FEBuildKey` HTML ETag 缓存失效使用。
306
+ - 类型扩展:支持扩展 SchemaForm、SchemaTable 单元格渲染组件、CallCom、KoaApp。
297
307
 
298
308
  ## 前端公共能力
299
309
 
@@ -303,21 +313,36 @@ VS Code 建议安装官方 Tailwind CSS IntelliSense 插件,并在工作区 `.
303
313
  import {
304
314
  api,
305
315
  apiFreezerStore,
316
+ addLanguageResources,
306
317
  AsyncSelect,
318
+ clearAuthToken,
307
319
  eventsInfo,
320
+ getCurrentLanguage,
321
+ getFallbackLanguage,
308
322
  FreezeState,
309
323
  get,
324
+ getSupportedLanguages,
325
+ getAuthToken,
310
326
  LanguageSwitch,
327
+ localKeyMap,
311
328
  merge,
312
329
  modeStore,
313
330
  post,
331
+ renderImportComponent,
332
+ registerFrontendI18nResources,
314
333
  request,
315
334
  schemaEventBus,
316
335
  schemaStore,
336
+ setFallbackLanguage,
337
+ setLanguage,
338
+ setResources,
339
+ setAuthToken,
317
340
  ThemeSwitch,
341
+ t,
318
342
  useApiFreezer,
319
343
  useModeStore,
320
344
  useSchemaStore,
345
+ useText,
321
346
  } from '@_tc/template-core/fe'
322
347
 
323
348
  import type {
@@ -333,6 +358,8 @@ import type {
333
358
  PageResponse,
334
359
  RequestConfig,
335
360
  ResponseConfig,
361
+ SchemaTableRenderComponent,
362
+ SchemaTableRenderComponentsMap,
336
363
  SchemaFormComponentsMap,
337
364
  SchemaFormNamespace,
338
365
  SelectProps,
@@ -345,30 +372,50 @@ import type {
345
372
  | --- | --- |
346
373
  | 应用启动 | `initApp` |
347
374
  | 内置前端组件 | `AsyncSelect`、`LanguageSwitch`、`ThemeSwitch` |
375
+ | 组件加载辅助 | `renderImportComponent` |
348
376
  | Dash 扩展类型 | `DashRoutesExtender`、`DashRoutesContext`、`DashComponentsMap`、`DashHeaderUserAreaProps`、`DashRouteGuard` |
349
- | SchemaPage 类型 | `CallComComponentsMap`、`CallComRenderer` |
377
+ | SchemaPage 类型 | `CallComComponentsMap`、`CallComRenderer`、`SchemaTableRenderComponent`、`SchemaTableRenderComponentsMap` |
350
378
  | SchemaForm 类型 | `FormFieldSchema`、`SchemaFormComponentsMap`、`SchemaFormNamespace`、`SelectProps` |
351
379
  | 请求方法 | `api`、`request`、`get`、`post`、`put`、`patch`、`del` |
352
380
  | 请求类型 | `BaseResponse`、`PageParams`、`PageResponse`、`RequestConfig`、`ResponseConfig`、`AxiosError` |
381
+ | RAF 风格计时器 | `rafSetTimeout`、`rafSetInterval`、`rafClearTimeout`、`rafClearInterval`、`clearRafTimer`、`RafTimerId`、`RafTimerCallback` |
382
+ | Token 工具 | `getAuthToken`、`setAuthToken`、`clearAuthToken`、`localKeyMap` |
383
+ | 多语言工具 | `useText`、`getText`、`t`、`registerFrontendI18nResources`、`addLanguageResources`、`setLanguage`、`setFallbackLanguage`、`setResources`、`getCurrentLanguage`、`getFallbackLanguage`、`getSupportedLanguages` |
353
384
  | 请求冻结 | `apiFreezerStore`、`useApiFreezer`、`FreezeState`、`ApiFreezerRequestMatcher` |
354
385
  | 事件工具 | `eventsInfo`、`merge` |
355
386
  | 共享状态 | `modeStore`、`useModeStore`、`schemaStore`、`useSchemaStore`、`schemaEventBus` |
356
387
 
357
388
  `modeStore` 管项目模型和当前项目数据,`schemaStore` 管当前 Schema 页面的 schema/cache,`schemaEventBus` 用来在 Search、Table、CallCom 之间通信。
358
389
 
390
+ `renderImportComponent` 封装了 `React.lazy` + `Suspense`,默认会用页面骨架屏作为 fallback。`getAuthToken()`、`setAuthToken()` 和 `clearAuthToken()` 用于读写或清理本地短 token,`localKeyMap` 暴露对应的本地存储 key 常量。
391
+
359
392
  只使用请求层时,也可以从 `@_tc/template-core/fe/common/request` 导入 `api`、请求方法和请求类型;这是发布包显式子路径,不要下钻到 `frontend/src/common/request`。
360
393
 
361
394
  ### 前端多语言
362
395
 
363
- TemplateCore 前端通过 `@_tc/template-core/fe` 暴露 i18n 能力。框架内置中文、英文资源,项目可以继续追加自己的资源。
396
+ TemplateCore 前端通过 `@_tc/template-core/fe` 暴露 i18n 能力。框架内置中文、英文资源,但不会在普通自定义页面 import 前端入口时自动注册,避免非 Dashboard 页面把框架文案整包带入运行时资源。
397
+
398
+ 默认 Dashboard 入口会自动调用 `registerFrontendI18nResources()`,所以 Dashboard、Schema CRUD、内置页头、语言切换等框架页面可以直接使用框架内置文案。自定义入口如果也要复用这些框架文案,需要在渲染前手动注册:
399
+
400
+ ```ts
401
+ import { initApp, registerFrontendI18nResources } from '@_tc/template-core/fe'
402
+
403
+ initApp(App, {
404
+ beforeRender: async () => {
405
+ await registerFrontendI18nResources()
406
+ },
407
+ })
408
+ ```
409
+
410
+ 项目可以继续追加自己的资源或新增语种。
364
411
 
365
412
  **追加自定义语言资源**:
366
413
 
367
414
  ```ts
368
- import { i18nStore } from '@_tc/template-core/fe'
415
+ import { addLanguageResources } from '@_tc/template-core/fe'
369
416
 
370
- i18nStore.getState().addResources('zh-CN', {
371
- business: {
417
+ addLanguageResources('zh-CN', {
418
+ app: {
372
419
  product: {
373
420
  menu: '商品管理',
374
421
  name: '商品名称',
@@ -378,8 +425,8 @@ i18nStore.getState().addResources('zh-CN', {
378
425
  },
379
426
  })
380
427
 
381
- i18nStore.getState().addResources('en-US', {
382
- business: {
428
+ addLanguageResources('en-US', {
429
+ app: {
383
430
  product: {
384
431
  menu: 'Products',
385
432
  name: 'Product name',
@@ -390,17 +437,49 @@ i18nStore.getState().addResources('en-US', {
390
437
  })
391
438
  ```
392
439
 
440
+ **新增语种并切换**:
441
+
442
+ ```ts
443
+ import { addLanguageResources, setLanguage } from '@_tc/template-core/fe'
444
+
445
+ addLanguageResources('ja-JP', {
446
+ app: {
447
+ product: {
448
+ menu: '商品管理',
449
+ },
450
+ },
451
+ })
452
+
453
+ setLanguage('ja-JP')
454
+ ```
455
+
456
+ `addLanguageResources()` 用于追加或新增某个语种的文案,默认会深合并同语种资源;传 `{ merge: false }` 可以替换该语种资源。`setResources(resources, { merge: true })` 可批量合并多语种资源。`LanguageSwitch` 默认会把已注册语种加入选项;需要自定义展示文案时仍可传入 `options`。
457
+
458
+ React 组件 render 中使用 `useText()` 读取文案。它会订阅语言和资源变化,调用 `setLanguage()` 后组件会自动重渲染:
459
+
460
+ ```tsx
461
+ import { useText } from '@_tc/template-core/fe'
462
+
463
+ function ProductTitle() {
464
+ const text = useText()
465
+
466
+ return <h1>{text('$i18n::app.product.menu')}</h1>
467
+ }
468
+ ```
469
+
470
+ `getText()` 是普通函数,适合请求错误、日志、校验工具或事件回调等非 React 场景;它不会主动触发 React 组件重渲染。
471
+
393
472
  资源注册时不写 `$i18n::` 前缀,配置中使用时才写:
394
473
 
395
474
  ```ts
396
- const title = '$i18n::business.product.createTitle'
475
+ const title = '$i18n::app.product.createTitle'
397
476
  ```
398
477
 
399
478
  **在 model / Schema 配置中使用**:
400
479
 
401
480
  ```ts
402
481
  {
403
- name: '$i18n::business.product.menu',
482
+ name: '$i18n::app.product.menu',
404
483
  moduleType: 'schema',
405
484
  schemaConfig: {
406
485
  schema: {
@@ -408,7 +487,7 @@ const title = '$i18n::business.product.createTitle'
408
487
  properties: {
409
488
  name: {
410
489
  type: 'string',
411
- label: '$i18n::business.product.name',
490
+ label: '$i18n::app.product.name',
412
491
  minLength: 2,
413
492
  createFormOption: {
414
493
  comType: 'input',
@@ -422,7 +501,7 @@ const title = '$i18n::business.product.createTitle'
422
501
  tableConfig: {
423
502
  headerButtons: [
424
503
  {
425
- label: '$i18n::business.product.create',
504
+ label: '$i18n::app.product.create',
426
505
  eventKey: 'callComponent',
427
506
  eventOption: { comName: 'createForm' },
428
507
  },
@@ -430,7 +509,7 @@ const title = '$i18n::business.product.createTitle'
430
509
  },
431
510
  componentConfig: {
432
511
  createForm: {
433
- title: '$i18n::business.product.createTitle',
512
+ title: '$i18n::app.product.createTitle',
434
513
  saveBtnText: '$i18n::common.submit',
435
514
  },
436
515
  },
@@ -469,7 +548,7 @@ export function Toolbar() {
469
548
  }
470
549
  ```
471
550
 
472
- `LanguageSwitch` 默认提供 `zh-CN` 和 `en-US`,也支持传入 `options` 覆盖语言列表。组件内部会调用 `i18nStore.getState().setLanguage()`,因此会沿用 `tc_language` 的持久化行为。
551
+ `LanguageSwitch` 默认提供 `zh-CN` 和 `en-US`,也支持传入 `options` 覆盖语言列表。组件当前是按钮 + 下拉菜单形态,`option.label` 支持 ReactNode,`buttonClassName` 可自定义触发按钮样式。组件内部会调用 `i18nStore.getState().setLanguage()`,因此会沿用 `tc_language` 的持久化行为。
473
552
 
474
553
  **AJV 校验文案**:
475
554
 
@@ -495,7 +574,7 @@ export function Toolbar() {
495
574
  }
496
575
  ```
497
576
 
498
- `ThemeSwitch` 会切换 `document.documentElement` 上的 `dark` class,并同步 `color-scheme`。默认写入 localStorage,key 是 `tc_theme`。刷新页面后会优先读取本地主题;没有本地主题时,读取当前根节点是否已有 `dark` class
577
+ `ThemeSwitch` 会切换 `document.documentElement` 上的 `dark` class,并同步 `color-scheme`。默认写入 localStorage,key 是 `tc_theme`。刷新页面后会优先读取本地主题;没有本地主题时,读取当前根节点是否已有 `dark` class。默认 Dashboard 会在渲染前调用 `initThemeMode()`,让已保存主题尽早生效。
499
578
 
500
579
  常用参数:
501
580
 
@@ -507,6 +586,21 @@ export function Toolbar() {
507
586
  | `persist` | 是否写入 localStorage,默认 `true`。 |
508
587
  | `storageKey` | 自定义本地存储 key,默认 `tc_theme`。 |
509
588
 
589
+ 如需在自定义入口或组件外手动初始化/切换主题,可以从 `@_tc/template-core/fe` 导入主题工具:
590
+
591
+ ```ts
592
+ import { applyThemeMode, getCurrentThemeMode, initThemeMode, themeSwitchStorageKey } from '@_tc/template-core/fe'
593
+
594
+ initThemeMode()
595
+ applyThemeMode('dark', true)
596
+ ```
597
+
598
+ RAF 风格计时器由 `@tc/common/rafTimer` 提供,浏览器优先使用 `requestAnimationFrame`,缺少 RAF 时自动降级到 `setTimeout`。
599
+
600
+ `@_tc/template-core/fe/rc` 和 `@_tc/template-core/fe/rc/hooks` 也会随发布包提供对应 UI 与 hooks 入口;hooks 汇总入口包含 `useBreadcrumb`、`useExecuteOnce`、`useInit`、`useLanguage`、`usePagination`、`useRefState`、`useWatch`。
601
+
602
+ `useRefState` 支持可选的 `delayTiming` 参数,传入大于 0 的值时会延迟 state 提交,并复用 `@tc/common/rafTimer` 的浏览器优先、Node/SSR 自动降级计时器实现。
603
+
510
604
  ### 前端请求封装详解
511
605
 
512
606
  框架内置的请求封装基于 `@tc/common/http`,底层使用原生 `fetch` API,实现了类似 Axios 的接口和拦截器机制,提供了签名、鉴权、错误处理等能力。
@@ -516,6 +610,7 @@ export function Toolbar() {
516
610
  - `timeout`:15000ms(15秒)
517
611
  - `credentials`:`'include'`,支持跨域携带 cookie
518
612
  - `window._signKey`:由服务端页面模板从 `app.config.signKey` 注入
613
+ - 默认会先设置 `Content-Type: application/json`;如果是上传文件、`FormData` 或其他内容类型,请在请求配置里显式覆盖
519
614
 
520
615
  **请求拦截器**:
521
616
 
@@ -738,7 +833,7 @@ app/middlewares/**/*.(js|ts) -> app.middlewares
738
833
  app/middleware.(js|ts) -> 全局中间件编排,按框架 -> 项目顺序执行
739
834
  app/router/**/*.(js|ts) -> Koa router
740
835
  app/router-schema/**/*.(js|ts) -> app.routerSchema
741
- app/extend/*.(js|ts) -> app.extends
836
+ app/extends/*.(js|ts) -> app.extends
742
837
  config/config.default.(js|ts) -> app.config
743
838
  config/config.{env}.(js|ts) -> app.config
744
839
  model/**/*.(js|ts) -> 内置 project service 按需读取的项目模型配置
@@ -872,10 +967,10 @@ const unsafeUsers = app.extends.db.queryDB(
872
967
  )
873
968
  ```
874
969
 
875
- 业务项目可以用自己的 `app/extend/db.ts` 覆盖默认实现。建议保留同一组方法名,这样 controller/service 调用方不用调整。
970
+ 项目可以用自己的 `app/extends/db.ts` 覆盖默认实现。建议保留同一组方法名,这样 controller/service 调用方不用调整。
876
971
 
877
972
  ```ts
878
- // app/extend/db.ts
973
+ // app/extends/db.ts
879
974
  import type { DB, DBFactory } from '@_tc/template-core'
880
975
 
881
976
  interface DataOptions {
@@ -988,7 +1083,7 @@ export default (app: KoaApp, router: Router) => {
988
1083
  - 每个 `app/router/*.ts` 文件都会获得独立的 `koa-router` 实例。
989
1084
  - 可以通过 `router.level = number` 控制挂载顺序,数值越小越早挂载。
990
1085
  - 默认 `level` 是 `0`,框架兜底 router 是 `99`。
991
- - 通配、兜底、重定向类路由建议设置较大的 `level`,避免抢先匹配业务 API。
1086
+ - 通配、兜底、重定向类路由建议设置较大的 `level`,避免抢先匹配项目 API。
992
1087
 
993
1088
  ```ts
994
1089
  import type { KoaApp, Router } from '@_tc/template-core'
@@ -1277,7 +1372,7 @@ DELETE {api} -> 删除
1277
1372
 
1278
1373
  ### 服务端兜底路由守卫
1279
1374
 
1280
- 业务项目可以创建 `app/router-guard.ts` 或 `app/router-guard.js`。它只在所有正常 `app/router/*` 路由都没有命中时执行。
1375
+ 项目可以创建 `app/router-guard.ts` 或 `app/router-guard.js`。它只在所有正常 `app/router/*` 路由都没有命中时执行。
1281
1376
 
1282
1377
  ```ts
1283
1378
  import type { Ctx, KoaApp } from '@_tc/template-core'
@@ -1302,7 +1397,7 @@ export default (_app: KoaApp) => {
1302
1397
 
1303
1398
  ### 扩展 Dashboard 顶部用户区域
1304
1399
 
1305
- 业务项目可以创建 `frontend/extended/dash/components.tsx`,通过组件映射填充内置 Dashboard 页头右侧区域。
1400
+ 项目可以创建 `frontend/extended/dash/components.tsx`,通过组件映射填充内置 Dashboard 页头右侧区域。
1306
1401
 
1307
1402
  ```tsx
1308
1403
  // frontend/extended/dash/components.tsx
@@ -1323,7 +1418,7 @@ export default components
1323
1418
 
1324
1419
  ### 扩展 Dashboard 登录守卫
1325
1420
 
1326
- 业务项目可以创建 `frontend/extended/dash/routeGuard.ts`,用于在 Dashboard 内置 `homePage` / 首菜单重定向前做登录判断。
1421
+ 项目可以创建 `frontend/extended/dash/routeGuard.ts`,用于在 Dashboard 内置 `homePage` / 首菜单重定向前做登录判断。
1327
1422
 
1328
1423
  ```ts
1329
1424
  // frontend/extended/dash/routeGuard.ts
@@ -1339,9 +1434,9 @@ export default dashRouteGuard
1339
1434
  返回值规则:
1340
1435
 
1341
1436
  - 返回 `string`:框架使用 `window.location.href` 跳转,登录页不需要在 Dash 路由下。
1342
- - 返回非 `string`:中断 Dashboard 内置重定向,业务方可自行跳转或处理提示。
1437
+ - 返回非 `string`:中断 Dashboard 内置重定向,使用方可自行跳转或处理提示。
1343
1438
  - `DashRouteGuardResult` 是 `string | undefined`;`undefined`(包括已登录分支的隐式返回)也会打断 Dashboard 内置重定向。
1344
- - 没有业务 `routeGuard` 文件时,框架使用兜底空对象,不影响默认 Dashboard 重定向。
1439
+ - 没有自定义 `routeGuard` 文件时,框架使用兜底空对象,不影响默认 Dashboard 重定向。
1345
1440
 
1346
1441
  ### 扩展 SchemaForm 字段组件
1347
1442
 
@@ -1511,6 +1606,90 @@ remark: {
1511
1606
  }
1512
1607
  ```
1513
1608
 
1609
+ ### 扩展 SchemaTable 单元格渲染组件
1610
+
1611
+ SchemaPage 表格列支持通过 `tableOption.renderComponent` 使用内置或自定义注册的渲染组件。内置组件:
1612
+
1613
+ - `PreviewImage`:把当前单元格值渲染成图片预览;值是数组时直接作为图片列表,值是单个字符串时自动转成单图数组。
1614
+
1615
+ 直接使用内置组件:
1616
+
1617
+ ```ts
1618
+ cover: {
1619
+ type: 'string',
1620
+ label: '封面',
1621
+ tableOption: {
1622
+ renderComponent: 'PreviewImage',
1623
+ renderComponentProps: {
1624
+ width: 48,
1625
+ height: 48,
1626
+ },
1627
+ },
1628
+ }
1629
+ ```
1630
+
1631
+ 自定义渲染组件时,先声明 props 类型:
1632
+
1633
+ ```ts
1634
+ // typing/template-core.d.ts
1635
+ import '@_tc/template-core/model'
1636
+
1637
+ declare module '@_tc/template-core/model' {
1638
+ export namespace SchemaTableNamespace {
1639
+ interface RenderComponentPropsMap {
1640
+ PriceCell: {
1641
+ value?: unknown
1642
+ record?: Record<string, unknown>
1643
+ rowIndex?: number
1644
+ fieldKey?: string
1645
+ currency?: string
1646
+ }
1647
+ }
1648
+ }
1649
+ }
1650
+ ```
1651
+
1652
+ 注册运行时组件:
1653
+
1654
+ ```ts
1655
+ // frontend/extended/SchemaPage/SchemaTable/data.ts
1656
+ import { lazy } from 'react'
1657
+ import type { SchemaTableRenderComponentsMap } from '@_tc/template-core/fe'
1658
+
1659
+ const componentsMap = {
1660
+ PriceCell: lazy(() => import('../../components/PriceCell')),
1661
+ } satisfies SchemaTableRenderComponentsMap
1662
+
1663
+ export default componentsMap
1664
+ ```
1665
+
1666
+ 组件会收到 `value`、`record`、`rowIndex`、`fieldKey`,以及 `renderComponentProps` 中的自定义参数:
1667
+
1668
+ ```tsx
1669
+ // frontend/components/PriceCell.tsx
1670
+ export default function PriceCell(props: {
1671
+ value?: unknown
1672
+ currency?: string
1673
+ }) {
1674
+ return <span>{props.currency ?? '¥'}{Number(props.value ?? 0).toFixed(2)}</span>
1675
+ }
1676
+ ```
1677
+
1678
+ model 中使用:
1679
+
1680
+ ```ts
1681
+ price: {
1682
+ type: 'number',
1683
+ label: '价格',
1684
+ tableOption: {
1685
+ renderComponent: 'PriceCell',
1686
+ renderComponentProps: {
1687
+ currency: '¥',
1688
+ },
1689
+ },
1690
+ }
1691
+ ```
1692
+
1514
1693
  ## 如何配置类型扩展
1515
1694
 
1516
1695
  ### tsconfig
@@ -1610,6 +1789,22 @@ declare module '@_tc/template-core/model' {
1610
1789
  - `OptionMap` 对应字段上的 `xxxOption`。
1611
1790
  - 运行时组件注册在 `frontend/extended/SchemaPage/CallCom/data.ts`。
1612
1791
 
1792
+ ### SchemaTable 渲染组件类型扩展
1793
+
1794
+ 扩展目标:
1795
+
1796
+ ```ts
1797
+ declare module '@_tc/template-core/model' {
1798
+ export namespace SchemaTableNamespace {
1799
+ interface RenderComponentPropsMap {}
1800
+ }
1801
+ }
1802
+ ```
1803
+
1804
+ - `RenderComponentPropsMap` 的 key 对应 `tableOption.renderComponent`。
1805
+ - 运行时组件注册在 `frontend/extended/SchemaPage/SchemaTable/data.ts`。
1806
+ - 组件运行时会自动收到 `value`、`record`、`rowIndex`、`fieldKey`;`renderComponentProps` 只配置自定义参数。
1807
+
1613
1808
  ### KoaApp 类型扩展
1614
1809
 
1615
1810
  使用方推荐增强根包 `@_tc/template-core`:
@@ -1792,6 +1987,16 @@ await buildFE('prod', {
1792
1987
  })
1793
1988
  ```
1794
1989
 
1990
+ 也可以压缩最终模板输出:
1991
+
1992
+ ```ts
1993
+ await buildFE('prod', {
1994
+ minifyHtml: true,
1995
+ })
1996
+ ```
1997
+
1998
+ 构建完成后会在输出目录写入 `FEBuildKey`,服务端渲染 HTML 时会用它判断本地 HTML ETag 缓存是否需要清空。
1999
+
1795
2000
  ## Node/backend 构建 buildBE
1796
2001
 
1797
2002
  消费方 Node/backend 侧构建使用 `buildBE()`。它复用发布包内的 `scripts/vite-build/buildEntries`,只是提供消费方默认配置。
@@ -1953,6 +2158,6 @@ await buildBE({
1953
2158
  - `model` 数组合并依赖稳定 `key`。
1954
2159
  - Dashboard 默认需要 URL 带 `?projk=项目key`。
1955
2160
  - Dashboard 登录守卫放在 `frontend/extended/dash/routeGuard.ts`;登录页通常不在 Dash 路由下,返回登录页 URL 即可。
1956
- - 服务端兜底守卫放在业务 `app/router-guard.ts|js`,不是 `app/business` 子目录。
2161
+ - 服务端兜底守卫放在项目根目录的 `app/router-guard.ts|js`。
1957
2162
  - 前端入口必须命名为 `.entry.tsx`、`.entry.ts`、`.entry.jsx` 或 `.entry.js`。
1958
2163
  - 入口同目录的 `.html` 只能作为插槽文件使用,不能写完整 HTML 文档;页面外壳始终由 `app/view/entry.tpl` 生成。
@@ -1 +1 @@
1
- var e=e=>JSON.stringify(e).replace(/</g,`\\u003c`).replace(/>/g,`\\u003e`).replace(/&/g,`\\u0026`).replace(/\u2028/g,`\\u2028`).replace(/\u2029/g,`\\u2029`),t=(t=>class{async renderPage(n,r){if(n.path.includes(`${t.options.apiPrefix}/`))await r();else{t.extends.logger.log(` - render page: `+n.params.page);try{t.extends.renderView(`${n.params.page}.entry.tpl`,n,{projKey:n.query.projk,name:t.options?.name,env:t.envs.get(),basePath:e(`${t.options.pageBasePage}${n.params.page}`),projKeyJson:e(String(n.query.projk??``)),signKey:e(t.config.signKey),options:e(t.options)})}catch(e){console.log(`-------------- render view error --------------`),console.log(e),t.extends.generateErrorMessage(`template not found`,{status:404,showError:!0,code:0})}}}});module.exports=t;
1
+ const e=require(`../../packages/common/string/index.js`);var t=e=>JSON.stringify(e).replace(/</g,`\\u003c`).replace(/>/g,`\\u003e`).replace(/&/g,`\\u0026`).replace(/\u2028/g,`\\u2028`).replace(/\u2029/g,`\\u2029`),n=(n=>class{async renderPage(r,i){let a=r.path;if(n.extends.localCacheHtmlEtag.keepFreshFEBuildKey(),a.includes(`${n.options.apiPrefix}/`))await i();else{n.extends.logger.log(` - render page: `+r.params.page);try{let i=r.query.projk;Array.isArray(i)&&(i=e.joinStr(...i));let a={projKey:i??``,name:n.options?.name??``,env:n.envs.get(),basePath:t(`${n.options.pageBasePage}${r.params.page}`),projKeyJson:t(String(r.query.projk??``)),signKey:t(n.config.signKey),options:t(n.options)},o=n.extends.renderView(`${r.params.page}.entry.tpl`,r,a),s=e.joinStr(a.basePath,a.name,a.env,a.projKey);if(!n.extends.localCacheHtmlEtag.hasEtag(s)){let e=n.extends.crypto.hmacSign(o);n.extends.localCacheHtmlEtag.setEtag(s,e)}let c=n.extends.localCacheHtmlEtag.getEtag(s);if(c||console.log(`---- etag 缓存异常 请检查服务 ----`),r.etag=c??Date.now()+``,r.fresh){r.status=304;return}}catch(e){console.log(`-------------- render view error --------------`),console.log(e),n.extends.generateErrorMessage(`template not found`,{status:404,showError:!0,code:0})}}}});module.exports=n;
@@ -6,7 +6,7 @@ require(`../../_virtual/_rolldown/runtime.js`);let e=require(`node:fs`),t=requir
6
6
  FROM tc_framework_data
7
7
  WHERE namespace = ?
8
8
  ORDER BY updated_at DESC, data_key ASC
9
- LIMIT ? OFFSET ?`,[d(e?.namespace),t,n]).map(e=>_(e))},countDBData:e=>{let t=y.getDBFirst(`SELECT COUNT(1) AS count_value FROM tc_framework_data WHERE namespace = ?`,[d(e?.namespace)]);return Number(t?.count_value??0)},clearDBData:e=>y.runDB(`DELETE FROM tc_framework_data WHERE namespace = ?`,[d(e?.namespace)]).changes,closeDB:()=>{c||=(i?.close(),!0)}};return y}function a(e){let t=`node:sqlite`,n;try{n=require(t)}catch(e){throw Error(`[db] 默认数据库依赖 Node.js 内置 ${t},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extend/db.ts。${y(e)}`)}if(!n.DatabaseSync)throw Error(`[db] ${t} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。`);return new n.DatabaseSync(e)}function o(e){e.exec(`
9
+ LIMIT ? OFFSET ?`,[d(e?.namespace),t,n]).map(e=>_(e))},countDBData:e=>{let t=y.getDBFirst(`SELECT COUNT(1) AS count_value FROM tc_framework_data WHERE namespace = ?`,[d(e?.namespace)]);return Number(t?.count_value??0)},clearDBData:e=>y.runDB(`DELETE FROM tc_framework_data WHERE namespace = ?`,[d(e?.namespace)]).changes,closeDB:()=>{c||=(i?.close(),!0)}};return y}function a(e){let t=`node:sqlite`,n;try{n=require(t)}catch(e){throw Error(`[db] 默认数据库依赖 Node.js 内置 ${t},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。${y(e)}`)}if(!n.DatabaseSync)throw Error(`[db] ${t} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。`);return new n.DatabaseSync(e)}function o(e){e.exec(`
10
10
  CREATE TABLE IF NOT EXISTS tc_framework_data (
11
11
  namespace TEXT NOT NULL,
12
12
  data_key TEXT NOT NULL,
@@ -0,0 +1 @@
1
+ const e=require(`../../_virtual/_rolldown/runtime.js`);let t=require(`fs`),n=require(`path`);n=e.__toESM(n);var r=`./dist/FEBuildKey`,i={etags:{},FEBuildKey:null},a=(e=>{let a=(e,t)=>{i.etags[e]=t},o=e=>!!s(e),s=e=>i.etags[e]||null,c=e=>{i.FEBuildKey=e},l=()=>i.FEBuildKey||null,u=()=>{for(let i of e.publicsPath){let e=n.default.resolve(i,r);if((0,t.existsSync)(e))return e}},d=()=>{let e,n=u();return n&&(e=(0,t.readFileSync)(n,`utf-8`)),e===l()};return{keepFreshFEBuildKey:()=>{if(!d()){let e=u();if(e){let n=(0,t.readFileSync)(e,`utf-8`);if(n){c(n),i.etags={};return}}console.log(`--- 没找到前端构建key文件 ---`),console.log(`--- filePath --- -> `,e)}},hasEtag:o,getEtag:s,setEtag:a}});module.exports=a;
@@ -0,0 +1 @@
1
+ const e=require(`../../_virtual/_rolldown/runtime.js`);let t=require(`node:path`);t=e.__toESM(t);let n=require(`nunjucks`);n=e.__toESM(n);var r=e=>{let r=e.publicsPath.map(e=>t.default.resolve(e,`./dist`));console.log(r);let i=n.default.configure(r,{autoescape:!0,throwOnUndefined:!1,trimBlocks:!1,lstripBlocks:!1,noCache:e.envs.get()===`local`,...typeof e.config.nunjucks==`object`?e.config.nunjucks:{}});return e.extends.nunjucksEnv=i,(e,t,n)=>t.body=i.render(e,Object.assign({},t.state,n))};module.exports=r;
@@ -1 +1 @@
1
- const e=require(`../_virtual/_rolldown/runtime.js`),t=require(`../packages/core/paths.js`);let n=require(`koa-compress`);n=e.__toESM(n);let r=require(`path`),i=require(`koa-bodyparser`);i=e.__toESM(i);let a=require(`koa-static`);a=e.__toESM(a);var o=(0,i.default)({formLimit:`1000mb`,enableTypes:[`form`,`json`,`text`]}),s=e=>{let i=e.envs.isLocal()?{maxage:0,setHeaders(e){e.setHeader(`Cache-Control`,`no-store, no-cache, must-revalidate, proxy-revalidate`),e.setHeader(`Pragma`,`no-cache`),e.setHeader(`Expires`,`0`)}}:{maxage:365*24*60*60*1e3};e.use(e.middlewares.errorHandle),e.use((0,n.default)({threshold:2048}));let s=(0,r.resolve)(t.getAppPath(e,`business`),`./public`),c=(0,r.resolve)(t.getAppPath(e,`frame`),`./public`),l=e.options.additionalPublicPaths??[];l=Array.isArray(l)?l:[l],e.use((0,a.default)(c,i)),e.use((0,a.default)(s,i)),l.forEach(t=>e.use((0,a.default)(t,i))),e.use(o),e.use(e.middlewares.requestParameterParsing),e.use(e.middlewares.projectHandler),!e.envs.isLocal()&&e.use(e.middlewares.apiSignVerify),e.use(e.middlewares.apiParamsVerify)};module.exports=s;
1
+ const e=require(`../_virtual/_rolldown/runtime.js`);let t=require(`koa-compress`);t=e.__toESM(t);let n=require(`koa-bodyparser`);n=e.__toESM(n);let r=require(`koa-static`);r=e.__toESM(r);var i=(0,n.default)({formLimit:`1000mb`,enableTypes:[`form`,`json`,`text`]}),a=e=>{let n=e.envs.isLocal()?{maxage:0,setHeaders(e){e.setHeader(`Cache-Control`,`no-store, no-cache, must-revalidate, proxy-revalidate`),e.setHeader(`Pragma`,`no-cache`),e.setHeader(`Expires`,`0`)}}:{maxage:365*24*60*60*1e3};e.use(e.middlewares.errorHandle),e.use((0,t.default)({threshold:2048})),e.publicsPath.forEach(t=>e.use((0,r.default)(t,n))),e.use(i),e.use(e.middlewares.requestParameterParsing),e.use(e.middlewares.projectHandler),!e.envs.isLocal()&&e.use(e.middlewares.apiSignVerify),e.use(e.middlewares.apiParamsVerify)};module.exports=a;
@@ -3,22 +3,6 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <script>
7
- ;(() => {
8
- const root = document.documentElement
9
- let theme = root.classList.contains('dark') ? 'dark' : 'light'
10
-
11
- try {
12
- const storedTheme = window.localStorage.getItem('tc_theme')
13
- if (storedTheme === 'light' || storedTheme === 'dark') {
14
- theme = storedTheme
15
- }
16
- } catch (_error) {}
17
-
18
- root.classList.toggle('dark', theme === 'dark')
19
- root.style.colorScheme = theme
20
- })()
21
- </script>
22
6
  <link rel="icon" type="image/x-icon" href="/static/logo.png" />
23
7
  <title>{{ name }}</title>
24
8
  <!-- TC_HEAD_SLOT -->
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../packages/common/log/index.js`),t=require(`./state.js`),n=require(`./dev.js`),r=require(`./prod.js`);var i=(i,a)=>{switch(t.setBuildFEOptions(a),i){case`dev`:return n.dev();case`prod`:return r.prod();default:return e.logRed(`Usage: npx tsx scripts/index.ts [dev|prod]`),Promise.resolve()}};exports.buildFE=i;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./buildBE.js`),t=require(`../packages/common/log/index.js`),n=require(`./state.js`),r=require(`./dev.js`),i=require(`./prod.js`);var a=(e,a)=>{switch(n.setBuildFEOptions(a),e){case`dev`:return r.dev();case`prod`:return i.prod();default:return t.logRed(`Usage: npx tsx scripts/index.ts [dev|prod]`),Promise.resolve()}};exports.buildBE=e.buildBE,exports.buildFE=a;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./buildBE.js`),t=require(`./buildFE.js`);exports.buildBE=e.buildBE,exports.buildFE=t.buildFE;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={options:{output:`frame`}};function t(t){e.options={output:`frame`,...t}}exports.buildFESharedState=e,exports.setBuildFEOptions=t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={options:{output:`frame`,minifyHtml:!1}};function t(t){e.options={output:`frame`,minifyHtml:!1,...t}}exports.buildFESharedState=e,exports.setBuildFEOptions=t;
@@ -1,3 +1,3 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../_virtual/_rolldown/runtime.js`),t=require(`../packages/utils/path.js`);require(`../packages/utils/index.js`);const n=require(`../packages/common/log/index.js`),r=require(`./state.js`);let i=require(`path`);i=e.__toESM(i);let a=require(`glob`);a=e.__toESM(a);let o=require(`fs`),s=require(`vite`),c=require(`@tailwindcss/vite`);c=e.__toESM(c);let l=require(`module`),u=require(`url`);var d=typeof __filename==`string`?__filename:(0,u.fileURLToPath)({}.url),f=i.default.dirname(d),p=process.cwd(),m=(0,l.createRequire)(d),h=i.default.resolve(f,`../../`),g=i.default.resolve(f,`../`),_=i.default.resolve(h,`./fe/frontend`),v=i.default.resolve(p,`.`),y=i.default.resolve(v,`./frontend`),b=e=>i.default.dirname(m.resolve(`${e}/package.json`)),x=i.default.join(v,`.tc-entry-html`),S=`<!-- {{InsertScript}} -->`,C={head:`<!-- TC_HEAD_SLOT -->`,bodyBeforeRoot:`<!-- TC_BODY_BEFORE_ROOT_SLOT -->`,bodyAfterRoot:`<!-- TC_BODY_AFTER_ROOT_SLOT -->`},w=[`head`,`body-before-root`,`body-after-root`],T=()=>({head:``,"body-before-root":``,"body-after-root":``}),E=e=>e.split(i.default.sep).join(`/`),D=e=>{let t=E(e);return t.startsWith(`.`)||t.startsWith(`/`)?t:`./${t}`},O=e=>/<html[\s>]/i.test(e)&&e.includes(`window['_basePath']`)&&/<div\s+id=["']root["']\s*><\/div>/i.test(e),k=e=>{let t=T(),r=(0,o.readFileSync)(e,`utf-8`),i=/<!--\s*tc-slot:([\w-]+)\s*-->([\s\S]*?)<!--\s*\/tc-slot:\1\s*-->/g,a=!1,s=r;if(r.replace(i,(n,r,i)=>{if(a=!0,!w.includes(r))throw Error(`Invalid html slot "${r}" in ${e}. Allowed slots: ${w.join(`, `)}.`);return t[r]+=i.trim()?`${i}\n`:``,s=s.replace(n,``),n}),s.trim()){if(O(r))return n.logYellow(`ignored legacy generated entry html: ${e}`),T();throw Error([`Invalid custom entry html: ${e}.`,`Custom entry html can only contain tc-slot blocks, for example:`,`<!-- tc-slot:head -->`,`<meta name="description" content="..." />`,`<!-- /tc-slot:head -->`].join(`
2
- `))}return a&&n.logYellow(`using custom entry html slots: ${e}`),t},A=(e,n)=>{let r=i.default.basename(e),s=[i.default.join(e,`${n}.html`),i.default.join(e,`${r}.html`)].find(e=>(0,o.existsSync)(e));if(s)return s;if(a.sync(t.resolve(e,`*.html`)).length)throw Error([`Entry html filename is not supported in ${e}.`,`Use ${n}.html or ${r}.html as a tc-slot file.`].join(`
3
- `))},j=(e,t)=>e.replace(C.head,t.head).replace(C.bodyBeforeRoot,t[`body-before-root`]).replace(C.bodyAfterRoot,t[`body-after-root`]),M=(e,t,n,r)=>{let a=i.default.join(x,`${n}.html`),s=D(i.default.relative(i.default.dirname(a),t));return(0,o.writeFileSync)(a,j(e,r).replace(S,`<script type="module" src="${s}"><\/script>`)),a};function N(){n.logWhite(`frameFEPath: `+_),n.logWhite(`runFEPath: `+y);let e=[_,y].reduce((e,n)=>{let r=[`js`,`jsx`,`ts`,`tsx`].map(e=>t.resolve(n,`/**`,`/*.`+e)),i=a.sync(r).filter(e=>e.includes(`.entry.`)).filter(e=>!e.includes(`.d.ts`));return[...e,...i]},[]),r={};if(!e.length)return r;(0,o.rmSync)(x,{recursive:!0,force:!0}),(0,o.mkdirSync)(x,{recursive:!0});let s=(0,o.readFileSync)(i.default.resolve(g,`./app/view/entry.tpl`),`utf-8`);for(let t=0;t<e.length;t++){let n=e[t],a=i.default.resolve(n,`../`),o=A(a,i.default.basename(n).replace(/\.entry\.[^.]+$/,``)),c=o?i.default.basename(o,`.html`):a.split(i.default.sep).at(-1);r[c]=M(s,n,c,o?k(o):T())}return r}function P(){let e=r.buildFESharedState.options.output??`frame`;return e!==`frame`&&n.logRed(`Please pay attention to the build output.`),e===`run`?i.default.join(v,`./app/public/dist`):typeof e==`function`?e():i.default.join(g,`./app/public/dist`)}var F=async e=>{let t=(await import(`chokidar`)).watch(y,{ignored:/(^|[\/\\])\../,persistent:!0,ignoreInitial:!0}),r=!1;t.on(`change`,async t=>{if(!r){r=!0,n.logYellow(`changed: ${t}`);try{await e?.()}catch(e){n.logRed(e)}finally{r=!1}}}),n.logYellow(`watching ${y}/...`)};function I(e=`.html`){let t=[...new Set(Array.isArray(e)?e:[e])];return{name:`flatten-html`,apply:`build`,closeBundle(){let e=P();if(!(0,o.existsSync)(e))return;let r=a.sync(`**/*.html`,{cwd:e,dot:!0});for(let n of r){let r=i.default.join(e,n),a=i.default.basename(n,`.html`),s=`.entry`;a.indexOf(s)===-1&&(a+=s);for(let n of t){let t=a+n,s=i.default.join(e,t);r!==s&&(0,o.copyFileSync)(r,s)}t.some(t=>r===i.default.join(e,a+t))||(0,o.unlinkSync)(r)}let s=[...new Set(r.map(e=>i.default.dirname(e)))].sort().reverse(),c=e=>{if(!((0,o.existsSync)(e)?(0,o.readdirSync)(e):[1]).length){(0,o.rmdirSync)(e);let t=e.split(i.default.sep).slice(0,-1);t.length&&c(t.join(i.default.sep))}};for(let t of s)t&&t!==`.`&&c(i.default.join(e,t));let l=t.flatMap(t=>a.sync(`**/*`+t,{cwd:e,dot:!0}));for(let e of l)n.logYellow(`final file path -----> `+e)}}}function L(e){let t=[``,`.ts`,`.tsx`,`.js`,`.jsx`];return e.reduce((e,[n,r,a=y,s=`./defaultAlias`])=>{let c=t.map(e=>i.default.resolve(a,r+e)).find(e=>(0,o.existsSync)(e)),l=i.default.resolve(f,s);return c&&(l=c),e[n]=l,e},{})}var R=(...e)=>new RegExp(e.join(`[\\/]`)),z=e=>`_${e}_tcC`,B=async(e,t)=>{try{await(0,s.build)({configFile:!1,base:`/dist`,plugins:[(await import(`@vitejs/plugin-react`)).default(),I([`.tpl`]),(0,c.default)()],build:{outDir:P(),emptyOutDir:!0,sourcemap:t===`dev`?`inline`:`hidden`,rolldownOptions:{input:e,output:{codeSplitting:{groups:[{name:z(`__nm`),test:R(`node_modules`),maxSize:5e5,minShareCount:2,priority:1},{name:z(`r`),test:R(`node_modules`,`react`),minShareCount:2,maxSize:5e5,priority:5},{name:z(`r-d`),test:R(`node_modules`,`react-dom`),minShareCount:2,maxSize:2e5,priority:10},{name:z(`r-r-d`),test:R(`node_modules`,`react-router-dom`),minShareCount:2,maxSize:5e5,priority:10},{name:z(`ajv`),test:R(`node_modules`,`ajv`),minShareCount:2,maxSize:2e5,priority:10},{name:z(`ui-lib`),test:R(`components`),minShareCount:2,maxSize:2e5,priority:5},{name:z(`ui-f-lib`),test:R(`components`,`.*?[Ff]orm.*?`),minShareCount:2,maxSize:5e4,priority:10}]}}}},resolve:{alias:{react:b(`react`),"react-dom":b(`react-dom`),"@tc/ui-react/hooks":i.default.resolve(f,`../../fe/packages/react/hooks/`),"@tc/ui-react":i.default.resolve(f,`../../fe/packages/react/ui/`),...L([[`@tc/scalability/SchemaForm/frameData`,`./extended/SchemaForm/data`,_],[`@tc/scalability/SchemaForm/data`,`./extended/SchemaForm/data`],[`@tc/scalability/SchemaPage/CallCom/data`,`./extended/SchemaPage/CallCom/data`],[`@tc/scalability/dash/customRoutes`,`./extended/dash/customRoutes`],[`@tc/scalability/dash/init`,`./extended/dash/init`],[`@tc/scalability/dash/components`,`./extended/dash/components`],[`@tc/scalability/dash/routeGuard`,`./extended/dash/routeGuard`,void 0,`./defaultRouteGuard`]])}}}),n.logJoinColorized(n.colorize(`builded`,`green`),n.colorize(` -> `,`white`),n.colorize(`time: `,`cyan`),n.colorize(new Date,`pink`))}catch(e){if(n.logRed(e),t!==`dev`)throw e}};exports.VBuildFE=B,exports.entries=N,exports.outDir=P,exports.watchFiles=F;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../_virtual/_rolldown/runtime.js`),t=require(`../packages/common/log/index.js`),n=require(`../packages/utils/path.js`);require(`../packages/utils/index.js`);const r=require(`./state.js`);let i=require(`fs`),a=require(`path`);a=e.__toESM(a);let o=require(`glob`);o=e.__toESM(o);let s=require(`vite`),c=require(`@tailwindcss/vite`);c=e.__toESM(c);let l=require(`module`),u=require(`url`);var d=typeof __filename==`string`?__filename:(0,u.fileURLToPath)({}.url),f=a.default.dirname(d),p=process.cwd(),m=(0,l.createRequire)(d),h=a.default.resolve(f,`../../`),g=a.default.resolve(f,`../`),_=a.default.resolve(h,`./fe/frontend`),v=a.default.resolve(p,`.`),y=a.default.resolve(v,`./frontend`),b=e=>a.default.dirname(m.resolve(`${e}/package.json`)),x=a.default.join(v,`.tc-entry-html`),S=`<!-- {{InsertScript}} -->`,C={head:`<!-- TC_HEAD_SLOT -->`,bodyBeforeRoot:`<!-- TC_BODY_BEFORE_ROOT_SLOT -->`,bodyAfterRoot:`<!-- TC_BODY_AFTER_ROOT_SLOT -->`},w=[`head`,`body-before-root`,`body-after-root`],T=()=>({head:``,"body-before-root":``,"body-after-root":``}),E=e=>e.trim().replace(/<!--(?!\s*(?:tc-slot:|\/tc-slot:))[\s\S]*?-->/g,``).replace(/>\s+</g,`><`),D=e=>{let t=[],n=e.replace(/<(script|style|textarea|pre)\b[\s\S]*?<\/\1>/gi,e=>{let n=`__TC_HTML_PRESERVED_${t.length}__`;return t.push(e),n}).replace(/<!--(?!\s*(?:tc-slot:|\/tc-slot:|\{\{InsertScript\}\}|TC_))[\s\S]*?-->/g,``).replace(/>\s+</g,`><`).trim();return t.reduce((e,t,n)=>e.replace(`__TC_HTML_PRESERVED_${n}__`,t),n)},O=e=>e.split(a.default.sep).join(`/`),k=e=>{let t=O(e);return t.startsWith(`.`)||t.startsWith(`/`)?t:`./${t}`},A=e=>/<html[\s>]/i.test(e)&&e.includes(`window['_basePath']`)&&/<div\s+id=["']root["']\s*><\/div>/i.test(e),j=e=>{let n=T(),r=(0,i.readFileSync)(e,`utf-8`),a=/<!--\s*tc-slot:([\w-]+)\s*-->([\s\S]*?)<!--\s*\/tc-slot:\1\s*-->/g,o=!1,s=r;if(r.replace(a,(t,r,i)=>{if(o=!0,!w.includes(r))throw Error(`Invalid html slot "${r}" in ${e}. Allowed slots: ${w.join(`, `)}.`);return n[r]+=i.trim()?`${i}\n`:``,s=s.replace(t,``),t}),s.trim()){if(A(r))return t.logYellow(`ignored legacy generated entry html: ${e}`),T();throw Error([`Invalid custom entry html: ${e}.`,`Custom entry html can only contain tc-slot blocks, for example:`,`<!-- tc-slot:head -->`,`<meta name="description" content="..." />`,`<!-- /tc-slot:head -->`].join(`
2
+ `))}return o&&t.logYellow(`using custom entry html slots: ${e}`),n},M=(e,t)=>{let r=a.default.basename(e),s=[a.default.join(e,`${t}.html`),a.default.join(e,`${r}.html`)].find(e=>(0,i.existsSync)(e));if(s)return s;if(o.sync(n.resolve(e,`*.html`)).length)throw Error([`Entry html filename is not supported in ${e}.`,`Use ${t}.html or ${r}.html as a tc-slot file.`].join(`
3
+ `))},N=(e,t)=>e.replace(C.head,E(t.head)).replace(C.bodyBeforeRoot,E(t[`body-before-root`])).replace(C.bodyAfterRoot,E(t[`body-after-root`])),P=(e=new Date)=>{let t=(e,t=2)=>e.toString().padStart(t,`0`);return[e.getFullYear(),t(e.getMonth()+1),t(e.getDate()),t(e.getHours())].join(`/`)+`:${t(e.getMinutes())}:${t(e.getSeconds())}:${t(e.getMilliseconds(),3)}`},F=(e,t,n,r)=>{let o=a.default.join(x,`${n}.html`),s=k(a.default.relative(a.default.dirname(o),t));return(0,i.writeFileSync)(o,N(e,r).replace(S,`<script type="module" src="${s}"><\/script>`)),o};function I(){t.logWhite(`frameFEPath: `+_),t.logWhite(`runFEPath: `+y);let e=[_,y].reduce((e,t)=>{let r=[`js`,`jsx`,`ts`,`tsx`].map(e=>n.resolve(t,`/**`,`/*.`+e)),i=o.sync(r).filter(e=>e.includes(`.entry.`)).filter(e=>!e.includes(`.d.ts`));return[...e,...i]},[]),r={};if(!e.length)return r;(0,i.rmSync)(x,{recursive:!0,force:!0}),(0,i.mkdirSync)(x,{recursive:!0});let s=(0,i.readFileSync)(a.default.resolve(g,`./app/view/entry.tpl`),`utf-8`);for(let t=0;t<e.length;t++){let n=e[t],i=a.default.resolve(n,`../`),o=M(i,a.default.basename(n).replace(/\.entry\.[^.]+$/,``)),c=o?a.default.basename(o,`.html`):i.split(a.default.sep).at(-1);r[c]=F(s,n,c,o?j(o):T())}return r}function L(){let e=r.buildFESharedState.options.output??`frame`;return e!==`frame`&&t.logRed(`Please pay attention to the build output.`),e===`run`?a.default.join(v,`./app/public/dist`):typeof e==`function`?e():a.default.join(g,`./app/public/dist`)}var R=async e=>{let n=(await import(`chokidar`)).watch(y,{ignored:/(^|[\/\\])\../,persistent:!0,ignoreInitial:!0}),r=!1;n.on(`change`,async n=>{if(!r){r=!0,t.logYellow(`changed: ${n}`);try{await e?.()}catch(e){t.logRed(e)}finally{r=!1}}}),t.logYellow(`watching ${y}/...`)};function z(){return{name:`flatten-html`,apply:`build`,closeBundle(){let e=L(),t=P();(0,i.writeFileSync)(n.resolve(e,`./FEBuildKey`),t)}}}function B(e=`.html`){let n=[...new Set(Array.isArray(e)?e:[e])];return{name:`flatten-html`,apply:`build`,closeBundle(){let e=L();if(!(0,i.existsSync)(e))return;let s=r.buildFESharedState.options.minifyHtml??!1,c=o.sync(`**/*.html`,{cwd:e,dot:!0});for(let t of c){let r=a.default.join(e,t),o=(0,i.readFileSync)(r,`utf-8`),c=s?D(o):o,l=a.default.basename(t,`.html`),u=`.entry`;l.indexOf(u)===-1&&(l+=u);for(let t of n){let n=l+t,o=a.default.join(e,n);r===o?s&&(0,i.writeFileSync)(o,c):(0,i.writeFileSync)(o,c)}n.some(t=>r===a.default.join(e,l+t))||(0,i.unlinkSync)(r)}let l=[...new Set(c.map(e=>a.default.dirname(e)))].sort().reverse(),u=e=>{if(!((0,i.existsSync)(e)?(0,i.readdirSync)(e):[1]).length){(0,i.rmdirSync)(e);let t=e.split(a.default.sep).slice(0,-1);t.length&&u(t.join(a.default.sep))}};for(let t of l)t&&t!==`.`&&u(a.default.join(e,t));let d=n.flatMap(t=>o.sync(`**/*`+t,{cwd:e,dot:!0}));for(let e of d)t.logYellow(`final file path -----> `+e)}}}function V(e){let t=[``,`.ts`,`.tsx`,`.js`,`.jsx`];return e.reduce((e,[n,r,o=y,s=`./defaultAlias`])=>{let c=t.map(e=>a.default.resolve(o,r+e)).find(e=>(0,i.existsSync)(e)),l=a.default.resolve(f,s);return c&&(l=c),e[n]=l,e},{})}var H=(...e)=>new RegExp(e.join(`[\\/]`)),U=e=>`_${e}_tcC`,W=async(e,n)=>{try{await(0,s.build)({configFile:!1,base:`/dist`,plugins:[(await import(`@vitejs/plugin-react`)).default(),B([`.tpl`]),z(),(0,c.default)()],build:{outDir:L(),emptyOutDir:!0,sourcemap:n===`dev`?`inline`:`hidden`,rolldownOptions:{input:e,output:{codeSplitting:{groups:[{name:U(`__nm`),test:H(`node_modules`),maxSize:5e5,minShareCount:2,priority:1},{name:U(`r`),test:H(`node_modules`,`react`),minShareCount:2,maxSize:5e5,priority:5},{name:U(`r-d`),test:H(`node_modules`,`react-dom`),minShareCount:2,maxSize:2e5,priority:10},{name:U(`r-r-d`),test:H(`node_modules`,`react-router-dom`),minShareCount:2,maxSize:5e5,priority:10},{name:U(`ajv`),test:H(`node_modules`,`ajv`),minShareCount:2,maxSize:2e5,priority:10},{name:U(`ui-lib`),test:H(`components`),minShareCount:2,maxSize:2e5,priority:5},{name:U(`ui-f-lib`),test:H(`components`,`.*?[Ff]orm.*?`),minShareCount:2,maxSize:5e4,priority:10}]}}}},resolve:{alias:{react:b(`react`),"react-dom":b(`react-dom`),"@tc/ui-react/hooks":a.default.resolve(f,`../../fe/packages/react/hooks/`),"@tc/ui-react":a.default.resolve(f,`../../fe/packages/react/ui/`),...V([[`@tc/scalability/SchemaForm/frameData`,`./extended/SchemaForm/data`,_],[`@tc/scalability/SchemaForm/data`,`./extended/SchemaForm/data`],[`@tc/scalability/SchemaPage/CallCom/data`,`./extended/SchemaPage/CallCom/data`],[`@tc/scalability/SchemaPage/SchemaTable/data`,`./extended/SchemaPage/SchemaTable/data`],[`@tc/scalability/dash/customRoutes`,`./extended/dash/customRoutes`],[`@tc/scalability/dash/init`,`./extended/dash/init`],[`@tc/scalability/dash/components`,`./extended/dash/components`],[`@tc/scalability/dash/routeGuard`,`./extended/dash/routeGuard`,void 0,`./defaultRouteGuard`]])}}}),t.logJoinColorized(t.colorize(`builded`,`green`),t.colorize(` -> `,`white`),t.colorize(`time: `,`cyan`),t.colorize(new Date,`pink`))}catch(e){if(t.logRed(e),n!==`dev`)throw e}};exports.VBuildFE=W,exports.entries=I,exports.generateBuildKeyPlugin=z,exports.outDir=L,exports.watchFiles=R;