@_tc/template-core 0.2.11 → 0.3.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/.skills/tc-component-usage-skills/SKILL.md +7 -9
- package/.skills/tc-component-usage-skills/reference/component-api.md +2 -2
- package/.skills/tc-component-usage-skills/reference/examples.md +9 -9
- package/.skills/tc-component-usage-skills/reference/patterns.md +5 -5
- package/.skills/tc-component-usage-skills/reference/template-core-frontend.md +1 -1
- package/.skills/tc-generator/SKILL.md +30 -14
- package/.skills/tc-generator/reference/example.md +4 -4
- package/.skills/tc-generator/reference/model-schema.md +9 -5
- package/.skills/tc-generator/reference/runtime-extensions.md +9 -7
- package/AGENT_README.md +52 -33
- package/CHANGE.md +91 -0
- package/README.md +147 -46
- package/cjs/app/controller/ssr.js +1 -0
- package/cjs/app/controller/view.js +1 -1
- package/cjs/app/html/shell.js +36 -0
- package/cjs/app/middleware.js +1 -1
- package/cjs/app/router/ssr.js +1 -0
- package/cjs/app/router/view.js +1 -1
- package/cjs/app/ssr/html.js +17 -0
- package/cjs/app/ssr/manifest.js +2 -0
- package/cjs/app/view/entry.tpl +2 -37
- package/cjs/bundler/buildBE.js +1 -1
- package/cjs/bundler/buildSSR.js +1 -0
- package/cjs/bundler/entryCollect.js +1 -0
- package/cjs/bundler/feSharedConfig.js +1 -0
- package/cjs/bundler/index.js +1 -1
- package/cjs/bundler/ssrClientManifest.js +1 -0
- package/cjs/bundler/ssrEntries.js +1 -0
- package/cjs/bundler/utils.js +3 -3
- package/cjs/packages/common/i18n/index.js +1 -1
- package/cjs/packages/common/index.js +1 -1
- package/cjs/packages/common/ssr/hydration.js +1 -0
- package/cjs/packages/common/ssr/index.js +1 -0
- package/cjs/packages/core/index.js +1 -1
- package/cjs/packages/core/loader/controller.js +1 -1
- package/cjs/packages/core/loader/extend.js +1 -1
- package/cjs/packages/core/loader/merge.js +1 -0
- package/cjs/packages/core/loader/middleware.js +1 -1
- package/cjs/packages/core/loader/model.js +1 -1
- package/cjs/packages/core/loader/router-schema.js +1 -1
- package/cjs/packages/core/loader/router.js +1 -1
- package/cjs/packages/core/loader/service.js +1 -1
- package/cjs/packages/core/paths.js +1 -1
- package/cjs/scripts/vite-build/build.js +3 -3
- package/cjs/scripts/vite-build/collect.js +1 -1
- package/cjs/scripts/vite-build/dts.js +1 -1
- package/cjs/scripts/vite-build/normalize.js +1 -1
- package/cjs/ssrSharedData/outputPaths.js +1 -0
- package/esm/app/controller/ssr.js +215 -0
- package/esm/app/controller/view.js +26 -25
- package/esm/app/html/shell.js +69 -0
- package/esm/app/middleware.js +18 -9
- package/esm/app/router/ssr.js +8 -0
- package/esm/app/router/view.js +5 -4
- package/esm/app/ssr/html.js +90 -0
- package/esm/app/ssr/manifest.js +47 -0
- package/esm/app/view/entry.tpl +2 -37
- package/esm/bundler/buildBE.js +1 -1
- package/esm/bundler/buildSSR.js +126 -0
- package/esm/bundler/entryCollect.js +45 -0
- package/esm/bundler/feSharedConfig.js +143 -0
- package/esm/bundler/index.js +4 -2
- package/esm/bundler/ssrClientManifest.js +14 -0
- package/esm/bundler/ssrEntries.js +13 -0
- package/esm/bundler/utils.js +248 -255
- package/esm/packages/common/i18n/index.js +5 -1
- package/esm/packages/common/index.js +4 -2
- package/esm/packages/common/ssr/hydration.js +55 -0
- package/esm/packages/common/ssr/index.js +20 -0
- package/esm/packages/core/index.js +42 -42
- package/esm/packages/core/loader/controller.js +11 -9
- package/esm/packages/core/loader/extend.js +20 -16
- package/esm/packages/core/loader/merge.js +7 -0
- package/esm/packages/core/loader/middleware.js +11 -12
- package/esm/packages/core/loader/model.js +2 -2
- package/esm/packages/core/loader/router-schema.js +22 -15
- package/esm/packages/core/loader/router.js +32 -26
- package/esm/packages/core/loader/service.js +11 -9
- package/esm/packages/core/paths.js +9 -1
- package/esm/scripts/vite-build/build.js +88 -83
- package/esm/scripts/vite-build/collect.js +31 -27
- package/esm/scripts/vite-build/dts.js +1 -1
- package/esm/scripts/vite-build/normalize.js +6 -3
- package/esm/ssrSharedData/outputPaths.js +33 -0
- package/fe/frontend/apps/dash/Dashboard.d.ts +5 -1
- package/fe/frontend/apps/dash/Dashboard.js +22 -13
- package/fe/frontend/apps/dash/types.d.ts +2 -0
- package/fe/frontend/src/api/baseInfo.d.ts +1 -1
- package/fe/frontend/src/common/CRUD/CRUD.js +1 -1
- package/fe/frontend/src/common/CRUD/index.js +1 -1
- package/fe/frontend/src/common/menu.d.ts +1 -1
- package/fe/frontend/src/common/menu.js +8 -7
- package/fe/frontend/src/common/request.js +1 -1
- package/fe/frontend/src/common/schemaForm.d.ts +1 -0
- package/fe/frontend/src/common/schemaForm.js +12 -0
- package/fe/frontend/src/components/AsyncSelect/AsyncSelect.d.ts +1 -1
- package/fe/frontend/src/components/Router/basename.d.ts +3 -0
- package/fe/frontend/src/components/Router/basename.js +11 -0
- package/fe/frontend/src/components/Router/index.d.ts +1 -1
- package/fe/frontend/src/components/Router/index.js +3 -1
- package/fe/frontend/src/defaultPages/SchemaPage/components/CallCom/builtIn.d.ts +1 -1
- package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaTable/data.d.ts +1 -1
- package/fe/frontend/src/defaultPages/SchemaPage/schemaType.d.ts +2 -2
- package/fe/frontend/src/defaultPages/SchemaPage/utils/schemaConversion.d.ts +1 -1
- package/fe/frontend/src/defaultPages/SidebarSlotPage/SidebarSlotContainer.d.ts +2 -1
- package/fe/frontend/src/defaultPages/SidebarSlotPage/SidebarSlotContainer.js +8 -4
- package/fe/frontend/src/defaultPages/SidebarSlotPageTmp.js +2 -1
- package/fe/frontend/src/exportStore.js +2 -2
- package/fe/frontend/src/hooks/useCurrentMenuData.d.ts +1 -1
- package/fe/frontend/src/hooks/useCurrentMenuData.js +2 -2
- package/fe/frontend/src/hooks/useRouterParams.js +4 -3
- package/fe/frontend/src/index.d.ts +1 -0
- package/fe/frontend/src/index.js +4 -3
- package/fe/frontend/src/main.js +2 -0
- package/fe/frontend/src/stores/mode.d.ts +15 -2
- package/fe/frontend/src/stores/mode.js +19 -5
- package/fe/frontend/src/typing/window.d.ts +2 -0
- package/fe/packages/common/LRUCache.js +2 -0
- package/fe/packages/common/array/index.js +37 -0
- package/fe/packages/common/cache/index.js +2 -0
- package/fe/packages/common/guards/index.js +19 -1
- package/fe/packages/common/http/index.js +1 -1
- package/fe/packages/common/i18n/index.js +8 -4
- package/fe/packages/common/i18n/locales.js +1 -1
- package/fe/packages/common/i18n/types.d.ts +1 -0
- package/fe/packages/common/i18n/types.js +0 -0
- package/fe/packages/common/index.d.ts +1 -0
- package/fe/packages/common/index.js +17 -0
- package/fe/packages/common/log/index.js +146 -0
- package/fe/packages/common/number/index.js +11 -0
- package/fe/packages/common/object/filterEmpty.js +2 -1
- package/fe/packages/common/object/filtereEmpty.js +2 -0
- package/fe/packages/common/object/index.js +20 -0
- package/fe/packages/common/ssr/hydration.d.ts +23 -0
- package/fe/packages/common/ssr/hydration.js +88 -0
- package/fe/packages/common/ssr/index.d.ts +8 -0
- package/fe/packages/common/ssr/index.js +52 -0
- package/fe/packages/common/string/index.js +32 -0
- package/fe/packages/common/types/index.js +0 -0
- package/fe/packages/react/hooks/index.d.ts +2 -0
- package/fe/packages/react/hooks/index.js +3 -1
- package/fe/packages/react/hooks/useHydrationData.d.ts +2 -0
- package/fe/packages/react/hooks/useHydrationData.js +23 -0
- package/fe/packages/react/hooks/useSSR.d.ts +6 -0
- package/fe/packages/react/hooks/useSSR.js +46 -0
- package/fe/packages/react/ui/components/DataTable/index.js +16 -15
- package/fe/packages/react/ui/components/Form/SchemaForm/data.d.ts +3 -2
- package/fe/packages/react/ui/components/Form/SchemaForm/data.js +5 -6
- package/fe/packages/react/ui/components/Form/SchemaForm/index.d.ts +1 -0
- package/fe/packages/react/ui/components/Form/SchemaForm/index.js +2 -2
- package/fe/packages/react/ui/components/Form/index.js +2 -1
- package/fe/packages/react/ui/components/Input/Input.js +5 -1
- package/fe/packages/react/ui/components/Popup/Popup.js +6 -1
- package/fe/packages/react/ui/components/index.js +2 -1
- package/fe/packages/react/ui/components/testPage/demos/core/DataTableDemo.js +241 -211
- package/fe/packages/react/ui/components/testPage/demos/core/DataTableDemo2.js +1 -1
- package/fe/packages/react/ui/i18n/I18nProvider.js +4 -0
- package/fe/packages/react/ui/index.js +2 -1
- package/fe/ssr/apps/dash/dash.entry.d.ts +13 -0
- package/fe/ssr/apps/dash/dash.entry.js +162 -0
- package/fe/ssr/apps/demo/demo.entry.d.ts +13 -0
- package/fe/ssr/apps/demo/demo.entry.js +38 -0
- package/fe/ssr/apps/server-data/server-data.entry.d.ts +26 -0
- package/fe/ssr/apps/server-data/server-data.entry.js +275 -0
- package/fe/ssr/apps/ui-components/ui-components.entry.d.ts +5 -0
- package/fe/ssr/apps/ui-components/ui-components.entry.js +17 -0
- package/fe/ssr/components/StreamingRender/StreamingCache.d.ts +2 -0
- package/fe/ssr/components/StreamingRender/StreamingCache.js +31 -0
- package/fe/ssr/components/StreamingRender/StreamingRender.d.ts +3 -0
- package/fe/ssr/components/StreamingRender/StreamingRender.js +48 -0
- package/fe/ssr/components/StreamingRender/StreamingScript.d.ts +8 -0
- package/fe/ssr/components/StreamingRender/StreamingScript.js +58 -0
- package/fe/ssr/components/StreamingRender/index.d.ts +4 -0
- package/fe/ssr/components/StreamingRender/index.js +5 -0
- package/fe/ssr/components/StreamingRender/type.d.ts +9 -0
- package/fe/ssr/components/StreamingRender/type.js +0 -0
- package/fe/ssr/components/index.d.ts +2 -0
- package/fe/ssr/components/index.js +2 -0
- package/fe/ssr/createSSREntry.d.ts +6 -0
- package/fe/ssr/createSSREntry.js +42 -0
- package/fe/ssr/hooks/index.d.ts +1 -0
- package/fe/ssr/hooks/index.js +2 -0
- package/fe/ssr/hooks/useSuspensePromise.d.ts +1 -0
- package/fe/ssr/hooks/useSuspensePromise.js +31 -0
- package/fe/ssr/index.d.ts +4 -0
- package/fe/ssr/index.js +6 -0
- package/fe/ssr/types.d.ts +13 -0
- package/fe/ssr/types.js +0 -0
- package/{model → models}/frontend/src/typing/window.d.ts +2 -0
- package/{model → models}/packages/common/i18n/types.d.ts +1 -0
- package/{model → models}/packages/common/index.d.ts +1 -0
- package/models/packages/common/ssr/hydration.d.ts +23 -0
- package/models/packages/common/ssr/index.d.ts +8 -0
- package/{model → models}/packages/react/ui/components/Form/SchemaForm/data.d.ts +3 -2
- package/{model → models}/packages/react/ui/components/Form/SchemaForm/index.d.ts +1 -0
- package/package.json +43 -6
- package/types/app/controller/ssr.d.ts +14 -0
- package/types/app/html/shell.d.ts +101 -0
- package/types/app/router/ssr.d.ts +6 -0
- package/types/app/ssr/html.d.ts +53 -0
- package/types/app/ssr/manifest.d.ts +17 -0
- package/types/app/typings.d.ts +2 -0
- package/types/bundler/buildSSR.d.ts +56 -0
- package/types/bundler/entryCollect.d.ts +36 -0
- package/types/bundler/feSharedConfig.d.ts +35 -0
- package/types/bundler/index.d.ts +4 -0
- package/types/bundler/ssrClientManifest.d.ts +4 -0
- package/types/bundler/ssrEntries.d.ts +23 -0
- package/types/bundler/state.d.ts +2 -2
- package/types/bundler/utils.d.ts +35 -2
- package/types/config/config.default.d.ts +10 -0
- package/types/packages/common/i18n/types.d.ts +2 -0
- package/types/packages/common/index.d.ts +1 -0
- package/types/packages/common/ssr/hydration.d.ts +72 -0
- package/types/packages/common/ssr/index.d.ts +34 -0
- package/types/packages/core/loader/merge.d.ts +3 -0
- package/types/packages/core/loader/model.d.ts +2 -2
- package/types/packages/core/paths.d.ts +5 -0
- package/types/packages/core/types.d.ts +10 -1
- package/types/scripts/vite-build/build.d.ts +1 -0
- package/types/scripts/vite-build/types.d.ts +3 -0
- package/types/ssrSharedData/outputPaths.d.ts +59 -0
- package/fe/packages/react/hooks/useWatch.test.js +0 -24
- package/fe/packages/react/ui/assets/table/no-result.js +0 -4
- package/fe/packages/react/ui/components/DataTable/dataTableWidth.test.js +0 -39
- package/fe/packages/react/ui/components/InputNumber/inputNumberUtils.test.js +0 -59
- /package/.skills/tc-generator/reference/project-template/{model → models}/product/mode.js +0 -0
- /package/.skills/tc-generator/reference/project-template/{model → models}/product/project/default.js +0 -0
- /package/fe/{model → models}/types/data/button.d.ts +0 -0
- /package/fe/{model → models}/types/data/component.d.ts +0 -0
- /package/fe/{model → models}/types/data/fetchInfo.d.ts +0 -0
- /package/fe/{model → models}/types/data/schema.d.ts +0 -0
- /package/fe/{model → models}/types/data/search.d.ts +0 -0
- /package/fe/{model → models}/types/index.d.ts +0 -0
- /package/fe/{model → models}/types/menuType.d.ts +0 -0
- /package/fe/{model → models}/types/model.d.ts +0 -0
- /package/{model → models}/frontend/extended/SchemaForm/data.d.ts +0 -0
- /package/{model → models}/frontend/src/common/auth/index.d.ts +0 -0
- /package/{model → models}/frontend/src/common/fetchErrorShow.d.ts +0 -0
- /package/{model → models}/frontend/src/common/language.d.ts +0 -0
- /package/{model → models}/frontend/src/common/logFn/index.d.ts +0 -0
- /package/{model → models}/frontend/src/common/request.d.ts +0 -0
- /package/{model → models}/frontend/src/components/AsyncSelect/AsyncSelect.d.ts +0 -0
- /package/{model → models}/frontend/src/components/AsyncSelect/index.d.ts +0 -0
- /package/{model → models}/frontend/src/defaultPages/SchemaPage/components/CallCom/DetailPanel.d.ts +0 -0
- /package/{model → models}/frontend/src/defaultPages/SchemaPage/components/CallCom/PopFrom.d.ts +0 -0
- /package/{model → models}/frontend/src/defaultPages/SchemaPage/components/CallCom/builtIn.d.ts +0 -0
- /package/{model → models}/frontend/src/defaultPages/SchemaPage/data/eventInfo.d.ts +0 -0
- /package/{model → models}/frontend/src/defaultPages/SchemaPage/data/index.d.ts +0 -0
- /package/{model → models}/frontend/src/defaultPages/SchemaPage/hooks/useComConfig.d.ts +0 -0
- /package/{model → models}/frontend/src/defaultPages/SchemaPage/schemaType.d.ts +0 -0
- /package/{model → models}/frontend/src/defaultPages/SchemaPage/utils/permissions.d.ts +0 -0
- /package/{model → models}/frontend/src/defaultPages/SchemaPage/utils/validator.d.ts +0 -0
- /package/{model → models}/frontend/src/hooks/useText.d.ts +0 -0
- /package/{model → models}/frontend/src/language/en-US.d.ts +0 -0
- /package/{model → models}/frontend/src/language/index.d.ts +0 -0
- /package/{model → models}/frontend/src/language/resources.d.ts +0 -0
- /package/{model → models}/frontend/src/language/zh-CN.d.ts +0 -0
- /package/{model → models}/frontend/src/stores/apiFreezer.d.ts +0 -0
- /package/{model → models}/frontend/src/stores/schemaEventBus.d.ts +0 -0
- /package/{model → models}/frontend/src/stores/schemaStore.d.ts +0 -0
- /package/{model → models}/frontend/src/typing/scalability.d.ts +0 -0
- /package/{model/model → models/models}/index.d.ts +0 -0
- /package/{model/model → models/models}/test.d.ts +0 -0
- /package/{model/model → models/models}/types/data/button.d.ts +0 -0
- /package/{model/model → models/models}/types/data/component.d.ts +0 -0
- /package/{model/model → models/models}/types/data/fetchInfo.d.ts +0 -0
- /package/{model/model → models/models}/types/data/schema.d.ts +0 -0
- /package/{model/model → models/models}/types/data/search.d.ts +0 -0
- /package/{model/model → models/models}/types/index.d.ts +0 -0
- /package/{model/model → models/models}/types/menuType.d.ts +0 -0
- /package/{model/model → models/models}/types/model.d.ts +0 -0
- /package/{model → models}/packages/common/array/index.d.ts +0 -0
- /package/{model → models}/packages/common/cache/LRUCache.d.ts +0 -0
- /package/{model → models}/packages/common/cache/index.d.ts +0 -0
- /package/{model → models}/packages/common/guards/index.d.ts +0 -0
- /package/{model → models}/packages/common/http/index.d.ts +0 -0
- /package/{model → models}/packages/common/i18n/default.d.ts +0 -0
- /package/{model → models}/packages/common/i18n/en-US.d.ts +0 -0
- /package/{model → models}/packages/common/i18n/index.d.ts +0 -0
- /package/{model → models}/packages/common/i18n/locales.d.ts +0 -0
- /package/{model → models}/packages/common/log/index.d.ts +0 -0
- /package/{model → models}/packages/common/number/index.d.ts +0 -0
- /package/{model → models}/packages/common/object/filterEmpty.d.ts +0 -0
- /package/{model → models}/packages/common/object/index.d.ts +0 -0
- /package/{model → models}/packages/common/rafTimer.d.ts +0 -0
- /package/{model → models}/packages/common/string/index.d.ts +0 -0
- /package/{model → models}/packages/common/types/index.d.ts +0 -0
- /package/{model → models}/packages/react/hooks/useBreadcrumb.d.ts +0 -0
- /package/{model → models}/packages/react/hooks/useExecuteOnce.d.ts +0 -0
- /package/{model → models}/packages/react/hooks/useLanguage.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Button/Button.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Button/SubmitButton.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Button/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Card/Card.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Card/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Checkbox/Checkbox.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Checkbox/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/ConfirmDialog/ConfirmDialog.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/ConfirmDialog/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/DataTable/ActionBtn.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/DataTable/dataTableWidth.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/DataTable/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Date/Calendar.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Date/Date.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Date/LocaleContext.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Date/LocaleProvider.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Date/TimePicker.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Date/data.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Date/dateLocaleStore.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Date/dropdownPositioning.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Date/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Date/locales.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Drawer/Drawer.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Drawer/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Dropdown/Dropdown.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Dropdown/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Form/Form.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Form/FormItem.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Form/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Form/useForm.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/ImagePreview/ImagePreview.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/ImagePreview/PreviewImage.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/ImagePreview/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Input/Input.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Input/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/InputNumber/InputNumber.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/InputNumber/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/InputNumber/inputNumberUtils.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Label/Label.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Label/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Layout/Layout.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Layout/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Loading/Loading.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Loading/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Menu/Menu.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Menu/MenuContext.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Menu/MenuItem.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Menu/SubMenu.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Menu/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Menu/menuTypes.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Menu/utils.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Message/Message.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Message/MessageManager.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Message/data.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Message/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Modal/Modal.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Modal/ModalManager.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Modal/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Notification/Notification.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Notification/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Overlay/Overlay.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Overlay/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Pagination/Pagination.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Pagination/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Popup/Popup.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Popup/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Radio/Radio.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Radio/RadioGroup.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Radio/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Search/Search.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Search/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Select/Select.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Select/dropdownPositioning.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Select/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Skeleton/Skeleton.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Skeleton/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Switch/Switch.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Switch/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/TableSearch/TableSearch.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/TableSearch/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/TableSearch/lang.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/TableSearch/tableSearchLocaleStore.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Tabs/Tabs.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Tabs/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Textarea/Textarea.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Textarea/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Tooltip/Tooltip.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Tooltip/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/TreeSelect/TreeSelect.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/TreeSelect/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Upload/ImageUpload.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Upload/Upload.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/Upload/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/breadcrumb/breadcrumb.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/breadcrumb/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/hooks/useDropdownPositioning.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/hooks/useInputController.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/table/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/table/table.d.ts +0 -0
- /package/{model → models}/packages/react/ui/components/types/baseType.d.ts +0 -0
- /package/{model → models}/packages/react/ui/i18n/I18nProvider.d.ts +0 -0
- /package/{model → models}/packages/react/ui/i18n/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/i18n/useI18n.d.ts +0 -0
- /package/{model → models}/packages/react/ui/index.d.ts +0 -0
- /package/{model → models}/packages/react/ui/lib/createStoreHook.d.ts +0 -0
- /package/{model → models}/packages/react/ui/lib/export.d.ts +0 -0
- /package/{model → models}/packages/react/ui/lib/utils.d.ts +0 -0
- /package/{model → models}/packages/react/ui/stores/breadcrumb.d.ts +0 -0
- /package/{model → models}/packages/react/ui/stores/language.d.ts +0 -0
- /package/{model → models}/packages/react/ui/types/index.d.ts +0 -0
- /package/{model → models}/typings/type.d.ts +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @_tc/template-core
|
|
2
2
|
|
|
3
|
-
TemplateCore 是一个基于 TypeScript、Koa、React 的后台框架包。它把后端约定式加载、前端 Dashboard、Schema CRUD 页面、
|
|
3
|
+
TemplateCore 是一个基于 TypeScript、Koa、React 的后台框架包。它把后端约定式加载、前端 Dashboard、Schema CRUD 页面、models 类型和类型扩展放到同一个 npm 包里,项目只需要按目录补充自己的 `app/`、`models/`、`frontend/`。
|
|
4
4
|
|
|
5
5
|
预览 & 文档地址:https://t-c-s-p.allomg.qzz.io/preview
|
|
6
6
|
|
|
@@ -34,7 +34,9 @@ my-admin/
|
|
|
34
34
|
│ ├── src/ # 库代码
|
|
35
35
|
│ ├── apps/ # 应用入口
|
|
36
36
|
│ └── extended/ # 扩展点
|
|
37
|
-
├──
|
|
37
|
+
├── ssr/
|
|
38
|
+
│ └── apps/ # SSR 页面入口,可选
|
|
39
|
+
├── models/
|
|
38
40
|
│ └── product/
|
|
39
41
|
│ ├── mode.ts
|
|
40
42
|
│ └── project/
|
|
@@ -55,7 +57,7 @@ async function main() {
|
|
|
55
57
|
await serverStart({
|
|
56
58
|
name: 'my-admin',
|
|
57
59
|
baseDir: join(__dirname, '.'),
|
|
58
|
-
|
|
60
|
+
pageBasePath: '/',
|
|
59
61
|
additionalPublicPaths: [join(__dirname, 'dist/public')],
|
|
60
62
|
})
|
|
61
63
|
|
|
@@ -76,7 +78,8 @@ main().catch((error) => {
|
|
|
76
78
|
| --- | --- | --- | --- | --- |
|
|
77
79
|
| `name` | `string` | 否 | - | 应用名称 |
|
|
78
80
|
| `baseDir` | `string` | 否 | - | 项目根目录,通常为 `join(__dirname, '.')` |
|
|
79
|
-
| `
|
|
81
|
+
| `pageBasePath` | `string` | 否 | `'/'` | 页面访问前缀,所有前端页面路由的基础路径 |
|
|
82
|
+
| `ssrPageBasePath` | `string` | 否 | `'/fessr'` | SSR 页面访问前缀,如 `/tssr` 会让 SSR 页面路由变成 `/tssr/:page` |
|
|
80
83
|
| `homePage` | `string` | 否 | - | 应用首页路径 |
|
|
81
84
|
| `additionalPublicPaths` | `string | string[]` | 否 | - | 追加静态资源目录;如需同时作为 Nunjucks 模板查找目录,建议传绝对路径数组 |
|
|
82
85
|
|
|
@@ -141,6 +144,96 @@ await buildFE('prod', {
|
|
|
141
144
|
await buildFE('prod', { minifyHtml: true })
|
|
142
145
|
```
|
|
143
146
|
|
|
147
|
+
### SSR 页面(可选)
|
|
148
|
+
|
|
149
|
+
SSR 入口放在根级 `ssr/apps/{page}/{page}.entry.tsx`。SSR 和 CSR 并存,SSR 页面默认通过 `/fessr/:page` 访问,不影响现有 `frontend/apps/` 页面。
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
my-admin/
|
|
153
|
+
└── ssr/
|
|
154
|
+
└── apps/
|
|
155
|
+
└── hello/
|
|
156
|
+
└── hello.entry.tsx
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
import { createSSREntry } from '@_tc/template-core/ssr/createSSREntry'
|
|
161
|
+
import type { SSRPageMetaResolver, SSRPropsContext } from '@_tc/template-core/ssr'
|
|
162
|
+
|
|
163
|
+
interface HelloProps {
|
|
164
|
+
name: string
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function HelloPage({ name }: HelloProps) {
|
|
168
|
+
return <h1>Hello, {name}</h1>
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export async function getServerProps(context: SSRPropsContext) {
|
|
172
|
+
return { name: (context.query.name as string) || 'SSR' }
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export const pageTitle: SSRPageMetaResolver<HelloProps> = ({ props }) => `Hello, ${props.name}`
|
|
176
|
+
export const pageDescription: SSRPageMetaResolver<HelloProps> = ({ path }) => `SSR hello page at ${path}`
|
|
177
|
+
|
|
178
|
+
export default HelloPage
|
|
179
|
+
|
|
180
|
+
createSSREntry(HelloPage)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
SSR 运行时会通过 React streaming bootstrap 动态 import 客户端入口。页面包含 `Suspense` 边界时,服务端可以先输出 shell / fallback,浏览器侧先启动 hydration,pending 内容后续继续 stream;如果页面没有 `Suspense` 边界,hydration 时机通常会接近完整 root HTML 到达之后。完整机制见 [Streaming Bootstrap 说明](./ssr/STREAMING_BOOTSTRAP.md)。
|
|
184
|
+
|
|
185
|
+
`pageTitle` / `pageDescription` 可以导出字符串,也可以导出同步或异步函数。函数会在 `getServerProps()` 之后执行,入参包含 `params`、`query`、`path`、`app`、`ctx` 和 `props`。
|
|
186
|
+
|
|
187
|
+
组件级流式异步数据可以使用 `StreamingRender`。它会在服务端 Suspense 中等待 `getData()`,把结果随 HTML 片段用 JSON script 注入,客户端 hydration 时优先复用这份数据。
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
import { StreamingRender } from '@_tc/template-core/ssr/components'
|
|
191
|
+
|
|
192
|
+
function OverviewPanel() {
|
|
193
|
+
return (
|
|
194
|
+
<StreamingRender
|
|
195
|
+
keyName="overview"
|
|
196
|
+
fallback={<div>Loading...</div>}
|
|
197
|
+
getData={loadOverview}
|
|
198
|
+
>
|
|
199
|
+
{(data) => <OverviewView data={data} />}
|
|
200
|
+
</StreamingRender>
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`keyName` 需要在页面内稳定且唯一;`getData()` 的返回值必须可 JSON 序列化,并且会进入 HTML,不能包含 token、密钥等敏感信息。客户端找不到对应注入数据时也可能执行 `getData()`,因此数据函数需要兼容浏览器 fallback,或在函数内部显式区分服务端和客户端逻辑。底层 Suspense Promise hook 可从 `@_tc/template-core/ssr/hooks` 或 `@_tc/template-core/ssr/hooks/useSuspensePromise` 引入。
|
|
206
|
+
|
|
207
|
+
启动时构建 SSR 双产物:
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
import { join } from 'path'
|
|
211
|
+
import { serverStart } from '@_tc/template-core'
|
|
212
|
+
import { buildSSR, watchSSRFiles } from '@_tc/template-core/bundler'
|
|
213
|
+
|
|
214
|
+
const baseDir = join(__dirname, '.')
|
|
215
|
+
|
|
216
|
+
await serverStart({
|
|
217
|
+
name: 'my-admin',
|
|
218
|
+
baseDir,
|
|
219
|
+
ssrPageBasePath: '/fessr',
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
await buildSSR({ baseDir, output: 'run' })
|
|
223
|
+
await watchSSRFiles({ baseDir, output: 'run' })
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
访问:
|
|
227
|
+
|
|
228
|
+
```text
|
|
229
|
+
http://localhost:9000/fessr/hello
|
|
230
|
+
http://localhost:9000/fessr/hello?name=TemplateCore
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
`buildSSR()` 会构建私有 `{ssrPrivateRoot}/ssr-server/{page}.mjs`、私有 `{ssrPrivateRoot}/ssr-manifest/manifest.json`,并把 SSR hydration 入口并入 FE browser build。浏览器侧静态资源走普通 `/dist/assets/*`,可与 CSR 入口共享 chunk;SSR HTML 会根据 manifest 生成 preload,并通过 React bootstrap dynamic import 启动对应客户端入口。服务端会从 `{publicPath}/../.tc/ssr` 查找 server bundle 和 manifest。`/dist/ssr-server/*` 和 `/dist/.vite/*` 会被拦截为 404,避免私有产物或误放文件直连暴露。如果 `output` 使用自定义目录,需要把对应 public 根目录加入 `additionalPublicPaths`。
|
|
234
|
+
|
|
235
|
+
`*.entry.tsx` 会被 server/client 两次构建处理,顶层代码需要同时兼容 Node 和浏览器。Node-only 逻辑建议放到 `*.server.ts`,并在 `getServerProps()` 内动态导入;浏览器 API 需要放到 `useEffect` 或 `typeof window !== 'undefined'` 守卫之后。`getServerProps()` 运行在 Node 侧,不要直接复用依赖 `window` / `localStorage` 签名上下文的前端 API 层。
|
|
236
|
+
|
|
144
237
|
配置文件:
|
|
145
238
|
|
|
146
239
|
```ts
|
|
@@ -161,7 +254,7 @@ export default {
|
|
|
161
254
|
http://localhost:9000/dash?projk=demo
|
|
162
255
|
```
|
|
163
256
|
|
|
164
|
-
`projk` 对应 `
|
|
257
|
+
`projk` 对应 `models/{modelKey}/project/{projectKey}.ts` 里的 `projectKey`。
|
|
165
258
|
|
|
166
259
|
## 内置功能
|
|
167
260
|
|
|
@@ -179,23 +272,30 @@ http://localhost:9000/dash?projk=demo
|
|
|
179
272
|
- 内置 UI 组件:提供丰富的 React 组件库,详见下方"内置 UI 组件"章节。
|
|
180
273
|
- API 中间件:错误处理、静态资源、body parser、项目上下文、接口签名、参数校验。
|
|
181
274
|
- 前端构建:扫描框架和项目的 `frontend/**/*.entry.{ts,tsx,js,jsx}`,输出服务端可渲染的 `.entry.tpl`,并写入 `FEBuildKey` 供 HTML ETag 缓存失效使用。
|
|
275
|
+
- SSR 页面:扫描框架和项目的 `ssr/apps/**/*.entry.{ts,tsx,js,jsx}`,输出 server/client 双产物并通过 `/fessr/:page` 服务端渲染。
|
|
182
276
|
- 类型扩展:支持扩展 SchemaForm、SchemaTable 单元格渲染组件、CallCom、KoaApp。
|
|
183
277
|
|
|
184
278
|
## 常用公开入口
|
|
185
279
|
|
|
186
|
-
完整 exports 以发布包内 `package.json` 为准,除下表外还包含 `./fe/main`、`./fe/common/request`、`./fe/*`、`./fe/rc/*`、`./fe/rc/hooks` 等子路径。
|
|
280
|
+
完整 exports 以发布包内 `package.json` 为准,除下表外还包含 `./fe/main`、`./fe/common/request`、`./ssr`、`./ssr/createSSREntry`、`./ssr/components`、`./ssr/components/StreamingRender`、`./ssr/hooks`、`./ssr/hooks/useSuspensePromise`、`./fe/*`、`./fe/rc/*`、`./fe/rc/hooks` 等子路径。
|
|
187
281
|
|
|
188
282
|
| 入口 | 用途 |
|
|
189
283
|
| --- | --- |
|
|
190
284
|
| `@_tc/template-core` | 服务启动、基础 Controller/Service、Koa 类型 |
|
|
191
|
-
| `@_tc/template-core/bundler` |
|
|
285
|
+
| `@_tc/template-core/bundler` | 构建入口,提供 `buildFE`、`buildBE`、`buildSSR`、`watchSSRFiles` |
|
|
286
|
+
| `@_tc/template-core/ssr` | SSR 类型与运行时辅助,导出 `SSRPropsContext`、`SSRPageMetaResolver`、`StreamingRender`、`useSuspensePromise` |
|
|
287
|
+
| `@_tc/template-core/ssr/createSSREntry` | SSR 页面客户端 hydration 工厂 |
|
|
288
|
+
| `@_tc/template-core/ssr/components` | SSR 组件汇总入口,导出 `StreamingRender` |
|
|
289
|
+
| `@_tc/template-core/ssr/components/StreamingRender` | `StreamingRender` 显式子路径 |
|
|
290
|
+
| `@_tc/template-core/ssr/hooks` | SSR hooks 汇总入口,导出 `useSuspensePromise` |
|
|
291
|
+
| `@_tc/template-core/ssr/hooks/useSuspensePromise` | `useSuspensePromise` 显式子路径 |
|
|
192
292
|
| `@_tc/template-core/fe` | 前端初始化、动态组件渲染辅助、Dash 路由扩展、请求方法、SchemaPage 事件、token 工具、共享状态和内置前端组件 |
|
|
193
293
|
| `@_tc/template-core/fe/main` | 前端初始化入口 |
|
|
194
294
|
| `@_tc/template-core/fe/common/request` | 请求实例、请求方法和请求类型的显式子路径 |
|
|
195
295
|
| `@_tc/template-core/fe/rc` | UI/SchemaForm 组件和类型 |
|
|
196
296
|
| `@_tc/template-core/fe/rc/hooks` | React hooks 汇总入口 |
|
|
197
297
|
| `@_tc/template-core/fe/tailwind_ui.css` | 前端全局样式入口,源码对应 `frontend/src/main.css` |
|
|
198
|
-
| `@_tc/template-core/
|
|
298
|
+
| `@_tc/template-core/models` | model 配置类型 |
|
|
199
299
|
|
|
200
300
|
### 后端类型
|
|
201
301
|
|
|
@@ -245,14 +345,14 @@ export const demoRouter = ((app, router) => {
|
|
|
245
345
|
`model` 是后台菜单、项目和 Schema 页面的数据源。框架会读取:
|
|
246
346
|
|
|
247
347
|
```text
|
|
248
|
-
|
|
249
|
-
|
|
348
|
+
models/{modelKey}/mode.ts
|
|
349
|
+
models/{modelKey}/project/{projectKey}.ts
|
|
250
350
|
```
|
|
251
351
|
|
|
252
|
-
`mode.ts`
|
|
352
|
+
`mode.ts` 定义模型基础配置:
|
|
253
353
|
|
|
254
354
|
```ts
|
|
255
|
-
import type { ModelDataType } from '@_tc/template-core/
|
|
355
|
+
import type { ModelDataType } from '@_tc/template-core/models'
|
|
256
356
|
|
|
257
357
|
const model: ModelDataType = {
|
|
258
358
|
mode: 'MB',
|
|
@@ -373,14 +473,14 @@ export default {
|
|
|
373
473
|
- `project` 会继承同目录上层 `mode`。
|
|
374
474
|
- 对象递归合并,`project` 覆盖 `mode`。
|
|
375
475
|
- 数组按 `key` 合并:同 key 覆盖,不同 key 新增。
|
|
376
|
-
- `
|
|
476
|
+
- `models/index.ts` 或 `models/index.js` 会被 loader 跳过。
|
|
377
477
|
|
|
378
478
|
### model 数组合并示例
|
|
379
479
|
|
|
380
480
|
假设 `mode.ts` 定义了两个菜单项:
|
|
381
481
|
|
|
382
482
|
```ts
|
|
383
|
-
//
|
|
483
|
+
// models/product/mode.ts
|
|
384
484
|
export default {
|
|
385
485
|
name: '商品后台',
|
|
386
486
|
menu: [
|
|
@@ -411,7 +511,7 @@ export default {
|
|
|
411
511
|
`project/demo.ts` 可以:
|
|
412
512
|
|
|
413
513
|
```ts
|
|
414
|
-
//
|
|
514
|
+
// models/product/project/demo.ts
|
|
415
515
|
export default {
|
|
416
516
|
name: 'Demo 企业商品后台',
|
|
417
517
|
menu: [
|
|
@@ -553,7 +653,7 @@ app/router-schema/**/*.(js|ts) -> app.routerSchema
|
|
|
553
653
|
app/extends/*.(js|ts) -> app.extends
|
|
554
654
|
config/config.default.(js|ts) -> app.config
|
|
555
655
|
config/config.{env}.(js|ts) -> app.config
|
|
556
|
-
|
|
656
|
+
models/**/*.(js|ts) -> 内置 project service 按需读取的项目模型配置
|
|
557
657
|
```
|
|
558
658
|
|
|
559
659
|
内置扩展:
|
|
@@ -1101,7 +1201,7 @@ Schema 表单校验会把 AJV keyword 映射到内置语言 key,覆盖 `requir
|
|
|
1101
1201
|
|
|
1102
1202
|
非必填字段为空时会跳过 AJV 校验,空值包括 `undefined`、`null`、空字符串、空数组和空对象。
|
|
1103
1203
|
|
|
1104
|
-
如果需要扩展更多 AJV
|
|
1204
|
+
如果需要扩展更多 AJV 文案,需要在 TemplateCore 源码中补充后重新发布:
|
|
1105
1205
|
|
|
1106
1206
|
1. `frontend/src/defaultPages/SchemaPage/utils/validator.ts` 的 `formatError()` 映射。
|
|
1107
1207
|
2. `frontend/src/language/zh-CN.ts` 和 `frontend/src/language/en-US.ts` 文案。
|
|
@@ -1140,15 +1240,15 @@ initThemeMode()
|
|
|
1140
1240
|
applyThemeMode('dark', true)
|
|
1141
1241
|
```
|
|
1142
1242
|
|
|
1143
|
-
RAF
|
|
1243
|
+
RAF 风格计时器通过 `@_tc/template-core/fe` 对外提供,浏览器优先使用 `requestAnimationFrame`,缺少 RAF 时自动降级到 `setTimeout`。
|
|
1144
1244
|
|
|
1145
1245
|
`@_tc/template-core/fe/rc` 和 `@_tc/template-core/fe/rc/hooks` 也会随发布包提供对应 UI 与 hooks 入口;hooks 汇总入口包含 `useBreadcrumb`、`useExecuteOnce`、`useInit`、`useLanguage`、`usePagination`、`useRefState`、`useWatch`。
|
|
1146
1246
|
|
|
1147
|
-
`useRefState` 支持可选的 `delayTiming` 参数,传入大于 0 的值时会延迟 state
|
|
1247
|
+
`useRefState` 支持可选的 `delayTiming` 参数,传入大于 0 的值时会延迟 state 提交,并复用包内浏览器优先、Node/SSR 自动降级的计时器实现。
|
|
1148
1248
|
|
|
1149
1249
|
### 前端请求封装详解
|
|
1150
1250
|
|
|
1151
|
-
|
|
1251
|
+
框架内置的请求封装通过 `@_tc/template-core/fe` 和 `@_tc/template-core/fe/common/request` 对外提供,底层使用原生 `fetch` API,实现了类似 Axios 的接口和拦截器机制,提供了签名、鉴权、错误处理等能力。
|
|
1152
1252
|
|
|
1153
1253
|
**基础配置**:
|
|
1154
1254
|
- `BASE_URL`:固定为 `/api`
|
|
@@ -1259,7 +1359,7 @@ try {
|
|
|
1259
1359
|
|
|
1260
1360
|
## 样式与 Tailwind V4
|
|
1261
1361
|
|
|
1262
|
-
使用内置前端或 UI 组件时,需要引入包内样式。默认
|
|
1362
|
+
使用内置前端或 UI 组件时,需要引入包内样式。默认 Dashboard 入口已经包含包内全局样式;如果项目侧自定义入口、只使用 `fe/rc` 组件,或希望样式入口更明确,建议显式引入:
|
|
1263
1363
|
|
|
1264
1364
|
```ts
|
|
1265
1365
|
// frontend/xxx/xxx.entry.tsx
|
|
@@ -1274,7 +1374,7 @@ import '@_tc/template-core/fe/tailwind_ui.css'
|
|
|
1274
1374
|
|
|
1275
1375
|
/* 扫描项目源码 */
|
|
1276
1376
|
@source "./**/*.{js,ts,jsx,tsx}";
|
|
1277
|
-
@source "../
|
|
1377
|
+
@source "../models/**/*.{js,ts,jsx,tsx}";
|
|
1278
1378
|
```
|
|
1279
1379
|
|
|
1280
1380
|
Tailwind V4 默认会忽略 `node_modules` 和 `.gitignore` 中的文件。如果没有使用上面的 `tailwind_ui.css`,或者项目侧构建链路绕过了 TemplateCore 的样式入口,需要手动把包加入 Tailwind 扫描:
|
|
@@ -1284,7 +1384,7 @@ Tailwind V4 默认会忽略 `node_modules` 和 `.gitignore` 中的文件。如
|
|
|
1284
1384
|
@import "tailwindcss";
|
|
1285
1385
|
|
|
1286
1386
|
@source "./**/*.{js,ts,jsx,tsx}";
|
|
1287
|
-
@source "../
|
|
1387
|
+
@source "../models/**/*.{js,ts,jsx,tsx}";
|
|
1288
1388
|
@source "../node_modules/@_tc/template-core";
|
|
1289
1389
|
```
|
|
1290
1390
|
|
|
@@ -1478,7 +1578,7 @@ frontend/report/index.html yes
|
|
|
1478
1578
|
frontend/report/report.html yes
|
|
1479
1579
|
```
|
|
1480
1580
|
|
|
1481
|
-
不要在插槽文件里写 `<!DOCTYPE html>`、`<html>`、`<body>` 或 `<div id="root"></div>`。页面外壳由 TemplateCore 的 `app/view/entry.tpl` 统一生成,`window._basePath`、`window._projKey`、`window._signKey`、`window.appOptions` 也由它注入。
|
|
1581
|
+
不要在插槽文件里写 `<!DOCTYPE html>`、`<html>`、`<body>` 或 `<div id="root"></div>`。页面外壳由 TemplateCore 的 `app/view/entry.tpl` 统一生成,`window._basePath`、`window._projKey`、`window._signKey`、`window._renderMode`、`window._isSSR`、`window.appOptions` 也由它注入。
|
|
1482
1582
|
|
|
1483
1583
|
扩展 Dashboard 路由:
|
|
1484
1584
|
|
|
@@ -1579,12 +1679,12 @@ import { buildBE } from '@_tc/template-core/bundler'
|
|
|
1579
1679
|
|
|
1580
1680
|
await buildBE({
|
|
1581
1681
|
rootDir: process.cwd(),
|
|
1582
|
-
input: ['index.ts', 'index.js', 'app', 'config', '
|
|
1682
|
+
input: ['index.ts', 'index.js', 'app', 'config', 'models'],
|
|
1583
1683
|
outDir: 'dist',
|
|
1584
1684
|
format: 'cjs',
|
|
1585
1685
|
alias: {
|
|
1586
1686
|
'@app': './app',
|
|
1587
|
-
'@model': './
|
|
1687
|
+
'@model': './models',
|
|
1588
1688
|
},
|
|
1589
1689
|
})
|
|
1590
1690
|
```
|
|
@@ -1604,7 +1704,7 @@ await buildBE({
|
|
|
1604
1704
|
import chokidar from 'chokidar'
|
|
1605
1705
|
import { buildBE } from '@_tc/template-core/bundler'
|
|
1606
1706
|
|
|
1607
|
-
const input = ['index.ts', 'index.js', 'app', 'config', '
|
|
1707
|
+
const input = ['index.ts', 'index.js', 'app', 'config', 'models']
|
|
1608
1708
|
|
|
1609
1709
|
let building = false
|
|
1610
1710
|
let pending = false
|
|
@@ -1626,7 +1726,7 @@ async function runBuild() {
|
|
|
1626
1726
|
format: 'cjs',
|
|
1627
1727
|
alias: {
|
|
1628
1728
|
'@app': './app',
|
|
1629
|
-
'@model': './
|
|
1729
|
+
'@model': './models',
|
|
1630
1730
|
},
|
|
1631
1731
|
})
|
|
1632
1732
|
console.log('[buildBE] done')
|
|
@@ -1671,7 +1771,7 @@ chokidar
|
|
|
1671
1771
|
默认会在当前工作目录构建这些入口:
|
|
1672
1772
|
|
|
1673
1773
|
```ts
|
|
1674
|
-
['index.ts', 'index.js', 'app', 'config', '
|
|
1774
|
+
['index.ts', 'index.js', 'app', 'config', 'models']
|
|
1675
1775
|
```
|
|
1676
1776
|
|
|
1677
1777
|
不存在的默认入口会自动跳过;如果没有任何匹配源码,构建仍会失败。输出到 `dist`,格式为 `cjs`。默认 `outputStructure: "preserve"` 按源路径输出,`bundleDependencies: false` 会 external Node 内置模块和 npm 包,不会把依赖打进产物。`buildBE` 会按同一组 input 扫描并复制内置白名单资源扩展,主要覆盖 `app`、`config`、`model` 目录。
|
|
@@ -1680,12 +1780,12 @@ chokidar
|
|
|
1680
1780
|
|
|
1681
1781
|
```ts
|
|
1682
1782
|
await buildBE({
|
|
1683
|
-
input: ['app', 'config', '
|
|
1783
|
+
input: ['app', 'config', 'models'],
|
|
1684
1784
|
outDir: 'dist',
|
|
1685
1785
|
format: ['es', 'cjs'],
|
|
1686
1786
|
alias: {
|
|
1687
1787
|
'@app': './app',
|
|
1688
|
-
'@model': './
|
|
1788
|
+
'@model': './models',
|
|
1689
1789
|
},
|
|
1690
1790
|
})
|
|
1691
1791
|
```
|
|
@@ -1707,7 +1807,7 @@ await buildBE({
|
|
|
1707
1807
|
|
|
1708
1808
|
```ts
|
|
1709
1809
|
await buildBE({
|
|
1710
|
-
input: ['app', 'config', '
|
|
1810
|
+
input: ['app', 'config', 'models'],
|
|
1711
1811
|
allowMissingInput: true,
|
|
1712
1812
|
})
|
|
1713
1813
|
```
|
|
@@ -1743,8 +1843,8 @@ export default components
|
|
|
1743
1843
|
// frontend/extended/dash/routeGuard.ts
|
|
1744
1844
|
import type { DashRouteGuard } from '@_tc/template-core/fe'
|
|
1745
1845
|
|
|
1746
|
-
const dashRouteGuard: DashRouteGuard = ({ isLoggedIn }) => {
|
|
1747
|
-
if (!isLoggedIn) return '/login'
|
|
1846
|
+
const dashRouteGuard: DashRouteGuard = ({ isLoggedIn, isSSR }) => {
|
|
1847
|
+
if (!isLoggedIn) return isSSR ? '/login?from=ssr' : '/login'
|
|
1748
1848
|
}
|
|
1749
1849
|
|
|
1750
1850
|
export default dashRouteGuard
|
|
@@ -1754,6 +1854,7 @@ export default dashRouteGuard
|
|
|
1754
1854
|
|
|
1755
1855
|
- 返回 `string`:框架使用 `window.location.href` 跳转,登录页不需要在 Dash 路由下。
|
|
1756
1856
|
- 返回非 `string`:中断 Dashboard 内置重定向,使用方可自行跳转或处理提示。
|
|
1857
|
+
- 入参包含 `renderMode: 'csr' | 'ssr'` 和 `isSSR`,可区分 SSR hydration 后的守卫跳转和普通 CSR 跳转。
|
|
1757
1858
|
- `DashRouteGuardResult` 是 `string | undefined`;`undefined`(包括已登录分支的隐式返回)也会打断 Dashboard 内置重定向。
|
|
1758
1859
|
- 没有自定义 `routeGuard` 文件时,框架使用兜底空对象,不影响默认 Dashboard 重定向。
|
|
1759
1860
|
|
|
@@ -1830,9 +1931,9 @@ CallCom 是 SchemaPage 中的弹窗、抽屉、面板类组件。内置组件有
|
|
|
1830
1931
|
|
|
1831
1932
|
```ts
|
|
1832
1933
|
// typing/template-core.d.ts
|
|
1833
|
-
import '@_tc/template-core/
|
|
1934
|
+
import '@_tc/template-core/models'
|
|
1834
1935
|
|
|
1835
|
-
declare module '@_tc/template-core/
|
|
1936
|
+
declare module '@_tc/template-core/models' {
|
|
1836
1937
|
export namespace CallComNamespace {
|
|
1837
1938
|
interface ConfigMap {
|
|
1838
1939
|
auditPanel: {
|
|
@@ -1951,9 +2052,9 @@ cover: {
|
|
|
1951
2052
|
|
|
1952
2053
|
```ts
|
|
1953
2054
|
// typing/template-core.d.ts
|
|
1954
|
-
import '@_tc/template-core/
|
|
2055
|
+
import '@_tc/template-core/models'
|
|
1955
2056
|
|
|
1956
|
-
declare module '@_tc/template-core/
|
|
2057
|
+
declare module '@_tc/template-core/models' {
|
|
1957
2058
|
export namespace SchemaTableNamespace {
|
|
1958
2059
|
interface RenderComponentPropsMap {
|
|
1959
2060
|
PriceCell: {
|
|
@@ -2017,7 +2118,7 @@ price: {
|
|
|
2017
2118
|
|
|
2018
2119
|
```json
|
|
2019
2120
|
{
|
|
2020
|
-
"include": ["app/**/*", "
|
|
2121
|
+
"include": ["app/**/*", "models/**/*", "frontend/**/*", "typing/**/*.d.ts"]
|
|
2021
2122
|
}
|
|
2022
2123
|
```
|
|
2023
2124
|
|
|
@@ -2044,9 +2145,9 @@ declare module '@_tc/template-core/fe/rc' {
|
|
|
2044
2145
|
|
|
2045
2146
|
```ts
|
|
2046
2147
|
// typing/template-core.d.ts
|
|
2047
|
-
import '@_tc/template-core/
|
|
2148
|
+
import '@_tc/template-core/models'
|
|
2048
2149
|
|
|
2049
|
-
declare module '@_tc/template-core/
|
|
2150
|
+
declare module '@_tc/template-core/models' {
|
|
2050
2151
|
interface ModelModeMap {
|
|
2051
2152
|
portal: {
|
|
2052
2153
|
portalConfig: {
|
|
@@ -2061,7 +2162,7 @@ declare module '@_tc/template-core/model' {
|
|
|
2061
2162
|
使用新 `mode`:
|
|
2062
2163
|
|
|
2063
2164
|
```ts
|
|
2064
|
-
import type { ModelDataType } from '@_tc/template-core/
|
|
2165
|
+
import type { ModelDataType } from '@_tc/template-core/models'
|
|
2065
2166
|
|
|
2066
2167
|
const model: ModelDataType<'portal'> = {
|
|
2067
2168
|
mode: 'portal',
|
|
@@ -2080,7 +2181,7 @@ export default model
|
|
|
2080
2181
|
继续使用内置管理后台时:
|
|
2081
2182
|
|
|
2082
2183
|
```ts
|
|
2083
|
-
import type { ModelDataType } from '@_tc/template-core/
|
|
2184
|
+
import type { ModelDataType } from '@_tc/template-core/models'
|
|
2084
2185
|
|
|
2085
2186
|
const model: ModelDataType<'MB'> = {
|
|
2086
2187
|
mode: 'MB',
|
|
@@ -2096,7 +2197,7 @@ const model: ModelDataType<'MB'> = {
|
|
|
2096
2197
|
扩展目标:
|
|
2097
2198
|
|
|
2098
2199
|
```ts
|
|
2099
|
-
declare module '@_tc/template-core/
|
|
2200
|
+
declare module '@_tc/template-core/models' {
|
|
2100
2201
|
export namespace CallComNamespace {
|
|
2101
2202
|
interface ConfigMap {}
|
|
2102
2203
|
interface OptionMap {}
|
|
@@ -2113,7 +2214,7 @@ declare module '@_tc/template-core/model' {
|
|
|
2113
2214
|
扩展目标:
|
|
2114
2215
|
|
|
2115
2216
|
```ts
|
|
2116
|
-
declare module '@_tc/template-core/
|
|
2217
|
+
declare module '@_tc/template-core/models' {
|
|
2117
2218
|
export namespace SchemaTableNamespace {
|
|
2118
2219
|
interface RenderComponentPropsMap {}
|
|
2119
2220
|
}
|
|
@@ -2203,7 +2304,7 @@ cp -R node_modules/@_tc/template-core/.skills/tc-component-usage-skills "${CODEX
|
|
|
2203
2304
|
|
|
2204
2305
|
## 注意事项
|
|
2205
2306
|
|
|
2206
|
-
- 不要在项目代码里引用 `dist/fe/*`、`dist/
|
|
2307
|
+
- 不要在项目代码里引用 `dist/fe/*`、`dist/models/*` 这类构建产物路径。
|
|
2207
2308
|
- npm 使用方只使用公开入口:`@_tc/template-core/*`。
|
|
2208
2309
|
- SchemaForm 和 CallCom 的类型扩展、运行时注册都要做,少一个就只会“类型通过但页面不显示”或“页面能配但类型报错”。
|
|
2209
2310
|
- `model` 数组合并依赖稳定 `key`。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require(`../../_virtual/_rolldown/runtime.js`),t=require(`../../packages/common/ssr/hydration.js`),n=require(`../../ssrSharedData/outputPaths.js`),r=require(`../html/shell.js`),i=require(`../ssr/html.js`),a=require(`../ssr/manifest.js`);let o=require(`node:fs`);o=e.__toESM(o);let s=require(`node:path`);s=e.__toESM(s);let c=require(`node:stream`),l=require(`node:url`);var u=/^[A-Za-z0-9_-]+$/,d=1e4,f=3e4;function p(e){return e instanceof Error?e:Error(String(e))}async function m(e,t,n){let r=typeof e==`function`?await e(t):e;return r==null?n:String(r)}function h(e){e.compress=!1}function g(e,t,n={}){let r=new c.Writable({write(e,n,r){if(t.destroyed){r(Error(`SSR response stream is already closed.`));return}if(t.write(e,n)){r();return}t.once(`drain`,r)},final(e){if(t.destroyed){e();return}t.end(()=>{n.onComplete?.(),e()})},destroy(e,n){e&&!t.destroyed&&t.destroy(e),n()}});t.once(`close`,()=>{!t.readableEnded&&!r.destroyed&&(n.onAbort?.(),e.abort(Error(`SSR response stream closed before rendering completed.`)),r.destroy(Error(`SSR response stream closed before rendering completed.`)))}),t.once(`error`,t=>{n.onAbort?.(),e.abort(t),r.destroyed||r.destroy(t)}),r.once(`error`,()=>void 0),e.pipe(r)}var _=(e=>{function _(t){for(let r of e.publicsPath){let e=n.resolveSSRPrivateDir(r,t);if(o.default.existsSync(e))return e}return null}let v=new Map,y=new Map;function b(e){return typeof e==`string`&&u.test(e)}function x(e,t){let n=s.default.relative(t,e);return!!n&&!n.startsWith(`..`)&&!s.default.isAbsolute(n)}function S(e,t){if(!b(t))return null;let n=o.default.realpathSync(e);return[`${t}.mjs`,`${t}.js`].map(t=>s.default.resolve(e,t)).find(t=>!x(t,e)||!o.default.existsSync(t)?!1:x(o.default.realpathSync(t),n))??null}function C(e,t){let n=(0,l.pathToFileURL)(e);return n.searchParams.set(`t`,String(t)),n.href}async function w(e){let t=_(n.SSR_SERVER_OUT_DIR);if(!t)return null;let r=S(t,e);if(!r)return null;let i=o.default.statSync(r),a=v.get(e);if(a&&a.path===r&&a.mtime===i.mtimeMs)return a.module;let s=await import(C(r,i.mtimeMs));return v.set(e,{module:s,mtime:i.mtimeMs,path:r}),s}async function T(e){let t=_(n.SSR_MANIFEST_OUT_DIR);if(!t)return null;let r=s.default.resolve(t,n.SSR_CLIENT_MANIFEST_FILE);if(!o.default.existsSync(r))return null;let i=o.default.statSync(r),a=y.get(r);if(a&&a.mtime===i.mtimeMs)return a.manifest;let c=o.default.readFileSync(r,`utf-8`),l=JSON.parse(c);return y.set(r,{manifest:l,mtime:i.mtimeMs}),l}function E(t,n,r,a,o,s){h(t),t.status=r,t.type=`text/html`,t.body=i.renderSSRErrorHtml({app:e,ctx:t,page:n,status:r,title:a,message:o,error:s})}return class{async renderSSRPage(o,s){let l=o.params.page;if(h(o),!b(l)){E(o,String(l??`unknown`),404,`SSR page not found`,`The requested SSR page is not registered.`);return}e.extends.logger.log(` - SSR render: ${l}`);try{let s=await w(l);if(!s){e.extends.logger.log(` - SSR bundle not found: ${l}, falling back`),E(o,l,404,`SSR bundle not found`,`No server bundle was found for "${l}".`);return}let u=s.default,h=s.getServerProps,_={params:o.params,query:o.query,path:o.path,app:e,ctx:o},v={};typeof h==`function`&&(v=await h(_)??{});let y={..._,props:v},b=await m(s.pageTitle,y,l),x=await m(s.pageDescription,y,``),S=t.createHydrationData(v,{title:b,description:x,pathname:o.path}),C=t.serializeHydrationDataScriptContent(S),D=await T(l),O=a.findSSRClientEntry(D,l),k=a.generateSSRPreloadLinks(D,O),A=O?.file?`import(${r.serializeForHtmlScript(n.ssrClientAssetUrl(O.file))})`:void 0,j=await import(`react`),M=i.createSSRDocumentElement(j,{app:e,ctx:o,page:l,title:S.meta.title??l,description:S.meta.description??``,preloadLinks:k,hydrationScriptContent:C,appNode:j.createElement(u,v)}),{renderToPipeableStream:N}=await import(`react-dom/server`);await new Promise((t,n)=>{let r=null,i=null,a=!1,s=null,u=!1,m=null,h=null,_=()=>{m&&=(clearTimeout(m),null)},v=()=>{h&&=(clearTimeout(h),null)},y=e=>{let t=p(e);v(),r?.abort(t),i?.destroy(t)},b=()=>{u||(_(),u=!0,t())},x=e=>{u||(_(),v(),u=!0,n(e))};try{r=N(M,{bootstrapScriptContent:A,onShellReady(){if(s){r?.abort(s),x(s);return}let e=new c.PassThrough;i=e,o.body=e,o.type=`text/html`,a=!0,_(),h=setTimeout(()=>{y(Error(`SSR stream render timed out after ${f}ms.`))},f);try{g(r,e,{onAbort:v,onComplete:v}),b()}catch(t){e.destroy(p(t)),v(),x(t)}},onShellError(e){r?.abort(e),x(e)},onError(t){if(!a){s=t;return}e.extends.logger.log(` - SSR stream error after shell: ${l}`),console.error(`[SSR Stream Error]`,t),v(),y(t)}}),u||(m=setTimeout(()=>{let e=Error(`SSR shell render timed out after ${d}ms.`);r?.abort(e),x(e)},d))}catch(e){x(e)}})}catch(t){e.extends.logger.log(` - SSR render error: ${l}`),console.error(`[SSR Error]`,t),E(o,l,500,`SSR render error`,`The SSR page failed while loading data or rendering.`,t)}}}});module.exports=_;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`../../packages/common/string/index.js`);var
|
|
1
|
+
const e=require(`../../packages/common/string/index.js`),t=require(`../../packages/core/paths.js`);var n=e=>JSON.stringify(e).replace(/</g,`\\u003c`).replace(/>/g,`\\u003e`).replace(/&/g,`\\u0026`).replace(/\u2028/g,`\\u2028`).replace(/\u2029/g,`\\u2029`),r=(r=>class{async renderPage(i,a){let o=i.path;if(r.extends.localCacheHtmlEtag.keepFreshFEBuildKey(),o.includes(`${r.options.apiPrefix}/`))await a();else{r.extends.logger.log(` - render page: `+i.params.page);try{let a=i.query.projk;Array.isArray(a)&&(a=e.joinStr(...a));let o=t.normalizeRouteBasePath(r.options.pageBasePath)||`/`,s=o===`/`?`/${i.params.page}`:`${o}/${i.params.page}`,c={projKey:a??``,name:r.options?.name??``,env:r.envs.get(),FEBasePage:n(o),basePath:n(s),projKeyJson:n(String(i.query.projk??``)),signKey:n(r.config.signKey),options:n(r.options)},l=r.extends.renderView(`${i.params.page}.entry.tpl`,i,c),u=e.joinStr(c.basePath,c.name,c.env,c.projKey);if(!r.extends.localCacheHtmlEtag.hasEtag(u)){let e=r.extends.crypto.hmacSign(l);r.extends.localCacheHtmlEtag.setEtag(u,e)}let d=r.extends.localCacheHtmlEtag.getEtag(u);if(d||console.log(`---- etag 缓存异常 请检查服务 ----`),i.etag=d??Date.now()+``,i.set(`Cache-Control`,`public, max-age=${(r.config.resourceCacheTimeMs??300*1e3)/1e3}, immutable`),i.fresh){i.status=304;return}}catch(e){console.log(`-------------- render view error --------------`),console.log(e),r.extends.generateErrorMessage(`template not found`,{status:404,showError:!0,code:0})}}}});module.exports=r;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={head:`<!-- TC_SHARED_HEAD -->`,runtimeContext:`<!-- TC_RUNTIME_CONTEXT -->`},t=e=>JSON.stringify(e).replace(/</g,`\\u003c`).replace(/>/g,`\\u003e`).replace(/&/g,`\\u0026`).replace(/\u2028/g,`\\u2028`).replace(/\u2029/g,`\\u2029`);function n(e){return String(e).replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`).replace(/'/g,`'`)}function r(e){return n(e)}function i(){return`;(() => {
|
|
2
|
+
const storageKey = 'tc_theme'
|
|
3
|
+
let mode = 'dark'
|
|
4
|
+
|
|
5
|
+
try {
|
|
6
|
+
const storedMode = localStorage.getItem(storageKey)
|
|
7
|
+
if (storedMode === 'light' || storedMode === 'dark') {
|
|
8
|
+
mode = storedMode
|
|
9
|
+
}
|
|
10
|
+
} catch (error) {
|
|
11
|
+
// Keep the template default when localStorage is unavailable.
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const root = document.documentElement
|
|
15
|
+
root.classList.toggle('dark', mode === 'dark')
|
|
16
|
+
root.style.colorScheme = mode
|
|
17
|
+
})()`}function a(){return`<script>${i()}<\/script>`}function o({titleHtml:e,descriptionAttr:t,preloadLinks:n=``}){let r=typeof t==`string`?`\n <meta name="description" content="${t}" />`:``,i=n?`\n ${n}`:``;return` <meta charset="UTF-8" />
|
|
18
|
+
${a()}
|
|
19
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
20
|
+
<link rel="icon" type="image/x-icon" href="/static/logo.png" />
|
|
21
|
+
<title>${e}</title>${r}${i}`}function s(){return o({titleHtml:`{{ name }}`})}function c({basePathExpression:e,feBasePageExpression:t,projKeyExpression:n,signKeyExpression:r,renderModeExpression:i}){return`window['_basePath'] = ${e}
|
|
22
|
+
window['_FEBasePage'] = ${t}
|
|
23
|
+
window['_projKey'] = ${n}
|
|
24
|
+
window['_signKey'] = ${r}
|
|
25
|
+
window['_renderMode'] = ${i}
|
|
26
|
+
window['_isSSR'] = window['_renderMode'] === 'ssr'
|
|
27
|
+
const s = document.getElementById('input')
|
|
28
|
+
s.parentElement.removeChild(s)`}function l(){return`const appOptionsScript = document.getElementById('app-options-data')
|
|
29
|
+
window['appOptions'] = JSON.parse(appOptionsScript.textContent || '{}')
|
|
30
|
+
appOptionsScript.parentElement.removeChild(appOptionsScript)`}function u(e){return`<script id="input">
|
|
31
|
+
${c(e)}
|
|
32
|
+
<\/script>
|
|
33
|
+
<script type="application/json" id="app-options-data">${e.optionsJsonHtml}<\/script>
|
|
34
|
+
<script>
|
|
35
|
+
${l()}
|
|
36
|
+
<\/script>`}function d(){return u({basePathExpression:`{{basePath | safe}}`,feBasePageExpression:`{{FEBasePage | safe}}`,projKeyExpression:`{{projKeyJson | safe}}`,signKeyExpression:`{{signKey | safe}}`,renderModeExpression:t(`csr`),optionsJsonHtml:`{{ options | safe }}`})}function f(e,t,n){if(!e.includes(t))throw Error(`CSR entry template is missing shared shell marker: ${t}`);return e.replace(t,n)}function p(t){return f(f(t,e.head,s()),e.runtimeContext,d())}exports.applySharedCSRShellTemplate=p,exports.escapeHtml=n,exports.escapeHtmlAttr=r,exports.renderAppOptionsScriptContent=l,exports.renderCSRDocumentHeadTemplate=s,exports.renderCSRRuntimeContextScriptsTemplate=d,exports.renderDocumentHeadHtml=o,exports.renderRuntimeContextScriptsFromExpressions=u,exports.renderRuntimeInputScriptContentFromExpressions=c,exports.renderThemeScript=a,exports.renderThemeScriptContent=i,exports.serializeForHtmlScript=t,exports.sharedCSRShellMarkers=e;
|
package/cjs/app/middleware.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`../_virtual/_rolldown/runtime.js`);let
|
|
1
|
+
const e=require(`../_virtual/_rolldown/runtime.js`),t=require(`../ssrSharedData/outputPaths.js`);let n=require(`koa-compress`);n=e.__toESM(n);let r=require(`koa-bodyparser`);r=e.__toESM(r);let i=require(`koa-static`);i=e.__toESM(i);var a=(0,r.default)({formLimit:`1000mb`,enableTypes:[`form`,`json`,`text`]}),o=e=>{let r=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:e.config.resourceCacheTimeMs??300*1e3};e.use(e.middlewares.errorHandle),e.use((0,n.default)({threshold:2048}));let o=[`/dist/${t.SSR_SERVER_OUT_DIR}`,`/dist/.vite`];e.use(async(e,t)=>{if(o.some(t=>e.path===t||e.path.startsWith(`${t}/`))){e.status=404;return}await t()}),e.publicsPath.forEach(t=>e.use((0,i.default)(t,r))),e.use(a),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=o;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require(`../../packages/core/paths.js`);var t=(t,n)=>{let r=e.normalizeRouteBasePath(t.options.ssrPageBasePath,`/fessr`);n.level=1,n.get([`${r}/:page`,`${r}/:page/:rest(.*)`],t.controller.ssr.renderSSRPage.bind(t.controller.ssr))};module.exports=t;
|
package/cjs/app/router/view.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
const e=require(`../../packages/core/paths.js`);var t=(t,n)=>{let r=e.normalizeRouteBasePath(t.options.pageBasePath);n.level=2,n.get([`${r}/:page`,`${r}/:page/:r(.*)`],t.controller.view.renderPage.bind(t.controller.view))};module.exports=t;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../../packages/core/paths.js`),t=require(`../html/shell.js`);function n(...e){return`/${e.filter(Boolean).map(e=>e.replace(/^\/+|\/+$/g,``)).filter(Boolean).join(`/`)}`}function r(e){let t=e.query.projk;return Array.isArray(t)?t.join(``):String(t??``)}function i(i,a,o){let s=e.normalizeRouteBasePath(i.options.pageBasePath)||`/`,c=n(e.normalizeRouteBasePath(i.options.ssrPageBasePath,`/fessr`)||`/fessr`,o),l=r(a);return{basePathExpression:t.serializeForHtmlScript(c),feBasePageExpression:t.serializeForHtmlScript(s),projKeyExpression:t.serializeForHtmlScript(l),signKeyExpression:t.serializeForHtmlScript(i.config.signKey),renderModeExpression:t.serializeForHtmlScript(`ssr`),optionsJsonHtml:t.serializeForHtmlScript(i.options)}}function a(e,n,r){return t.renderRuntimeInputScriptContentFromExpressions(i(e,n,r))}function o(e,n,r){return t.renderRuntimeContextScriptsFromExpressions(i(e,n,r))}function s(e){let{app:t,ctx:n,page:r,hydrationScript:i=``,clientScript:a=``}=e;return{beforeAppHtml:`<!DOCTYPE html>
|
|
2
|
+
<html lang="en" class="dark" style="color-scheme: dark">
|
|
3
|
+
<head>
|
|
4
|
+
${c(e)}
|
|
5
|
+
</head>
|
|
6
|
+
${o(t,n,r)}
|
|
7
|
+
<body>
|
|
8
|
+
<div id="root">`,afterAppHtml:`</div>
|
|
9
|
+
${i}
|
|
10
|
+
${a}
|
|
11
|
+
</body>
|
|
12
|
+
</html>`}}function c(e){let{title:n,description:r=``,preloadLinks:i=``}=e;return t.renderDocumentHeadHtml({titleHtml:t.escapeHtml(n),descriptionAttr:t.escapeHtmlAttr(r),preloadLinks:i})}function l(e,n){let{app:r,ctx:i,page:o,appNode:s,hydrationScriptContent:l=``}=n;return e.createElement(`html`,{lang:`en`,className:`dark`,style:{colorScheme:`dark`}},e.createElement(`head`,{dangerouslySetInnerHTML:{__html:c(n)}}),e.createElement(`body`,null,e.createElement(`script`,{id:`input`,dangerouslySetInnerHTML:{__html:a(r,i,o)}}),e.createElement(`script`,{type:`application/json`,id:`app-options-data`,dangerouslySetInnerHTML:{__html:t.serializeForHtmlScript(r.options)}}),e.createElement(`script`,{dangerouslySetInnerHTML:{__html:t.renderAppOptionsScriptContent()}}),l?e.createElement(`script`,{dangerouslySetInnerHTML:{__html:l}}):null,e.createElement(`div`,{id:`root`},s)))}function u(e){let{appHtml:t,...n}=e,{beforeAppHtml:r,afterAppHtml:i}=s(n);return`${r}${t}${i}`}function d(e){let{app:n,ctx:r,page:i,status:a,title:o,message:s,error:c}=e,l=n.config.ssr?.exposeErrorDetails??n.envs.isLocal(),d=c instanceof Error?c.stack||c.message:String(c??``),f=l&&d?`<pre style="white-space:pre-wrap;margin-top:16px;padding:12px;border:1px solid #d8dee4;background:#f6f8fa;color:#24292f;overflow:auto">${t.escapeHtml(d)}</pre>`:``;return u({app:n,ctx:r,page:i,title:o,description:s,appHtml:`<main style="font-family:system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;max-width:720px;margin:72px auto;padding:0 24px;line-height:1.5;color:#24292f">
|
|
13
|
+
<p style="margin:0 0 8px;color:#57606a;font-size:14px">SSR ${a}</p>
|
|
14
|
+
<h1 style="margin:0 0 12px;font-size:28px;line-height:1.2">${t.escapeHtml(o)}</h1>
|
|
15
|
+
<p style="margin:0;color:#57606a">${t.escapeHtml(s)}</p>
|
|
16
|
+
${f}
|
|
17
|
+
</main>`})}exports.createSSRDocumentElement=l,exports.escapeHtml=t.escapeHtml,exports.escapeHtmlAttr=t.escapeHtmlAttr,exports.renderSSRErrorHtml=d,exports.renderSSRHtmlShell=u,exports.renderSSRHtmlShellParts=s,exports.serializeForHtmlScript=t.serializeForHtmlScript;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../../_virtual/_rolldown/runtime.js`),t=require(`../../ssrSharedData/outputPaths.js`);let n=require(`node:path`);n=e.__toESM(n);function r(e){return String(e).replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`).replace(/'/g,`'`)}function i(e,t,r){let i=t.split(n.default.sep).join(`/`),a=r.src?.split(n.default.sep).join(`/`);return[r.name,i,a].filter(e=>!!e).some(t=>{let r=t.split(n.default.sep).join(`/`),i=n.default.basename(r).replace(/\.entry\.[^.]+$/,``);return r===e||i===e||n.default.basename(n.default.dirname(r))===e})}function a(e,t){if(!e)return null;let n=Object.entries(e),r=n.find(([,e])=>e.isEntry&&e.name===t);if(r)return r[1];let a=n.find(([e,n])=>n.isEntry&&i(t,e,n));return a?a[1]:n.find(([e,n])=>i(t,e,n))?.[1]??null}function o(e,n){if(!e||!n)return``;let i=e,a=[],o=new Set,s=new Set;function c(e){o.has(e)||(o.add(e),a.push(`<link rel="modulepreload" href="${r(t.ssrClientAssetUrl(e))}" />`))}function l(e){o.has(e)||(o.add(e),a.push(`<link rel="stylesheet" href="${r(t.ssrClientAssetUrl(e))}" />`))}function u(e){if(!s.has(e)){s.add(e),e.file&&c(e.file);for(let t of e.css??[])l(t);for(let t of e.imports??[]){let e=i[t];e&&u(e)}}}return u(n),a.join(`
|
|
2
|
+
`)}exports.findSSRClientEntry=a,exports.generateSSRPreloadLinks=o;
|
package/cjs/app/view/entry.tpl
CHANGED
|
@@ -1,46 +1,11 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en" class="dark" style="color-scheme: dark">
|
|
3
3
|
<head>
|
|
4
|
-
|
|
5
|
-
<script>
|
|
6
|
-
;(() => {
|
|
7
|
-
const storageKey = 'tc_theme'
|
|
8
|
-
let mode = 'dark'
|
|
9
|
-
|
|
10
|
-
try {
|
|
11
|
-
const storedMode = localStorage.getItem(storageKey)
|
|
12
|
-
if (storedMode === 'light' || storedMode === 'dark') {
|
|
13
|
-
mode = storedMode
|
|
14
|
-
}
|
|
15
|
-
} catch (error) {
|
|
16
|
-
// Keep the template default when localStorage is unavailable.
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const root = document.documentElement
|
|
20
|
-
root.classList.toggle('dark', mode === 'dark')
|
|
21
|
-
root.style.colorScheme = mode
|
|
22
|
-
})()
|
|
23
|
-
</script>
|
|
24
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
25
|
-
<link rel="icon" type="image/x-icon" href="/static/logo.png" />
|
|
26
|
-
<title>{{ name }}</title>
|
|
4
|
+
<!-- TC_SHARED_HEAD -->
|
|
27
5
|
<!-- TC_HEAD_SLOT -->
|
|
28
6
|
</head>
|
|
29
7
|
|
|
30
|
-
|
|
31
|
-
window['_basePath'] = {{basePath | safe}}
|
|
32
|
-
window['_FEBasePage'] = {{FEBasePage | safe}}
|
|
33
|
-
window['_projKey'] = {{projKeyJson | safe}}
|
|
34
|
-
window['_signKey'] = {{signKey | safe}}
|
|
35
|
-
const s = document.getElementById('input')
|
|
36
|
-
s.parentElement.removeChild(s)
|
|
37
|
-
</script>
|
|
38
|
-
<script type="application/json" id="app-options-data">{{ options | safe }}</script>
|
|
39
|
-
<script>
|
|
40
|
-
const appOptionsScript = document.getElementById('app-options-data')
|
|
41
|
-
window['appOptions'] = JSON.parse(appOptionsScript.textContent || '{}')
|
|
42
|
-
appOptionsScript.parentElement.removeChild(appOptionsScript)
|
|
43
|
-
</script>
|
|
8
|
+
<!-- TC_RUNTIME_CONTEXT -->
|
|
44
9
|
|
|
45
10
|
<body>
|
|
46
11
|
<!-- TC_BODY_BEFORE_ROOT_SLOT -->
|
package/cjs/bundler/buildBE.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../scripts/vite-build/build.js`);require(`../scripts/vite-build/index.js`);var t=[`index.ts`,`index.js`,`app`,`config`,`
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../scripts/vite-build/build.js`);require(`../scripts/vite-build/index.js`);var t=[`index.ts`,`index.js`,`app`,`config`,`models`];async function n(n={}){return e.buildEntries({...n,rootDir:n.rootDir,input:n.input??t,outDir:n.outDir??`dist`,format:n.format??`cjs`,alias:n.alias,allowMissingInput:n.allowMissingInput??!n.input,outputStructure:n.outputStructure??`preserve`,bundleDependencies:n.bundleDependencies??!1,externalNodeBuiltins:n.externalNodeBuiltins??!0,dts:n.dts??!1,copy:n.copy??{input:n.input??t,extensions:{input:[`.tpl`,`.html`,`.css`,`.scss`,`.sass`,`.less`,`.svg`,`.png`,`.jpg`,`.jpeg`,`.gif`,`.webp`,`.ico`,`.json`,`.md`,`.txt`,`.xml`,`.yml`,`.yaml`],mergeDefault:!1}}})}exports.buildBE=n;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../_virtual/_rolldown/runtime.js`),t=require(`../packages/common/log/index.js`),n=require(`../ssrSharedData/outputPaths.js`),r=require(`./feSharedConfig.js`),i=require(`./ssrEntries.js`),a=require(`./state.js`),o=require(`./utils.js`);let s=require(`path`);s=e.__toESM(s);let c=require(`vite`);var l=r.createBundlerPaths();function u(e){return i.collectBundlerSSREntries(l,e)}function d(e){return n.resolveSSRServerOutDir({...e,frameNodePath:l.frameNodePath})}function f(e){return n.resolveSSRClientOutDir({...e,frameNodePath:l.frameNodePath})}function p(e){return n.resolveSSRManifestOutDir({...e,frameNodePath:l.frameNodePath})}async function m(e,n){t.logGreen(`[SSR] Building server bundle...`),await(0,c.build)({configFile:!1,plugins:r.createFEBasePlugins(),build:{outDir:d(n),emptyOutDir:!0,ssr:!0,rolldownOptions:{input:e,external:r.ssrReactExternal,output:{codeSplitting:{groups:o.createFECodeSplittingGroups()}}}},ssr:{external:r.ssrReactExternal,noExternal:r.createSSRNoExternal(l,n?.ssrNoExternal)},resolve:{alias:r.createSSRResolveAlias(l,n)}}),t.logGreen(`[SSR] Server bundle done.`)}async function h(e,n){t.logGreen(`[SSR] Building shared browser client bundle...`);let r={...a.buildFESharedState.options};a.setBuildFEOptions({...r,baseDir:n?.baseDir??r.baseDir,output:n?.output??r.output,minifyHtml:n?.minifyHtml??r.minifyHtml});try{await o.VBuildFE(o.entries(a.buildFESharedState.options),void 0,{ssrInput:e,ssrManifestOutDir:p(n)})}finally{a.setBuildFEOptions(r)}t.logGreen(`[SSR] Shared browser client bundle done.`)}async function g(e){let n=u(e);if(Object.keys(n).length)try{await m(n,e),await h(n,e),t.logGreen(`[SSR] All builds completed.`)}catch(e){throw t.logRed(`[SSR] Build failed:`),t.logRed(e),e}}async function _(e){let r=await import(`chokidar`),i=e?.debounceMs??200,a=s.default.resolve(n.resolveRunPath(e),`./ssr/apps`),o=[...new Set([l.frameSSRAppsPath,a])],c=r.watch(o,{ignored:e=>{let t=e.split(s.default.sep).join(`/`);return/(^|\/)\./.test(t)||/(^|\/)node_modules(\/|$)/.test(t)||/(^|\/)(dist|build|coverage)(\/|$)/.test(t)||/(^|\/)ssr-(server|client)(\/|$)/.test(t)},depth:8,persistent:!0,ignoreInitial:!0,usePolling:!0,interval:300}),u,d=!1,f=!1,p=async()=>{if(d){f=!0;return}d=!0;try{do{f=!1;try{await g(e)}catch(e){t.logRed(e)}}while(f)}finally{d=!1}},m=e=>{t.logYellow(`[SSR] changed: ${e}`),u&&clearTimeout(u),u=setTimeout(()=>{u=void 0,p()},i)};return c.on(`all`,(e,t)=>{[`add`,`change`,`unlink`,`unlinkDir`].includes(e)&&m(t)}),c.on(`error`,e=>{t.logRed(`[SSR] watcher error:`),t.logRed(e)}),t.logYellow(`[SSR] watching ${o.join(`, `)}/...`),c}exports.buildSSR=g,exports.ssrClientOutDir=f,exports.ssrEntries=u,exports.ssrManifestOutDir=p,exports.ssrServerOutDir=d,exports.watchSSRFiles=_;
|