@qlover/create-app 0.7.14 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/configs/_common/.gitignore.template +6 -0
  3. package/dist/configs/_common/.prettierignore +17 -5
  4. package/dist/configs/_common/.vscode/settings.json +6 -1
  5. package/dist/index.cjs +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/templates/next-app/.env.template +1 -1
  8. package/dist/templates/next-app/README.en.md +130 -0
  9. package/dist/templates/next-app/README.md +114 -20
  10. package/dist/templates/next-app/config/Identifier/api.ts +5 -5
  11. package/dist/templates/next-app/config/Identifier/common/admint.table.ts +69 -0
  12. package/dist/templates/next-app/config/Identifier/common/common.ts +76 -0
  13. package/dist/templates/next-app/config/Identifier/common/index.ts +3 -0
  14. package/dist/templates/next-app/config/Identifier/{validator.ts → common/validators.ts} +5 -5
  15. package/dist/templates/next-app/config/Identifier/index.ts +2 -12
  16. package/dist/templates/next-app/config/Identifier/pages/index.ts +6 -0
  17. package/dist/templates/next-app/config/Identifier/pages/page.admin.home.ts +27 -0
  18. package/dist/templates/next-app/config/Identifier/pages/page.admin.locales.ts +266 -0
  19. package/dist/templates/next-app/config/Identifier/pages/page.admin.user.ts +293 -0
  20. package/dist/templates/{react-app/config/Identifier → next-app/config/Identifier/pages}/page.home.ts +15 -22
  21. package/dist/templates/next-app/config/Identifier/{page.login.ts → pages/page.login.ts} +28 -34
  22. package/dist/templates/next-app/config/Identifier/{page.register.ts → pages/page.register.ts} +30 -29
  23. package/dist/templates/next-app/config/adminNavs.ts +19 -0
  24. package/dist/templates/next-app/config/common.ts +22 -13
  25. package/dist/templates/next-app/config/i18n/HomeI18n.ts +5 -5
  26. package/dist/templates/next-app/config/i18n/admin18n.ts +61 -19
  27. package/dist/templates/next-app/config/i18n/i18nConfig.ts +2 -0
  28. package/dist/templates/next-app/config/i18n/i18nKeyScheam.ts +36 -0
  29. package/dist/templates/next-app/config/i18n/loginI18n.ts +22 -22
  30. package/dist/templates/next-app/config/i18n/register18n.ts +23 -24
  31. package/dist/templates/next-app/docs/en/api.md +387 -0
  32. package/dist/templates/next-app/docs/en/component.md +544 -0
  33. package/dist/templates/next-app/docs/en/database.md +496 -0
  34. package/dist/templates/next-app/docs/en/development-guide.md +727 -0
  35. package/dist/templates/next-app/docs/en/env.md +563 -0
  36. package/dist/templates/next-app/docs/en/i18n.md +287 -0
  37. package/dist/templates/next-app/docs/en/index.md +165 -0
  38. package/dist/templates/next-app/docs/en/page.md +457 -0
  39. package/dist/templates/next-app/docs/en/project-structure.md +176 -0
  40. package/dist/templates/next-app/docs/en/router.md +427 -0
  41. package/dist/templates/next-app/docs/en/theme.md +532 -0
  42. package/dist/templates/next-app/docs/en/validator.md +478 -0
  43. package/dist/templates/next-app/docs/zh/api.md +387 -0
  44. package/dist/templates/next-app/docs/zh/component.md +544 -0
  45. package/dist/templates/next-app/docs/zh/database.md +496 -0
  46. package/dist/templates/next-app/docs/zh/development-guide.md +727 -0
  47. package/dist/templates/next-app/docs/zh/env.md +563 -0
  48. package/dist/templates/next-app/docs/zh/i18n.md +287 -0
  49. package/dist/templates/next-app/docs/zh/index.md +165 -0
  50. package/dist/templates/next-app/docs/zh/page.md +457 -0
  51. package/dist/templates/next-app/docs/zh/project-structure.md +176 -0
  52. package/dist/templates/next-app/docs/zh/router.md +427 -0
  53. package/dist/templates/next-app/docs/zh/theme.md +532 -0
  54. package/dist/templates/next-app/docs/zh/validator.md +476 -0
  55. package/dist/templates/next-app/make/generateLocales.ts +19 -12
  56. package/dist/templates/next-app/migrations/schema/LocalesSchema.ts +15 -0
  57. package/dist/templates/next-app/migrations/sql/1694244000000.sql +11 -0
  58. package/dist/templates/next-app/package.json +7 -3
  59. package/dist/templates/next-app/public/locales/en.json +172 -207
  60. package/dist/templates/next-app/public/locales/zh.json +172 -207
  61. package/dist/templates/next-app/src/app/[locale]/admin/locales/page.tsx +153 -0
  62. package/dist/templates/next-app/src/app/[locale]/admin/users/page.tsx +48 -50
  63. package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +2 -2
  64. package/dist/templates/next-app/src/app/api/admin/locales/create/route.ts +34 -0
  65. package/dist/templates/next-app/src/app/api/admin/locales/import/route.ts +40 -0
  66. package/dist/templates/next-app/src/app/api/admin/locales/route.ts +42 -0
  67. package/dist/templates/next-app/src/app/api/admin/locales/update/route.ts +32 -0
  68. package/dist/templates/next-app/src/app/api/locales/json/route.ts +44 -0
  69. package/dist/templates/next-app/src/base/cases/AdminPageManager.ts +1 -13
  70. package/dist/templates/next-app/src/base/cases/Datetime.ts +18 -0
  71. package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +12 -6
  72. package/dist/templates/next-app/src/base/cases/ResourceState.ts +17 -0
  73. package/dist/templates/next-app/src/base/cases/TranslateI18nInterface.ts +25 -0
  74. package/dist/templates/next-app/src/base/cases/ZodColumnBuilder.ts +200 -0
  75. package/dist/templates/next-app/src/base/port/ZodBuilderInterface.ts +8 -0
  76. package/dist/templates/next-app/src/base/services/AdminLocalesService.ts +20 -0
  77. package/dist/templates/next-app/src/base/services/AdminPageEvent.ts +26 -0
  78. package/dist/templates/next-app/src/base/services/AdminPageScheduler.ts +42 -0
  79. package/dist/templates/next-app/src/base/services/ResourceService.ts +122 -0
  80. package/dist/templates/next-app/src/base/services/adminApi/AdminLocalesApi.ts +104 -0
  81. package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +38 -5
  82. package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +1 -1
  83. package/dist/templates/next-app/src/i18n/request.ts +30 -1
  84. package/dist/templates/next-app/src/server/PageParams.ts +2 -10
  85. package/dist/templates/next-app/src/server/port/DBBridgeInterface.ts +5 -0
  86. package/dist/templates/next-app/src/server/port/DBTableInterface.ts +2 -0
  87. package/dist/templates/next-app/src/server/port/LocalesRepositoryInterface.ts +43 -0
  88. package/dist/templates/next-app/src/server/repositorys/LocalesRepository.ts +197 -0
  89. package/dist/templates/next-app/src/server/services/ApiLocaleService.ts +122 -0
  90. package/dist/templates/next-app/src/server/sqlBridges/SupabaseBridge.ts +60 -11
  91. package/dist/templates/next-app/src/server/validators/ExtendedExecutorError.ts +6 -0
  92. package/dist/templates/next-app/src/server/validators/LocalesValidator.ts +131 -0
  93. package/dist/templates/next-app/src/server/validators/LoginValidator.ts +2 -5
  94. package/dist/templates/next-app/src/server/validators/PaginationValidator.ts +32 -16
  95. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/_default.css +2 -1
  96. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/dark.css +28 -29
  97. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/pink.css +2 -1
  98. package/dist/templates/next-app/src/uikit/components/AdminLayout.tsx +17 -3
  99. package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +5 -4
  100. package/dist/templates/next-app/src/uikit/components/BaseLayout.tsx +5 -4
  101. package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +3 -2
  102. package/dist/templates/next-app/src/uikit/components/ComboProvider.tsx +1 -1
  103. package/dist/templates/next-app/src/uikit/components/EditableCell.tsx +118 -0
  104. package/dist/templates/next-app/src/uikit/components/LogoutButton.tsx +5 -6
  105. package/dist/templates/next-app/src/uikit/components/ThemeSwitcher.tsx +1 -1
  106. package/dist/templates/next-app/src/uikit/components/With.tsx +2 -2
  107. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportButton.tsx +62 -0
  108. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportEvent.ts +28 -0
  109. package/dist/templates/next-app/src/uikit/components/localesImportButton/import.module.css +6 -0
  110. package/dist/templates/next-app/src/uikit/hook/useI18nInterface.ts +8 -14
  111. package/dist/templates/next-app/src/uikit/hook/useWarnTranslations.ts +25 -0
  112. package/dist/templates/react-app/.prettierignore +17 -0
  113. package/dist/templates/react-app/README.en.md +71 -54
  114. package/dist/templates/react-app/README.md +35 -18
  115. package/dist/templates/react-app/__tests__/__mocks__/BootstrapTest.ts +14 -0
  116. package/dist/templates/react-app/__tests__/__mocks__/MockAppConfit.ts +1 -1
  117. package/dist/templates/react-app/__tests__/__mocks__/MockDialogHandler.ts +2 -2
  118. package/dist/templates/react-app/__tests__/__mocks__/MockLogger.ts +1 -1
  119. package/dist/templates/react-app/__tests__/__mocks__/components/TestApp.tsx +45 -0
  120. package/dist/templates/react-app/__tests__/__mocks__/components/TestBootstrapsProvider.tsx +34 -0
  121. package/dist/templates/react-app/__tests__/__mocks__/components/TestRouter.tsx +46 -0
  122. package/dist/templates/react-app/__tests__/__mocks__/components/index.ts +12 -0
  123. package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +1 -2
  124. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOC.ts +51 -0
  125. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOCRegister.ts +69 -0
  126. package/dist/templates/react-app/__tests__/setup/index.ts +1 -51
  127. package/dist/templates/react-app/__tests__/setup/setupGlobal.ts +51 -0
  128. package/dist/templates/react-app/__tests__/src/App.structure.test.tsx +115 -0
  129. package/dist/templates/react-app/__tests__/src/base/cases/AppConfig.test.ts +2 -2
  130. package/dist/templates/react-app/__tests__/src/base/cases/AppError.test.ts +1 -1
  131. package/dist/templates/react-app/__tests__/src/base/cases/DialogHandler.test.ts +3 -5
  132. package/dist/templates/react-app/__tests__/src/base/cases/I18nKeyErrorPlugin.test.ts +13 -2
  133. package/dist/templates/react-app/__tests__/src/base/cases/InversifyContainer.test.ts +1 -1
  134. package/dist/templates/react-app/__tests__/src/base/cases/PublicAssetsPath.test.ts +1 -1
  135. package/dist/templates/react-app/__tests__/src/base/cases/RequestLogger.test.ts +5 -5
  136. package/dist/templates/react-app/__tests__/src/base/cases/RequestStatusCatcher.test.ts +1 -2
  137. package/dist/templates/react-app/__tests__/src/base/cases/RouterLoader.test.ts +25 -15
  138. package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +29 -15
  139. package/dist/templates/react-app/__tests__/src/core/IOC.test.ts +19 -9
  140. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapClient.test.ts +153 -0
  141. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapsApp.test.ts +9 -7
  142. package/dist/templates/react-app/__tests__/src/main.integration.test.tsx +4 -5
  143. package/dist/templates/react-app/__tests__/src/main.test.tsx +4 -4
  144. package/dist/templates/react-app/__tests__/src/uikit/components/BaseHeader.test.tsx +68 -59
  145. package/dist/templates/react-app/config/IOCIdentifier.ts +8 -8
  146. package/dist/templates/react-app/config/Identifier/{common.error.ts → common/common.error.ts} +5 -5
  147. package/dist/templates/react-app/config/Identifier/{common.ts → common/common.ts} +9 -9
  148. package/dist/templates/react-app/config/Identifier/common/index.ts +2 -0
  149. package/dist/templates/react-app/config/Identifier/index.ts +1 -9
  150. package/dist/templates/react-app/config/Identifier/pages/index.ts +8 -0
  151. package/dist/templates/react-app/config/Identifier/{page.about.ts → pages/page.about.ts} +34 -26
  152. package/dist/templates/react-app/config/Identifier/{page.executor.ts → pages/page.executor.ts} +47 -39
  153. package/dist/templates/{next-app/config/Identifier → react-app/config/Identifier/pages}/page.home.ts +24 -23
  154. package/dist/templates/react-app/config/Identifier/pages/page.identifiter.ts +102 -0
  155. package/dist/templates/react-app/config/Identifier/{page.jsonStorage.ts → pages/page.jsonStorage.ts} +18 -11
  156. package/dist/templates/react-app/config/Identifier/{page.login.ts → pages/page.login.ts} +37 -27
  157. package/dist/templates/react-app/config/Identifier/{page.register.ts → pages/page.register.ts} +37 -25
  158. package/dist/templates/react-app/config/Identifier/{page.request.ts → pages/page.request.ts} +34 -44
  159. package/dist/templates/react-app/config/app.router.ts +66 -69
  160. package/dist/templates/react-app/config/i18n/PageI18nInterface.ts +51 -0
  161. package/dist/templates/react-app/config/i18n/aboutI18n.ts +42 -0
  162. package/dist/templates/react-app/config/i18n/executorI18n.ts +51 -0
  163. package/dist/templates/react-app/config/i18n/homeI18n.ts +24 -0
  164. package/dist/templates/react-app/config/i18n/i18nConfig.ts +30 -0
  165. package/dist/templates/react-app/config/i18n/identifiter18n.ts +30 -0
  166. package/dist/templates/react-app/config/i18n/jsonStorage18n.ts +27 -0
  167. package/dist/templates/react-app/config/i18n/login18n.ts +42 -0
  168. package/dist/templates/react-app/config/i18n/notFoundI18n.ts +34 -0
  169. package/dist/templates/react-app/config/i18n/register18n.ts +40 -0
  170. package/dist/templates/react-app/config/i18n/request18n.ts +41 -0
  171. package/dist/templates/react-app/config/theme.ts +14 -4
  172. package/dist/templates/react-app/docs/en/bootstrap.md +1670 -341
  173. package/dist/templates/react-app/docs/en/development-guide.md +1021 -345
  174. package/dist/templates/react-app/docs/en/env.md +1132 -278
  175. package/dist/templates/react-app/docs/en/i18n.md +858 -147
  176. package/dist/templates/react-app/docs/en/index.md +733 -104
  177. package/dist/templates/react-app/docs/en/ioc.md +1228 -287
  178. package/dist/templates/react-app/docs/en/playwright/e2e-tests.md +321 -0
  179. package/dist/templates/react-app/docs/en/playwright/index.md +19 -0
  180. package/dist/templates/react-app/docs/en/playwright/installation-summary.md +332 -0
  181. package/dist/templates/react-app/docs/en/playwright/overview.md +222 -0
  182. package/dist/templates/react-app/docs/en/playwright/quickstart.md +325 -0
  183. package/dist/templates/react-app/docs/en/playwright/reorganization-notes.md +340 -0
  184. package/dist/templates/react-app/docs/en/playwright/setup-complete.md +290 -0
  185. package/dist/templates/react-app/docs/en/playwright/testing-guide.md +565 -0
  186. package/dist/templates/react-app/docs/en/store.md +1194 -184
  187. package/dist/templates/react-app/docs/en/why-no-globals.md +797 -0
  188. package/dist/templates/react-app/docs/zh/bootstrap.md +1670 -341
  189. package/dist/templates/react-app/docs/zh/development-guide.md +1021 -345
  190. package/dist/templates/react-app/docs/zh/env.md +1132 -275
  191. package/dist/templates/react-app/docs/zh/i18n.md +858 -147
  192. package/dist/templates/react-app/docs/zh/index.md +717 -104
  193. package/dist/templates/react-app/docs/zh/ioc.md +1229 -287
  194. package/dist/templates/react-app/docs/zh/playwright/e2e-tests.md +321 -0
  195. package/dist/templates/react-app/docs/zh/playwright/index.md +19 -0
  196. package/dist/templates/react-app/docs/zh/playwright/installation-summary.md +332 -0
  197. package/dist/templates/react-app/docs/zh/playwright/overview.md +222 -0
  198. package/dist/templates/react-app/docs/zh/playwright/quickstart.md +325 -0
  199. package/dist/templates/react-app/docs/zh/playwright/reorganization-notes.md +340 -0
  200. package/dist/templates/react-app/docs/zh/playwright/setup-complete.md +290 -0
  201. package/dist/templates/react-app/docs/zh/playwright/testing-guide.md +565 -0
  202. package/dist/templates/react-app/docs/zh/store.md +1192 -184
  203. package/dist/templates/react-app/docs/zh/why-no-globals.md +797 -0
  204. package/dist/templates/react-app/e2e/App.spec.ts +319 -0
  205. package/dist/templates/react-app/e2e/fixtures/base.fixture.ts +40 -0
  206. package/dist/templates/react-app/e2e/main.spec.ts +20 -0
  207. package/dist/templates/react-app/e2e/utils/test-helpers.ts +19 -0
  208. package/dist/templates/react-app/eslint.config.mjs +247 -0
  209. package/dist/templates/react-app/makes/eslint-utils.mjs +195 -0
  210. package/dist/templates/react-app/makes/generateTs2LocalesOptions.ts +26 -0
  211. package/dist/templates/react-app/package.json +31 -3
  212. package/dist/templates/react-app/playwright.config.ts +79 -0
  213. package/dist/templates/react-app/public/locales/en/common.json +190 -179
  214. package/dist/templates/react-app/public/locales/zh/common.json +190 -179
  215. package/dist/templates/react-app/src/App.tsx +15 -42
  216. package/dist/templates/react-app/src/base/apis/AiApi.ts +5 -5
  217. package/dist/templates/react-app/src/base/apis/feApi/FeApi.ts +1 -1
  218. package/dist/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +1 -1
  219. package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +8 -8
  220. package/dist/templates/react-app/src/base/apis/feApi/FeApiType.ts +1 -1
  221. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +6 -6
  222. package/dist/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +1 -1
  223. package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +12 -14
  224. package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +1 -1
  225. package/dist/templates/react-app/src/base/cases/DialogHandler.ts +5 -2
  226. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +3 -3
  227. package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +3 -3
  228. package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +2 -2
  229. package/dist/templates/react-app/src/base/cases/RequestLogger.ts +4 -4
  230. package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +1 -1
  231. package/dist/templates/react-app/src/base/cases/ResourceState.ts +23 -0
  232. package/dist/templates/react-app/src/base/cases/RouterLoader.ts +4 -4
  233. package/dist/templates/react-app/src/base/cases/TranslateI18nInterface.ts +26 -0
  234. package/dist/templates/react-app/src/base/port/ExecutorPageBridgeInterface.ts +2 -3
  235. package/dist/templates/react-app/src/base/port/I18nServiceInterface.ts +1 -1
  236. package/dist/templates/react-app/src/base/port/IOCInterface.ts +36 -0
  237. package/dist/templates/react-app/src/base/port/JSONStoragePageBridgeInterface.ts +2 -1
  238. package/dist/templates/react-app/src/base/port/ProcesserExecutorInterface.ts +1 -1
  239. package/dist/templates/react-app/src/base/port/RequestPageBridgeInterface.ts +2 -2
  240. package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +9 -5
  241. package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +1 -1
  242. package/dist/templates/react-app/src/base/services/I18nService.ts +29 -29
  243. package/dist/templates/react-app/src/base/services/IdentifierService.ts +143 -0
  244. package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +3 -3
  245. package/dist/templates/react-app/src/base/services/RouteService.ts +27 -8
  246. package/dist/templates/react-app/src/base/services/UserService.ts +8 -8
  247. package/dist/templates/react-app/src/base/types/Page.ts +14 -2
  248. package/dist/templates/react-app/src/base/types/global.d.ts +1 -1
  249. package/dist/templates/react-app/src/core/IOC.ts +5 -46
  250. package/dist/templates/react-app/src/core/bootstraps/{BootstrapApp.ts → BootstrapClient.ts} +44 -17
  251. package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +14 -7
  252. package/dist/templates/react-app/src/core/bootstraps/IocIdentifierTest.ts +1 -1
  253. package/dist/templates/react-app/src/core/bootstraps/PrintBootstrap.ts +1 -1
  254. package/dist/templates/react-app/src/core/clientIoc/ClientIOC.ts +40 -0
  255. package/dist/templates/react-app/src/core/{IocRegisterImpl.ts → clientIoc/ClientIOCRegister.ts} +35 -24
  256. package/dist/templates/react-app/src/core/globals.ts +9 -9
  257. package/dist/templates/react-app/src/main.tsx +4 -4
  258. package/dist/templates/react-app/src/pages/404.tsx +6 -3
  259. package/dist/templates/react-app/src/pages/500.tsx +5 -2
  260. package/dist/templates/react-app/src/pages/NoRouteFound.tsx +5 -0
  261. package/dist/templates/react-app/src/pages/auth/Layout.tsx +9 -6
  262. package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +46 -56
  263. package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +46 -58
  264. package/dist/templates/react-app/src/pages/base/AboutPage.tsx +35 -40
  265. package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +51 -51
  266. package/dist/templates/react-app/src/pages/base/HomePage.tsx +14 -15
  267. package/dist/templates/react-app/src/pages/base/IdentifierPage.tsx +70 -11
  268. package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +24 -25
  269. package/dist/templates/react-app/src/pages/base/Layout.tsx +2 -2
  270. package/dist/templates/react-app/src/pages/base/RedirectPathname.tsx +3 -2
  271. package/dist/templates/react-app/src/pages/base/RequestPage.tsx +41 -59
  272. package/dist/templates/react-app/src/styles/css/antd-themes/{_default.css → _common/_default.css} +85 -0
  273. package/dist/templates/react-app/src/styles/css/antd-themes/{dark.css → _common/dark.css} +99 -0
  274. package/dist/templates/react-app/src/styles/css/antd-themes/_common/index.css +3 -0
  275. package/dist/templates/react-app/src/styles/css/antd-themes/{pink.css → _common/pink.css} +86 -0
  276. package/dist/templates/react-app/src/styles/css/antd-themes/index.css +4 -3
  277. package/dist/templates/react-app/src/styles/css/antd-themes/menu/_default.css +108 -0
  278. package/dist/templates/react-app/src/styles/css/antd-themes/menu/dark.css +67 -0
  279. package/dist/templates/react-app/src/styles/css/antd-themes/menu/index.css +3 -0
  280. package/dist/templates/react-app/src/styles/css/antd-themes/menu/pink.css +67 -0
  281. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/_default.css +34 -0
  282. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/dark.css +31 -0
  283. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/index.css +3 -0
  284. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/pink.css +36 -0
  285. package/dist/templates/react-app/src/styles/css/antd-themes/table/_default.css +44 -0
  286. package/dist/templates/react-app/src/styles/css/antd-themes/table/dark.css +43 -0
  287. package/dist/templates/react-app/src/styles/css/antd-themes/table/index.css +3 -0
  288. package/dist/templates/react-app/src/styles/css/antd-themes/table/pink.css +43 -0
  289. package/dist/templates/react-app/src/styles/css/page.css +4 -3
  290. package/dist/templates/react-app/src/styles/css/themes/_default.css +1 -0
  291. package/dist/templates/react-app/src/styles/css/themes/dark.css +1 -0
  292. package/dist/templates/react-app/src/styles/css/themes/pink.css +1 -0
  293. package/dist/templates/react-app/src/styles/css/zIndex.css +1 -1
  294. package/dist/templates/react-app/src/uikit/bridges/ExecutorPageBridge.ts +3 -3
  295. package/dist/templates/react-app/src/uikit/bridges/JSONStoragePageBridge.ts +2 -2
  296. package/dist/templates/react-app/src/uikit/bridges/NavigateBridge.ts +1 -1
  297. package/dist/templates/react-app/src/uikit/bridges/RequestPageBridge.ts +3 -3
  298. package/dist/templates/react-app/src/uikit/components/AppRouterProvider.tsx +35 -0
  299. package/dist/templates/react-app/src/uikit/components/BaseHeader.tsx +15 -11
  300. package/dist/templates/react-app/src/uikit/components/BaseRouteProvider.tsx +14 -11
  301. package/dist/templates/react-app/src/uikit/components/BaseRouteSeo.tsx +18 -0
  302. package/dist/templates/react-app/src/uikit/components/BootstrapsProvider.tsx +13 -0
  303. package/dist/templates/react-app/src/uikit/components/ClientSeo.tsx +62 -0
  304. package/dist/templates/react-app/src/uikit/components/ComboProvider.tsx +38 -0
  305. package/dist/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +48 -27
  306. package/dist/templates/react-app/src/uikit/components/Loading.tsx +4 -2
  307. package/dist/templates/react-app/src/uikit/components/LocaleLink.tsx +4 -5
  308. package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +34 -11
  309. package/dist/templates/react-app/src/uikit/components/ProcessExecutorProvider.tsx +9 -5
  310. package/dist/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +6 -3
  311. package/dist/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +97 -40
  312. package/dist/templates/react-app/src/uikit/components/UserAuthProvider.tsx +5 -5
  313. package/dist/templates/react-app/src/uikit/components/With.tsx +17 -0
  314. package/dist/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +17 -11
  315. package/dist/templates/react-app/src/uikit/contexts/IOCContext.ts +13 -0
  316. package/dist/templates/react-app/src/uikit/hooks/useAppTranslation.ts +26 -0
  317. package/dist/templates/react-app/src/uikit/hooks/useI18nGuard.ts +8 -11
  318. package/dist/templates/react-app/src/uikit/hooks/useI18nInterface.ts +25 -0
  319. package/dist/templates/react-app/src/uikit/hooks/useIOC.ts +35 -0
  320. package/dist/templates/react-app/src/uikit/hooks/useNavigateBridge.ts +3 -3
  321. package/dist/templates/react-app/src/uikit/hooks/useStrictEffect.ts +0 -1
  322. package/dist/templates/react-app/tsconfig.e2e.json +21 -0
  323. package/dist/templates/react-app/tsconfig.json +8 -1
  324. package/dist/templates/react-app/tsconfig.node.json +1 -1
  325. package/dist/templates/react-app/tsconfig.test.json +3 -1
  326. package/dist/templates/react-app/vite.config.ts +50 -34
  327. package/package.json +2 -1
  328. package/dist/configs/react-app/eslint.config.js +0 -94
  329. package/dist/templates/next-app/config/Identifier/common.error.ts +0 -41
  330. package/dist/templates/next-app/config/Identifier/common.ts +0 -69
  331. package/dist/templates/next-app/config/Identifier/page.about.ts +0 -181
  332. package/dist/templates/next-app/config/Identifier/page.admin.ts +0 -48
  333. package/dist/templates/next-app/config/Identifier/page.executor.ts +0 -272
  334. package/dist/templates/next-app/config/Identifier/page.identifiter.ts +0 -39
  335. package/dist/templates/next-app/config/Identifier/page.jsonStorage.ts +0 -72
  336. package/dist/templates/next-app/config/Identifier/page.request.ts +0 -182
  337. package/dist/templates/next-app/docs/env.md +0 -94
  338. package/dist/templates/next-app/src/base/cases/ChatAction.ts +0 -21
  339. package/dist/templates/next-app/src/base/cases/FocusBarAction.ts +0 -36
  340. package/dist/templates/next-app/src/base/cases/RequestState.ts +0 -20
  341. package/dist/templates/next-app/src/base/port/AdminPageInterface.ts +0 -85
  342. package/dist/templates/next-app/src/base/port/AsyncStateInterface.ts +0 -7
  343. package/dist/templates/next-app/src/base/services/AdminUserService.ts +0 -45
  344. package/dist/templates/next-app/src/uikit/components/ChatRoot.tsx +0 -17
  345. package/dist/templates/next-app/src/uikit/components/chat/ChatActionInterface.ts +0 -30
  346. package/dist/templates/next-app/src/uikit/components/chat/ChatFocusBar.tsx +0 -65
  347. package/dist/templates/next-app/src/uikit/components/chat/ChatMessages.tsx +0 -59
  348. package/dist/templates/next-app/src/uikit/components/chat/ChatWrap.tsx +0 -28
  349. package/dist/templates/next-app/src/uikit/components/chat/FocusBarActionInterface.ts +0 -19
  350. package/dist/templates/next-app/src/uikit/hook/useMountedClient.ts +0 -17
  351. package/dist/templates/next-app/src/uikit/hook/useStore.ts +0 -15
  352. package/dist/templates/react-app/__tests__/__mocks__/I18nService.ts +0 -13
  353. package/dist/templates/react-app/__tests__/src/App.test.tsx +0 -139
  354. package/dist/templates/react-app/config/Identifier/page.identifiter.ts +0 -39
  355. package/dist/templates/react-app/config/i18n.ts +0 -15
  356. package/dist/templates/react-app/docs/en/project-structure.md +0 -434
  357. package/dist/templates/react-app/docs/zh/project-structure.md +0 -434
  358. package/dist/templates/react-app/src/base/cases/RequestState.ts +0 -20
  359. package/dist/templates/react-app/src/base/port/AsyncStateInterface.ts +0 -7
  360. package/dist/templates/react-app/src/uikit/hooks/useDocumentTitle.ts +0 -15
  361. package/dist/templates/react-app/src/uikit/hooks/useStore.ts +0 -15
@@ -1,120 +1,328 @@
1
- # 环境变量注入
1
+ # 环境变量管理
2
2
 
3
- ## 什么是环境变量注入?
3
+ ## 📋 目录
4
4
 
5
- 环境变量注入是 Bootstrap 的一个重要功能,它允许我们将环境变量自动注入到应用配置中,实现配置的集中管理和环境隔离。
5
+ - [什么是环境变量管理](#-什么是环境变量管理)
6
+ - [为什么需要环境变量](#-为什么需要环境变量)
7
+ - [工作原理](#-工作原理)
8
+ - [项目中的实现](#-项目中的实现)
9
+ - [多环境配置](#-多环境配置)
10
+ - [环境变量注入](#-环境变量注入)
11
+ - [AppConfig 使用](#-appconfig-使用)
12
+ - [高级用法](#-高级用法)
13
+ - [测试配置](#-测试配置)
14
+ - [最佳实践](#-最佳实践)
15
+ - [常见问题](#-常见问题)
6
16
 
7
- **简单来说**:就像给应用穿上不同的衣服一样,根据不同的环境(开发、测试、生产),应用会使用不同的配置。
17
+ ---
8
18
 
9
- ## 工作原理
19
+ ## 🎯 什么是环境变量管理
10
20
 
11
- ### 1. 环境变量加载流程
21
+ 环境变量管理是 Bootstrap 架构的核心组成部分,负责在不同环境(开发、测试、生产)中使用不同的配置,并通过 **自动注入** 的方式将配置传递给应用。
22
+
23
+ ### 核心流程
12
24
 
13
25
  ```
14
- 应用启动Bootstrap 初始化InjectEnv 插件加载环境变量注入到 AppConfig应用使用配置
26
+ 启动应用Vite 加载 .env 文件 Bootstrap 初始化注入环境变量到 AppConfig IOC 容器应用使用
15
27
  ```
16
28
 
17
- ### 2. 核心技术栈
29
+ ### 关键概念
30
+
31
+ ```
32
+ ┌─────────────────────────────────────────────────┐
33
+ │ 环境变量管理系统 │
34
+ │ ┌───────────────────────────────────────────┐ │
35
+ │ │ 1. Vite --mode 选择环境 │ │
36
+ │ │ 2. 加载对应的 .env 文件 │ │
37
+ │ │ 3. envConfig 插件预处理 │ │
38
+ │ │ 4. Bootstrap 注入到 AppConfig │ │
39
+ │ │ 5. 注册到 IOC 容器 │ │
40
+ │ │ 6. 应用通过 IOC 获取配置 │ │
41
+ │ └───────────────────────────────────────────┘ │
42
+ └─────────────────────────────────────────────────┘
43
+ ```
18
44
 
19
- - **@qlover/env-loader**:环境变量加载器
20
- - **@qlover/corekit-bridge/vite-env-config**:Vite 环境变量配置插件
21
- - **dotenv**:.env 文件解析
22
- - **Vite**:前端构建工具
45
+ ---
23
46
 
24
- ### 3. 文件结构
47
+ ## 🤔 为什么需要环境变量
25
48
 
49
+ ### 问题:硬编码配置的痛点
50
+
51
+ #### ❌ 传统方式:配置散落各处
52
+
53
+ ```typescript
54
+ // ❌ 问题 1:API 地址硬编码在代码中
55
+ function fetchUserInfo() {
56
+ // 😰 开发环境和生产环境的 API 地址不同,每次切换都要改代码
57
+ return fetch('http://localhost:3000/api/user');
58
+ }
59
+
60
+ // ❌ 问题 2:配置散落在各个文件
61
+ function saveToken(token: string) {
62
+ // 😰 存储键名硬编码,难以统一管理
63
+ localStorage.setItem('user_token', token);
64
+ }
65
+
66
+ // ❌ 问题 3:敏感信息直接写在代码中
67
+ function callAI(prompt: string) {
68
+ // 😰 API Key 直接暴露在代码中,存在安全风险
69
+ return fetch('https://api.openai.com/v1/chat', {
70
+ headers: {
71
+ Authorization: 'Bearer sk-xxxxxxxxxxxx' // 😰 危险!
72
+ }
73
+ });
74
+ }
75
+
76
+ // ❌ 问题 4:环境切换困难
77
+ if (window.location.host === 'localhost:3000') {
78
+ // 😰 需要手动判断环境
79
+ apiUrl = 'http://localhost:3000/api';
80
+ } else if (window.location.host === 'staging.example.com') {
81
+ apiUrl = 'https://api.staging.example.com';
82
+ } else {
83
+ apiUrl = 'https://api.production.com';
84
+ }
26
85
  ```
27
- 项目根目录/
28
- ├── .env # 默认环境变量
29
- ├── .env.local # 本地环境变量(git ignored)
30
- ├── .env.development # 开发环境变量
31
- ├── .env.production # 生产环境变量
32
- ├── .env.staging # 测试环境变量
33
- ├── vite.config.ts # Vite 配置
34
- └── src/
35
- └── base/
36
- └── cases/
37
- └── AppConfig.ts # 应用配置类
86
+
87
+ **问题总结:**
88
+
89
+ - 😰 **配置散落** - 配置分散在多个文件中,难以管理
90
+ - 😰 **环境切换困难** - 需要手动修改代码或使用复杂的条件判断
91
+ - 😰 **安全风险** - 敏感信息可能被提交到代码仓库
92
+ - 😰 **难以测试** - 测试时需要 mock 大量硬编码的值
93
+ - 😰 **团队协作困难** - 每个开发者的本地配置可能不同
94
+
95
+ #### ✅ 解决方案:环境变量 + AppConfig
96
+
97
+ ```typescript
98
+ // ✅ 1. 环境变量文件(不同环境不同配置)
99
+ // .env.localhost
100
+ VITE_API_BASE_URL=http://localhost:3000/api
101
+ VITE_AI_API_TOKEN=sk-dev-xxxxx
102
+
103
+ // .env.staging
104
+ VITE_API_BASE_URL=https://api.staging.example.com
105
+ VITE_AI_API_TOKEN=sk-staging-xxxxx
106
+
107
+ // .env.production
108
+ VITE_API_BASE_URL=https://api.production.com
109
+ VITE_AI_API_TOKEN=sk-prod-xxxxx
110
+
111
+ // ✅ 2. AppConfig 统一管理配置
112
+ export class AppConfig {
113
+ readonly feApiBaseUrl = ''; // ← 自动注入
114
+ readonly aiApiToken = ''; // ← 自动注入
115
+ readonly userTokenStorageKey = '__fe_user_token__';
116
+ }
117
+
118
+ // ✅ 3. 通过 IOC 容器获取配置
119
+ @injectable()
120
+ export class UserService {
121
+ constructor(
122
+ @inject(IOCIdentifier.AppConfig) private config: AppConfig
123
+ ) {}
124
+
125
+ async fetchUserInfo() {
126
+ // ✅ 从配置中获取 API 地址,自动适配环境
127
+ return fetch(`${this.config.feApiBaseUrl}/user`);
128
+ }
129
+ }
130
+
131
+ // ✅ 4. 运行时切换环境(无需修改代码)
132
+ npm run dev # localhost 环境
133
+ npm run dev:staging # staging 环境
134
+ npm run build:production # production 环境
38
135
  ```
39
136
 
40
- ## 环境变量文件
137
+ **优势:**
138
+
139
+ - ✅ **集中管理** - 所有配置在 AppConfig 中统一管理
140
+ - ✅ **环境切换简单** - 只需切换运行命令
141
+ - ✅ **安全** - 敏感信息通过 `.env.local` 管理,不提交到仓库
142
+ - ✅ **易于测试** - 测试时可以轻松 mock AppConfig
143
+ - ✅ **团队协作友好** - 每个开发者可以有自己的 `.env.local`
41
144
 
42
- ### 1. 文件加载优先级
145
+ ---
43
146
 
44
- Vite 会按照以下优先级加载环境变量文件:
147
+ ## ⚙️ 工作原理
148
+
149
+ ### 环境变量加载流程
45
150
 
46
151
  ```
47
- .env.local > .env.[mode] > .env
152
+ ┌────────────────────────────────────────────────────────────┐
153
+ │ 1. package.json: 定义启动命令 │
154
+ │ npm run dev → vite --mode localhost │
155
+ │ npm run dev:staging → vite --mode staging │
156
+ │ npm run build:production → vite build --mode production │
157
+ └──────────────────┬─────────────────────────────────────────┘
158
+
159
+ ┌────────────────────────────────────────────────────────────┐
160
+ │ 2. Vite: 根据 --mode 加载对应的 .env 文件 │
161
+ │ --mode localhost → .env.localhost │
162
+ │ --mode staging → .env.staging │
163
+ │ --mode production → .env.production │
164
+ │ │
165
+ │ 加载优先级:.env.local > .env.[mode] > .env │
166
+ └──────────────────┬─────────────────────────────────────────┘
167
+
168
+ ┌────────────────────────────────────────────────────────────┐
169
+ │ 3. vite.config.ts: envConfig 插件预处理 │
170
+ │ - 注入 APP_NAME、APP_VERSION 等 │
171
+ │ - 设置环境变量前缀 (VITE_) │
172
+ └──────────────────┬─────────────────────────────────────────┘
173
+
174
+ ┌────────────────────────────────────────────────────────────┐
175
+ │ 4. BootstrapClient: 初始化 Bootstrap │
176
+ │ envOptions: { │
177
+ │ target: appConfig, // 注入目标 │
178
+ │ source: import.meta.env, // 环境变量源 │
179
+ │ prefix: 'VITE_', // 前缀 │
180
+ │ blackList: ['env', 'userNodeEnv'] // 黑名单 │
181
+ │ } │
182
+ └──────────────────┬─────────────────────────────────────────┘
183
+
184
+ ┌────────────────────────────────────────────────────────────┐
185
+ │ 5. InjectEnv 插件: 自动注入环境变量到 AppConfig │
186
+ │ - VITE_APP_NAME → appConfig.appName │
187
+ │ - VITE_FE_API_BASE_URL → appConfig.feApiBaseUrl │
188
+ │ - VITE_AI_API_TOKEN → appConfig.aiApiToken │
189
+ └──────────────────┬─────────────────────────────────────────┘
190
+
191
+ ┌────────────────────────────────────────────────────────────┐
192
+ │ 6. IOC 容器: 注册 AppConfig │
193
+ │ container.bind(IOCIdentifier.AppConfig).toConstantValue │
194
+ └──────────────────┬─────────────────────────────────────────┘
195
+
196
+ ┌────────────────────────────────────────────────────────────┐
197
+ │ 7. 应用使用: 通过 IOC 获取配置 │
198
+ │ const config = useIOC('AppConfig'); │
199
+ │ console.log(config.feApiBaseUrl); │
200
+ └────────────────────────────────────────────────────────────┘
48
201
  ```
49
202
 
50
- **示例**:
51
-
52
- ```bash
53
- # 开发模式
54
- vite dev --mode development
55
- # 加载顺序:.env.local > .env.development > .env
203
+ ### 命名转换规则
56
204
 
57
- # 生产模式
58
- vite build --mode production
59
- # 加载顺序:.env.local > .env.production > .env
205
+ 环境变量名会自动转换为 AppConfig 属性名:
60
206
 
61
- # 自定义模式
62
- vite dev --mode staging
63
- # 加载顺序:.env.local > .env.staging > .env
207
+ ```
208
+ VITE_APP_NAME → appName
209
+ VITE_FE_API_BASE_URL → feApiBaseUrl
210
+ VITE_AI_API_TOKEN → aiApiToken
211
+ VITE_USER_TOKEN_STORAGE_KEY → userTokenStorageKey
64
212
  ```
65
213
 
66
- ### 2. 环境变量文件示例
214
+ **转换规则:**
67
215
 
68
- ```bash
69
- # .env (默认配置)
70
- VITE_APP_NAME=MyApp
71
- VITE_API_BASE_URL=http://api.example.com
72
- VITE_USER_TOKEN_KEY=user_token
216
+ 1. 移除前缀 (`VITE_`)
217
+ 2. 将下划线分隔转换为驼峰命名
218
+ 3. 匹配 AppConfig 中的属性名
73
219
 
74
- # .env.development (开发环境)
75
- VITE_API_BASE_URL=http://localhost:3000/api
76
- VITE_DEBUG=true
220
+ ---
77
221
 
78
- # .env.production (生产环境)
79
- VITE_API_BASE_URL=https://api.production.com
80
- VITE_DEBUG=false
222
+ ## 🛠️ 项目中的实现
223
+
224
+ ### 1. 定义启动命令
81
225
 
82
- # .env.local (本地覆盖,不提交到 git)
83
- VITE_API_KEY=your_secret_key
84
- VITE_LOCAL_DEBUG=true
226
+ ```json
227
+ // package.json
228
+ {
229
+ "scripts": {
230
+ "dev": "vite --mode localhost",
231
+ "dev:staging": "vite --mode staging",
232
+ "dev:prod": "vite --mode production",
233
+ "build": "npm run lint && vite build",
234
+ "build:staging": "npm run lint && vite build --mode staging",
235
+ "build:production": "npm run lint && vite build --mode production"
236
+ }
237
+ }
85
238
  ```
86
239
 
87
- ## 项目中的实现
240
+ **说明:**
241
+
242
+ - `--mode` 参数决定加载哪个 `.env` 文件
243
+ - 开发环境:使用 `localhost` 模式
244
+ - 测试环境:使用 `staging` 模式
245
+ - 生产环境:使用 `production` 模式
88
246
 
89
- ### 1. Vite 配置
247
+ ### 2. 配置 Vite
90
248
 
91
- ```tsx
249
+ ```typescript
92
250
  // vite.config.ts
93
- import envConfig from '@qlover/corekit-bridge/vite-env-config';
251
+ import { defineConfig } from 'vitest/config';
252
+ import { envPrefix } from './config/common';
253
+ import { name, version } from './package.json';
254
+ import envConfig from '@qlover/corekit-bridge/build/vite-env-config';
94
255
 
95
256
  export default defineConfig({
96
257
  plugins: [
258
+ // ✅ envConfig 插件:预处理环境变量
97
259
  envConfig({
98
- envPops: true, // 启用环境变量加载
99
- envPrefix: 'VITE_', // 环境变量前缀
260
+ envPops: true, // 启用环境变量处理
261
+ envPrefix, // 环境变量前缀: 'VITE_'
100
262
  records: [
101
263
  ['APP_NAME', name], // 注入应用名称
102
264
  ['APP_VERSION', version] // 注入应用版本
103
265
  ]
104
266
  })
267
+ // ... 其他插件
105
268
  ],
106
- envPrefix: 'VITE_', // Vite 环境变量前缀
269
+ envPrefix: envPrefix, // Vite 环境变量前缀
107
270
  server: {
108
271
  port: Number(process.env.VITE_SERVER_PORT || 3200)
109
272
  }
110
273
  });
111
274
  ```
112
275
 
113
- ### 2. 应用配置类
276
+ **关键配置:**
277
+
278
+ - `envConfig` 插件负责预处理环境变量
279
+ - `records` 可以注入额外的变量(如 package.json 中的信息)
280
+ - `envPrefix` 设置为 `'VITE_'`,只有此前缀的变量会被暴露给客户端
281
+
282
+ ### 3. 定义公共配置
283
+
284
+ ```typescript
285
+ // config/common.ts
286
+ export const envPrefix = 'VITE_';
114
287
 
115
- ```tsx
288
+ /**
289
+ * 启动器环境变量注入黑名单
290
+ * 这些属性不会从环境变量注入
291
+ */
292
+ export const envBlackList = ['env', 'userNodeEnv'];
293
+
294
+ export const browserGlobalsName = 'feGlobals';
295
+ ```
296
+
297
+ ### 4. 定义 AppConfig
298
+
299
+ ```typescript
116
300
  // src/base/cases/AppConfig.ts
301
+ import type { EnvConfigInterface } from '@qlover/corekit-bridge';
302
+
303
+ /**
304
+ * 应用配置类
305
+ *
306
+ * 所有属性都会在 Bootstrap 初始化时自动注入对应的环境变量值
307
+ *
308
+ * 环境变量命名规则:
309
+ * - 属性名会转换为大写下划线格式
310
+ * - 添加 VITE_ 前缀
311
+ *
312
+ * 示例:
313
+ * - appName → VITE_APP_NAME
314
+ * - feApiBaseUrl → VITE_FE_API_BASE_URL
315
+ * - aiApiToken → VITE_AI_API_TOKEN
316
+ */
117
317
  export class AppConfig implements EnvConfigInterface {
318
+ constructor(
319
+ /**
320
+ * 当前环境模式
321
+ * @description 从 Vite 的 MODE 自动设置
322
+ */
323
+ readonly env: string = import.meta.env.VITE_USER_NODE_ENV
324
+ ) {}
325
+
118
326
  /**
119
327
  * 应用名称
120
328
  * @description 从 VITE_APP_NAME 环境变量注入
@@ -127,18 +335,30 @@ export class AppConfig implements EnvConfigInterface {
127
335
  */
128
336
  readonly appVersion = '';
129
337
 
130
- /**
131
- * 当前环境模式
132
- * @description 从 Vite 的 mode 获取
133
- */
134
- readonly env: string = import.meta.env.MODE;
135
-
136
338
  /**
137
339
  * 用户令牌存储键
138
340
  * @description 从 VITE_USER_TOKEN_STORAGE_KEY 环境变量注入
139
341
  */
140
342
  readonly userTokenStorageKey = '__fe_user_token__';
141
343
 
344
+ /**
345
+ * 用户信息存储键
346
+ * @description 从 VITE_USER_INFO_STORAGE_KEY 环境变量注入
347
+ */
348
+ readonly userInfoStorageKey = '__fe_user_info__';
349
+
350
+ /**
351
+ * 前端 API 基础 URL
352
+ * @description 从 VITE_FE_API_BASE_URL 环境变量注入
353
+ */
354
+ readonly feApiBaseUrl = '';
355
+
356
+ /**
357
+ * 用户 API 基础 URL
358
+ * @description 从 VITE_USER_API_BASE_URL 环境变量注入
359
+ */
360
+ readonly userApiBaseUrl = '';
361
+
142
362
  /**
143
363
  * AI API 基础 URL
144
364
  * @description 从 VITE_AI_API_BASE_URL 环境变量注入
@@ -151,329 +371,966 @@ export class AppConfig implements EnvConfigInterface {
151
371
  */
152
372
  readonly aiApiToken = '';
153
373
 
154
- // ... 更多配置项
374
+ /**
375
+ * AI API 令牌前缀
376
+ * @description 从 VITE_AI_API_TOKEN_PREFIX 环境变量注入
377
+ */
378
+ readonly aiApiTokenPrefix = 'Bearer';
379
+
380
+ /**
381
+ * 是否需要 AI API 令牌
382
+ * @description 从 VITE_AI_API_REQUIRE_TOKEN 环境变量注入
383
+ */
384
+ readonly aiApiRequireToken = true;
385
+
386
+ /**
387
+ * 默认登录用户名
388
+ * @description 从 VITE_LOGIN_USER 环境变量注入
389
+ */
390
+ readonly loginUser = '';
391
+
392
+ /**
393
+ * 默认登录密码
394
+ * @description 从 VITE_LOGIN_PASSWORD 环境变量注入
395
+ */
396
+ readonly loginPassword = '';
397
+
398
+ /**
399
+ * OpenAI 可用模型列表
400
+ */
401
+ readonly openAiModels = [
402
+ 'gpt-4o-mini',
403
+ 'gpt-3.5-turbo',
404
+ 'gpt-3.5-turbo-2',
405
+ 'gpt-4',
406
+ 'gpt-4-32k'
407
+ ];
408
+
409
+ /**
410
+ * OpenAI API 基础 URL
411
+ * @description 从 VITE_OPEN_AI_BASE_URL 环境变量注入
412
+ */
413
+ readonly openAiBaseUrl = '';
414
+
415
+ /**
416
+ * OpenAI API 令牌
417
+ * @description 从 VITE_OPEN_AI_TOKEN 环境变量注入
418
+ */
419
+ readonly openAiToken = '';
420
+
421
+ /**
422
+ * OpenAI API 令牌前缀
423
+ * @description 从 VITE_OPEN_AI_TOKEN_PREFIX 环境变量注入
424
+ */
425
+ readonly openAiTokenPrefix = '';
426
+
427
+ /**
428
+ * 是否需要 OpenAI API 令牌
429
+ * @description 从 VITE_OPEN_AI_REQUIRE_TOKEN 环境变量注入
430
+ */
431
+ readonly openAiRequireToken = true;
432
+
433
+ /**
434
+ * 项目启动 URL
435
+ * @description 从 Bootstrap 注入的 BOOT_HREF
436
+ */
437
+ readonly bootHref = '';
438
+
439
+ /**
440
+ * 是否为生产环境
441
+ */
442
+ get isProduction(): boolean {
443
+ return this.env === 'production';
444
+ }
155
445
  }
156
446
  ```
157
447
 
158
- ### 3. Bootstrap 中的注入
448
+ ### 5. Bootstrap 配置
159
449
 
160
- ```tsx
161
- // src/core/bootstraps/BootstrapApp.ts
162
- const bootstrap = new Bootstrap({
163
- root: window,
164
- logger,
165
- ioc: {
166
- manager: IOC,
167
- register: new IocRegisterImpl({ pathname, appConfig })
168
- },
169
- envOptions: {
170
- target: appConfig, // 注入目标
171
- source: {
172
- ...import.meta.env, // 环境变量源
173
- [envPrefix + 'BOOT_HREF']: root.location.href
174
- },
175
- prefix: envPrefix, // 环境变量前缀
176
- blackList: envBlackList // 黑名单(不注入的变量)
450
+ ```typescript
451
+ // src/core/bootstraps/BootstrapClient.ts
452
+ import { envBlackList, envPrefix, browserGlobalsName } from '@config/common';
453
+ import { Bootstrap } from '@qlover/corekit-bridge';
454
+ import * as globals from '../globals';
455
+
456
+ export class BootstrapClient {
457
+ static async main(args: BootstrapClientArgs) {
458
+ const { root, bootHref, ioc, iocRegister } = args;
459
+ const { logger, appConfig } = globals;
460
+
461
+ // 创建 IOC 容器
462
+ const IOC = ioc.create({
463
+ pathname: bootHref,
464
+ appConfig: appConfig
465
+ });
466
+
467
+ // 创建 Bootstrap 实例
468
+ const bootstrap = new Bootstrap({
469
+ root,
470
+ logger,
471
+ ioc: {
472
+ manager: IOC,
473
+ register: iocRegister
474
+ },
475
+ // ✅ 环境变量注入配置
476
+ envOptions: {
477
+ target: appConfig, // 注入目标:AppConfig 实例
478
+ source: Object.assign({}, import.meta.env, {
479
+ [envPrefix + 'BOOT_HREF']: bootHref // 额外注入启动 URL
480
+ }),
481
+ prefix: envPrefix, // 环境变量前缀:'VITE_'
482
+ blackList: envBlackList // 黑名单:['env', 'userNodeEnv']
483
+ },
484
+ // 全局变量封装配置
485
+ globalOptions: {
486
+ sources: globals,
487
+ target: browserGlobalsName
488
+ }
489
+ });
490
+
491
+ try {
492
+ logger.info('bootstrap start...');
493
+
494
+ // ✅ 初始化 Bootstrap(此时会执行环境变量注入)
495
+ await bootstrap.initialize();
496
+
497
+ // 注册业务插件
498
+ const bootstrapsRegistry = new BootstrapsRegistry(IOC);
499
+ await bootstrap.use(bootstrapsRegistry.register()).start();
500
+
501
+ logger.info('bootstrap completed successfully');
502
+ } catch (error) {
503
+ logger.error(`${appConfig.appName} startup error:`, error);
504
+ }
505
+
506
+ return args;
177
507
  }
178
- });
508
+ }
179
509
  ```
180
510
 
181
- ## 多环境配置
511
+ **关键流程:**
182
512
 
183
- ### 1. 开发环境配置
513
+ 1. `appConfig` 是一个 AppConfig 实例,所有属性都有默认值
514
+ 2. `bootstrap.initialize()` 时会执行 `InjectEnv` 插件
515
+ 3. `InjectEnv` 插件遍历 `appConfig` 的属性,从 `import.meta.env` 中查找对应的环境变量
516
+ 4. 如果找到环境变量且值不为空,则覆盖默认值
517
+ 5. 最后 `appConfig` 被注册到 IOC 容器中
518
+
519
+ ---
520
+
521
+ ## 🌍 多环境配置
522
+
523
+ ### 环境文件结构
524
+
525
+ ```
526
+ 项目根目录/
527
+ ├── .env # 默认配置(所有环境共享)
528
+ ├── .env.localhost # 本地开发环境
529
+ ├── .env.staging # 测试环境
530
+ ├── .env.production # 生产环境
531
+ ├── .env.local # 本地覆盖配置(不提交到 git)
532
+ └── .env.template # 环境变量模板(提交到 git)
533
+ ```
534
+
535
+ ### 加载优先级
536
+
537
+ ```
538
+ .env.local > .env.[mode] > .env
539
+ ```
540
+
541
+ **示例:**
184
542
 
185
543
  ```bash
186
- # package.json
187
- {
188
- "scripts": {
189
- "dev": "vite --mode localhost",
190
- "dev:staging": "vite --mode staging",
191
- "dev:prod": "vite --mode production"
192
- }
193
- }
544
+ # 运行:npm run dev (vite --mode localhost)
545
+ # 加载顺序:
546
+ # 1. .env.local # 优先级最高
547
+ # 2. .env.localhost # 其次
548
+ # 3. .env # 最后
549
+
550
+ # 运行:npm run build:production (vite build --mode production)
551
+ # 加载顺序:
552
+ # 1. .env.local
553
+ # 2. .env.production
554
+ # 3. .env
194
555
  ```
195
556
 
557
+ ### 示例 1:默认配置
558
+
196
559
  ```bash
197
- # .env.development
198
- VITE_APP_NAME=MyApp Dev
199
- VITE_API_BASE_URL=http://localhost:3000/api
200
- VITE_DEBUG=true
201
- VITE_LOG_LEVEL=debug
560
+ # .env
561
+ # 所有环境共享的配置
562
+
563
+ VITE_APP_NAME=MyApp
564
+ VITE_USER_TOKEN_STORAGE_KEY=__fe_user_token__
565
+ VITE_USER_INFO_STORAGE_KEY=__fe_user_info__
566
+ VITE_AI_API_TOKEN_PREFIX=Bearer
567
+ VITE_AI_API_REQUIRE_TOKEN=true
202
568
  ```
203
569
 
204
- ### 2. 测试环境配置
570
+ ### 示例 2:本地开发环境
205
571
 
206
572
  ```bash
207
- # .env.staging
208
- VITE_APP_NAME=MyApp Staging
209
- VITE_API_BASE_URL=https://api.staging.com
573
+ # .env.localhost
574
+ # 本地开发环境配置
575
+
576
+ # API 配置
577
+ VITE_FE_API_BASE_URL=http://localhost:3000/api
578
+ VITE_USER_API_BASE_URL=http://localhost:3000/api/user
579
+ VITE_AI_API_BASE_URL=http://localhost:3001/v1
580
+
581
+ # AI 配置(开发环境可能使用本地 Mock)
582
+ VITE_AI_API_TOKEN=sk-dev-xxxxx
583
+ VITE_AI_API_REQUIRE_TOKEN=false
584
+
585
+ # 调试配置
586
+ VITE_LOG_LEVEL=debug
210
587
  VITE_DEBUG=true
211
- VITE_LOG_LEVEL=info
588
+
589
+ # 默认登录信息(方便开发)
590
+ VITE_LOGIN_USER=admin
591
+ VITE_LOGIN_PASSWORD=admin123
212
592
  ```
213
593
 
214
- ### 3. 生产环境配置
594
+ ### 示例 3:测试环境
215
595
 
216
596
  ```bash
217
- # .env.production
218
- VITE_APP_NAME=MyApp
219
- VITE_API_BASE_URL=https://api.production.com
220
- VITE_DEBUG=false
221
- VITE_LOG_LEVEL=warn
597
+ # .env.staging
598
+ # 测试环境配置
599
+
600
+ # API 配置
601
+ VITE_FE_API_BASE_URL=https://api.staging.example.com
602
+ VITE_USER_API_BASE_URL=https://api.staging.example.com/user
603
+ VITE_AI_API_BASE_URL=https://api.staging.example.com/ai
604
+
605
+ # AI 配置
606
+ VITE_AI_API_TOKEN=sk-staging-xxxxx
607
+ VITE_AI_API_REQUIRE_TOKEN=true
608
+
609
+ # 调试配置
610
+ VITE_LOG_LEVEL=info
611
+ VITE_DEBUG=true
222
612
  ```
223
613
 
224
- ### 4. 本地覆盖配置
614
+ ### 示例 4:生产环境
225
615
 
226
616
  ```bash
227
- # .env.local (不提交到 git)
228
- VITE_API_KEY=your_secret_key
229
- VITE_LOCAL_DEBUG=true
230
- VITE_CUSTOM_FEATURE=true
231
- ```
617
+ # .env.production
618
+ # 生产环境配置
232
619
 
233
- ## 在代码中使用
620
+ # API 配置
621
+ VITE_FE_API_BASE_URL=https://api.example.com
622
+ VITE_USER_API_BASE_URL=https://api.example.com/user
623
+ VITE_AI_API_BASE_URL=https://api.openai.com/v1
234
624
 
235
- ### 1. 直接使用环境变量
625
+ # AI 配置
626
+ VITE_AI_API_TOKEN=sk-prod-xxxxx
627
+ VITE_AI_API_REQUIRE_TOKEN=true
236
628
 
237
- ```tsx
238
- // 在组件中直接使用
239
- function App() {
240
- const apiUrl = import.meta.env.VITE_API_BASE_URL;
241
- const isDebug = import.meta.env.VITE_DEBUG === 'true';
242
- return (
243
- <div>
244
- <p>API URL: {apiUrl}</p>
245
- {isDebug && <p>Debug mode enabled</p>}
246
- </div>
247
- );
248
- }
629
+ # 调试配置
630
+ VITE_LOG_LEVEL=error
631
+ VITE_DEBUG=false
249
632
  ```
250
633
 
251
- ### 2. 通过 AppConfig 使用
634
+ ### 示例 5:本地覆盖配置
252
635
 
253
- ```tsx
254
- // 通过 IOC 获取配置
255
- function UserService() {
256
- const appConfig = IOC(IOCIdentifier.AppConfig);
636
+ ```bash
637
+ # .env.local
638
+ # 本地个人配置,不提交到 git
257
639
 
258
- const apiUrl = appConfig.aiApiBaseUrl;
259
- const token = appConfig.aiApiToken;
640
+ # 覆盖 AI API Token(使用自己的 Key)
641
+ VITE_AI_API_TOKEN=sk-my-personal-key
260
642
 
261
- // 使用配置进行 API 调用
262
- const response = await fetch(`${apiUrl}/chat`, {
263
- headers: {
264
- Authorization: `Bearer ${token}`
265
- }
266
- });
267
- }
643
+ # 覆盖 API 地址(连接到自己的本地服务)
644
+ VITE_FE_API_BASE_URL=http://192.168.1.100:3000/api
645
+
646
+ # 启用特定功能
647
+ VITE_ENABLE_EXPERIMENTAL_FEATURES=true
268
648
  ```
269
649
 
270
- ### 3. 在服务中使用
650
+ ### 示例 6:环境变量模板
271
651
 
272
- ```tsx
273
- @injectable()
274
- export class ApiService {
275
- constructor(@inject(IOCIdentifier.AppConfig) private appConfig: AppConfig) {}
652
+ ```bash
653
+ # .env.template
654
+ # 环境变量模板,提交到 git 供团队参考
276
655
 
277
- async makeRequest() {
278
- const baseUrl = this.appConfig.aiApiBaseUrl;
279
- const token = this.appConfig.aiApiToken;
656
+ # ===== 必填配置 =====
657
+ VITE_FE_API_BASE_URL=https://your-api-url.com
658
+ VITE_AI_API_TOKEN=your-ai-api-token-here
280
659
 
281
- return fetch(`${baseUrl}/api/endpoint`, {
282
- headers: {
283
- Authorization: `Bearer ${token}`
284
- }
285
- });
286
- }
287
- }
660
+ # ===== 可选配置 =====
661
+ VITE_LOGIN_USER=your-default-username
662
+ VITE_LOGIN_PASSWORD=your-default-password
663
+
664
+ # ===== 说明 =====
665
+ # 1. 复制此文件为 .env.local
666
+ # 2. 填写实际的配置值
667
+ # 3. .env.local 不会被提交到 git
288
668
  ```
289
669
 
290
- ## 环境变量注入插件
670
+ ---
291
671
 
292
- ### 1. InjectEnv 插件工作原理
672
+ ## 🔄 环境变量注入
293
673
 
294
- ```tsx
295
- // corekit-bridge/src/core/bootstrap/plugins/InjectEnv.ts
674
+ ### InjectEnv 插件工作原理
675
+
676
+ ```typescript
677
+ // @qlover/corekit-bridge/src/core/bootstrap/plugins/InjectEnv.ts (简化版)
296
678
  export class InjectEnv implements BootstrapExecutorPlugin {
297
679
  readonly pluginName = 'InjectEnv';
298
680
 
299
681
  constructor(protected options: InjectEnvConfig) {}
300
682
 
683
+ /**
684
+ * 在 Bootstrap 初始化前执行
685
+ */
301
686
  onBefore(): void {
302
687
  const { target, source, prefix, blackList } = this.options;
303
- // 遍历目标对象的属性
688
+
689
+ // 遍历目标对象的所有属性
304
690
  for (const key in target) {
691
+ // 跳过黑名单中的属性
305
692
  if (blackList.includes(key)) {
306
- continue; // 跳过黑名单中的属性
693
+ continue;
307
694
  }
308
695
 
309
- const value = target[key as keyof typeof target];
310
- const envValue = this.env(key, value); // 获取环境变量值
696
+ const currentValue = target[key as keyof typeof target];
697
+
698
+ // 获取对应的环境变量值
699
+ const envValue = this.getEnvValue(key, currentValue);
311
700
 
312
701
  // 如果环境变量存在且与默认值不同,则注入
313
- if (!this.isEmpty(envValue) && envValue !== value) {
702
+ if (!this.isEmpty(envValue) && envValue !== currentValue) {
314
703
  target[key as keyof typeof target] = envValue;
315
704
  }
316
705
  }
317
706
  }
707
+
708
+ /**
709
+ * 获取环境变量值
710
+ */
711
+ private getEnvValue<D>(key: string, defaultValue?: D): D {
712
+ const { prefix = '', source = {} } = this.options;
713
+
714
+ // 将驼峰命名转换为大写下划线命名
715
+ // appName → APP_NAME
716
+ // feApiBaseUrl → FE_API_BASE_URL
717
+ const formattedKey = key.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase();
718
+
719
+ // 添加前缀
720
+ const envKey = `${prefix}${formattedKey}`;
721
+
722
+ // 获取环境变量值
723
+ const value = source[envKey];
724
+
725
+ // 如果是 JSON 字符串,则解析
726
+ if (typeof value === 'string' && this.isJSONString(value)) {
727
+ return JSON.parse(value);
728
+ }
729
+
730
+ return (value ?? defaultValue) as D;
731
+ }
732
+
733
+ /**
734
+ * 判断值是否为空
735
+ */
736
+ private isEmpty(value: any): boolean {
737
+ return value === undefined || value === null || value === '';
738
+ }
739
+
740
+ /**
741
+ * 判断是否为 JSON 字符串
742
+ */
743
+ private isJSONString(str: string): boolean {
744
+ try {
745
+ JSON.parse(str);
746
+ return true;
747
+ } catch {
748
+ return false;
749
+ }
750
+ }
318
751
  }
319
752
  ```
320
753
 
321
- ### 2. 环境变量获取逻辑
754
+ ### 注入示例
755
+
756
+ ```typescript
757
+ // 假设有以下环境变量:
758
+ VITE_APP_NAME=MyApp
759
+ VITE_FE_API_BASE_URL=https://api.example.com
760
+ VITE_AI_API_TOKEN=sk-xxxxx
322
761
 
323
- ```tsx
324
- env<D>(key: string, defaultValue?: D): D {
325
- const { prefix = '', source = {} } = this.options;
762
+ // AppConfig 初始状态:
763
+ const appConfig = new AppConfig();
764
+ console.log(appConfig.appName); // ''
765
+ console.log(appConfig.feApiBaseUrl); // ''
766
+ console.log(appConfig.aiApiToken); // ''
326
767
 
327
- // 将驼峰命名转换为下划线命名
328
- const formattedKey = key.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase();
329
- const envKey = `${prefix}${formattedKey}`;
768
+ // Bootstrap 初始化后(InjectEnv 插件执行后):
769
+ await bootstrap.initialize();
330
770
 
331
- const value = source[envKey];
771
+ console.log(appConfig.appName); // 'MyApp'
772
+ console.log(appConfig.feApiBaseUrl); // 'https://api.example.com'
773
+ console.log(appConfig.aiApiToken); // 'sk-xxxxx'
774
+ ```
332
775
 
333
- // 如果是 JSON 字符串,则解析
334
- if (typeof value === 'string' && InjectEnv.isJSONString(value)) {
335
- return JSON.parse(value);
336
- }
776
+ ---
337
777
 
338
- return (value ?? defaultValue) as D;
778
+ ## 📦 AppConfig 使用
779
+
780
+ ### 1. 在服务中使用(推荐)⭐
781
+
782
+ ```typescript
783
+ // src/base/services/UserService.ts
784
+ import { injectable, inject } from 'inversify';
785
+ import { IOCIdentifier } from '@config/IOCIdentifier';
786
+ import type { AppConfig } from '@/base/cases/AppConfig';
787
+
788
+ @injectable()
789
+ export class UserService {
790
+ constructor(
791
+ @inject(IOCIdentifier.AppConfig) private config: AppConfig,
792
+ @inject(UserApi) private api: UserApi
793
+ ) {}
794
+
795
+ async login(username: string, password: string) {
796
+ // ✅ 使用配置中的 API 地址
797
+ const response = await this.api.post(
798
+ `${this.config.userApiBaseUrl}/login`,
799
+ { username, password }
800
+ );
801
+
802
+ // ✅ 使用配置中的存储键
803
+ this.storage.setItem(this.config.userTokenStorageKey, response.token);
804
+
805
+ return response.user;
806
+ }
339
807
  }
340
808
  ```
341
809
 
342
- ## 最佳实践
810
+ ### 2. 在 UI 组件中使用
343
811
 
344
- ### 1. 环境变量命名规范
812
+ ```typescript
813
+ // src/pages/base/HomePage.tsx
814
+ import { useIOC } from '@/uikit/hooks/useIOC';
345
815
 
346
- ```bash
347
- #好的命名
348
- VITE_APP_NAME=MyApp
349
- VITE_API_BASE_URL=https://api.example.com
350
- VITE_USER_TOKEN_STORAGE_KEY=user_token
351
- VITE_DEBUG=true
816
+ function HomePage() {
817
+ //通过 Hook 获取配置
818
+ const config = useIOC('AppConfig');
352
819
 
353
- # ❌ 不好的命名
354
- VITE_app_name=MyApp
355
- VITE_API_BASE_URL=https://api.example.com
356
- VITE_USER_TOKEN_STORAGE_KEY=user_token
357
- VITE_DEBUG=true
820
+ return (
821
+ <div>
822
+ <h1>{config.appName}</h1>
823
+ <p>Version: {config.appVersion}</p>
824
+ <p>Environment: {config.env}</p>
825
+ {!config.isProduction && <p>🚧 Development Mode</p>}
826
+ </div>
827
+ );
828
+ }
829
+ ```
830
+
831
+ ### 3. 在插件中使用
832
+
833
+ ```typescript
834
+ // src/base/apis/feApi/FeApiBootstrap.ts
835
+ export class FeApiBootstarp implements BootstrapExecutorPlugin {
836
+ readonly pluginName = 'FeApiBootstarp';
837
+
838
+ onBefore({ parameters: { ioc } }: BootstrapContext): void {
839
+ const feApi = ioc.get<FeApi>(FeApi);
840
+ // ✅ 从 IOC 获取配置
841
+ const config = ioc.get<AppConfig>(IOCIdentifier.AppConfig);
842
+
843
+ // ✅ 使用配置设置 API 基础 URL
844
+ feApi.setBaseURL(config.feApiBaseUrl);
845
+
846
+ // 添加其他插件
847
+ feApi.usePlugin(
848
+ new AuthTokenPlugin({
849
+ getToken: () => {
850
+ const storage = ioc.get(IOCIdentifier.LocalStorageEncrypt);
851
+ return storage.getItem(config.userTokenStorageKey);
852
+ }
853
+ })
854
+ );
855
+ }
856
+ }
358
857
  ```
359
858
 
360
- ### 2. 敏感信息处理
859
+ ### 4. 直接在代码中使用环境变量
361
860
 
362
- ```bash
363
- # .env.local (不提交到 git)
364
- VITE_API_KEY=your_secret_key
365
- VITE_DATABASE_PASSWORD=your_password
861
+ ```typescript
862
+ // 注意:直接使用 import.meta.env 不推荐,因为无法被 IOC 管理
366
863
 
367
- # .env.template (提交到 git,作为模板)
368
- VITE_API_KEY=your_api_key_here
369
- VITE_DATABASE_PASSWORD=your_password_here
864
+ // 不推荐:直接使用(绕过了 AppConfig)
865
+ function MyComponent() {
866
+ const apiUrl = import.meta.env.VITE_FE_API_BASE_URL;
867
+ // ...
868
+ }
869
+
870
+ // ✅ 推荐:通过 AppConfig 使用
871
+ function MyComponent() {
872
+ const config = useIOC('AppConfig');
873
+ const apiUrl = config.feApiBaseUrl;
874
+ // ...
875
+ }
370
876
  ```
371
877
 
372
- ### 3. 类型安全
878
+ ---
373
879
 
374
- ```tsx
375
- // 定义环境变量类型
376
- interface EnvVariables {
377
- VITE_APP_NAME: string;
378
- VITE_API_BASE_URL: string;
379
- VITE_DEBUG: boolean;
380
- VITE_PORT: number;
880
+ ## 🚀 高级用法
881
+
882
+ ### 1. 动态修改配置
883
+
884
+ 有时候你可能需要在运行时动态修改配置(而不是通过环境变量):
885
+
886
+ ```typescript
887
+ // ✅ 方法 1:在 Bootstrap 初始化前修改
888
+ const appConfig = new AppConfig();
889
+
890
+ // 动态修改配置
891
+ if (window.location.hostname.includes('localhost')) {
892
+ // 本地开发时使用不同的 API 地址
893
+ (appConfig as any).feApiBaseUrl = 'http://localhost:3000/api';
381
894
  }
382
895
 
383
- // AppConfig 中使用
384
- export class AppConfig implements EnvConfigInterface {
385
- readonly appName: string = '';
386
- readonly apiBaseUrl: string = '';
387
- readonly debug: boolean = false;
388
- readonly port: number = 3000;
896
+ // 然后传递给 Bootstrap
897
+ const bootstrap = new Bootstrap({
898
+ envOptions: {
899
+ target: appConfig, // 使用修改后的配置
900
+ source: import.meta.env,
901
+ prefix: 'VITE_',
902
+ blackList: envBlackList
903
+ }
904
+ });
905
+
906
+ await bootstrap.initialize();
907
+ ```
908
+
909
+ ```typescript
910
+ // ✅ 方法 2:创建配置工厂函数
911
+ export function createAppConfig(): AppConfig {
912
+ const config = new AppConfig();
913
+
914
+ // 根据特定条件动态设置配置
915
+ if (someCondition) {
916
+ (config as any).aiApiBaseUrl = 'https://custom-api.com';
917
+ }
918
+
919
+ return config;
389
920
  }
921
+
922
+ // 在 Bootstrap 中使用
923
+ const appConfig = createAppConfig();
390
924
  ```
391
925
 
392
- ### 4. 环境变量验证
926
+ ### 2. 配置验证
393
927
 
394
- ```tsx
395
- // 在应用启动时验证必要的环境变量
928
+ ```typescript
929
+ // src/base/cases/AppConfig.ts
396
930
  export class AppConfig implements EnvConfigInterface {
397
- constructor() {
398
- this.validateRequiredEnvVars();
399
- }
931
+ // ... 属性定义
400
932
 
401
- private validateRequiredEnvVars(): void {
402
- const required = ['VITE_API_BASE_URL', 'VITE_APP_NAME'];
403
- for (const envVar of required) {
404
- if (!import.meta.env[envVar]) {
405
- throw new Error(`Missing required environment variable: ${envVar}`);
933
+ /**
934
+ * 验证必需的配置项
935
+ */
936
+ validate(): void {
937
+ const required: (keyof AppConfig)[] = [
938
+ 'appName',
939
+ 'feApiBaseUrl',
940
+ 'userTokenStorageKey'
941
+ ];
942
+
943
+ for (const key of required) {
944
+ if (!this[key]) {
945
+ throw new Error(`Missing required configuration: ${key}`);
406
946
  }
407
947
  }
408
948
  }
409
949
  }
950
+
951
+ // 在 Bootstrap 中使用
952
+ const appConfig = new AppConfig();
953
+
954
+ await bootstrap.initialize();
955
+
956
+ // 初始化后验证
957
+ appConfig.validate();
958
+ ```
959
+
960
+ ### 3. 配置组合
961
+
962
+ ```typescript
963
+ // ✅ 方法 3:从多个源组合配置
964
+ const appConfig = new AppConfig();
965
+
966
+ const bootstrap = new Bootstrap({
967
+ envOptions: {
968
+ target: appConfig,
969
+ // 合并多个配置源
970
+ source: Object.assign(
971
+ {},
972
+ import.meta.env, // Vite 环境变量
973
+ { VITE_BOOT_HREF: window.location.href }, // 运行时信息
974
+ window.__APP_CONFIG__ // 服务端注入的配置
975
+ ),
976
+ prefix: 'VITE_',
977
+ blackList: envBlackList
978
+ }
979
+ });
980
+ ```
981
+
982
+ ### 4. 条件配置
983
+
984
+ ```typescript
985
+ // src/core/bootstraps/BootstrapClient.ts
986
+ const appConfig = new AppConfig();
987
+
988
+ // ✅ 根据环境设置不同的配置源
989
+ const configSource =
990
+ import.meta.env.VITE_USER_NODE_ENV === 'production'
991
+ ? import.meta.env // 生产环境:只使用环境变量
992
+ : {
993
+ ...import.meta.env,
994
+ ...window.__DEV_CONFIG__ // 开发环境:允许 window 注入
995
+ };
996
+
997
+ const bootstrap = new Bootstrap({
998
+ envOptions: {
999
+ target: appConfig,
1000
+ source: configSource,
1001
+ prefix: 'VITE_',
1002
+ blackList: envBlackList
1003
+ }
1004
+ });
1005
+ ```
1006
+
1007
+ ---
1008
+
1009
+ ## 🧪 测试配置
1010
+
1011
+ ### 1. 测试时 Mock AppConfig
1012
+
1013
+ ```typescript
1014
+ // __tests__/src/base/services/UserService.test.ts
1015
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
1016
+ import { UserService } from '@/base/services/UserService';
1017
+ import type { AppConfig } from '@/base/cases/AppConfig';
1018
+
1019
+ describe('UserService', () => {
1020
+ let userService: UserService;
1021
+ let mockConfig: AppConfig;
1022
+
1023
+ beforeEach(() => {
1024
+ // ✅ 创建 mock 配置
1025
+ mockConfig = {
1026
+ userApiBaseUrl: 'http://localhost:3000/api',
1027
+ userTokenStorageKey: '__test_token__',
1028
+ userInfoStorageKey: '__test_user__',
1029
+ isProduction: false
1030
+ } as AppConfig;
1031
+
1032
+ // 创建服务
1033
+ userService = new UserService(mockConfig, mockApi, mockStorage);
1034
+ });
1035
+
1036
+ it('should use config values', async () => {
1037
+ await userService.login('user', 'pass');
1038
+
1039
+ // ✅ 验证使用了配置中的值
1040
+ expect(mockApi.post).toHaveBeenCalledWith(
1041
+ `${mockConfig.userApiBaseUrl}/login`,
1042
+ expect.any(Object)
1043
+ );
1044
+ });
1045
+ });
1046
+ ```
1047
+
1048
+ ### 2. 测试不同环境配置
1049
+
1050
+ ```typescript
1051
+ // __tests__/src/base/cases/AppConfig.test.ts
1052
+ import { describe, it, expect } from 'vitest';
1053
+ import { AppConfig } from '@/base/cases/AppConfig';
1054
+
1055
+ describe('AppConfig', () => {
1056
+ it('should detect production environment', () => {
1057
+ const config = new AppConfig('production');
1058
+ expect(config.isProduction).toBe(true);
1059
+ });
1060
+
1061
+ it('should detect non-production environment', () => {
1062
+ const config = new AppConfig('localhost');
1063
+ expect(config.isProduction).toBe(false);
1064
+ });
1065
+
1066
+ it('should have default values', () => {
1067
+ const config = new AppConfig();
1068
+ expect(config.appName).toBe('');
1069
+ expect(config.userTokenStorageKey).toBe('__fe_user_token__');
1070
+ });
1071
+ });
410
1072
  ```
411
1073
 
412
- ## 调试和故障排除
1074
+ ### 3. 测试环境变量注入
1075
+
1076
+ ```typescript
1077
+ // __tests__/src/core/bootstraps/BootstrapClient.test.ts
1078
+ import { describe, it, expect, vi } from 'vitest';
1079
+ import { BootstrapClient } from '@/core/bootstraps/BootstrapClient';
413
1080
 
414
- ### 1. 检查环境变量加载
1081
+ describe('BootstrapClient', () => {
1082
+ it('should inject environment variables to AppConfig', async () => {
1083
+ const mockArgs = {
1084
+ root: {},
1085
+ bootHref: 'http://localhost:3000',
1086
+ ioc: {
1087
+ create: vi.fn().mockReturnValue(mockIOC)
1088
+ }
1089
+ };
1090
+
1091
+ // 执行启动
1092
+ await BootstrapClient.main(mockArgs);
415
1093
 
416
- ```tsx
417
- // 在控制台中检查环境变量
418
- console.log('import.meta.env:', import.meta.env);
419
- console.log('AppConfig:', IOC(IOCIdentifier.AppConfig));
1094
+ // ✅ 验证配置已注入
1095
+ const globals = (mockArgs.root as any).feGlobals;
1096
+ expect(globals.appConfig).toBeDefined();
1097
+ expect(globals.appConfig.appName).toBeTruthy();
1098
+ });
1099
+ });
420
1100
  ```
421
1101
 
422
- ### 2. 常见问题
1102
+ ---
1103
+
1104
+ ## 💎 最佳实践
1105
+
1106
+ ### 1. ✅ 使用环境变量前缀
1107
+
1108
+ ```bash
1109
+ # ✅ 好的命名:使用 VITE_ 前缀
1110
+ VITE_APP_NAME=MyApp
1111
+ VITE_API_BASE_URL=https://api.example.com
1112
+
1113
+ # ❌ 错误命名:没有前缀
1114
+ APP_NAME=MyApp
1115
+ API_BASE_URL=https://api.example.com
1116
+ ```
423
1117
 
424
- **问题 1:环境变量未注入**
1118
+ ### 2. ✅ 敏感信息使用 .env.local
425
1119
 
426
1120
  ```bash
427
- # 检查环境变量前缀
428
- # 确保使用 VITE_ 前缀
429
- VITE_APP_NAME=MyApp # ✅ 正确
430
- APP_NAME=MyApp # ❌ 错误,不会被注入
1121
+ # .env.local(不提交到 git)
1122
+ VITE_AI_API_TOKEN=sk-your-secret-key
1123
+ VITE_DATABASE_PASSWORD=your-password
1124
+
1125
+ # .gitignore
1126
+ .env.local
431
1127
  ```
432
1128
 
433
- **问题 2:环境变量文件未加载**
1129
+ ### 3. ✅ 提供 .env.template
434
1130
 
435
1131
  ```bash
436
- # 检查文件命名
437
- .env.development # ✅ 正确
438
- .env.dev # ❌ 错误,Vite 不认识
1132
+ # .env.template(提交到 git)
1133
+ # 团队成员可以复制此文件为 .env.local 并填写实际值
1134
+
1135
+ VITE_AI_API_TOKEN=your-api-token-here
1136
+ VITE_DATABASE_PASSWORD=your-password-here
439
1137
  ```
440
1138
 
441
- **问题 3:环境变量被黑名单过滤**
1139
+ ### 4. ✅ 使用类型安全的配置
1140
+
1141
+ ```typescript
1142
+ // ✅ 好的做法:通过 AppConfig 访问
1143
+ const config = useIOC('AppConfig');
1144
+ const apiUrl = config.feApiBaseUrl; // ✅ 类型安全
1145
+
1146
+ // ❌ 不好的做法:直接访问环境变量
1147
+ const apiUrl = import.meta.env.VITE_FE_API_BASE_URL; // ❌ 可能为 undefined
1148
+ ```
1149
+
1150
+ ### 5. ✅ 为 AppConfig 添加注释
1151
+
1152
+ ```typescript
1153
+ export class AppConfig {
1154
+ /**
1155
+ * AI API 基础 URL
1156
+ * @description 从 VITE_AI_API_BASE_URL 环境变量注入
1157
+ * @default 'https://api.openai.com/v1'
1158
+ * @example 'https://api.openai.com/v1'
1159
+ */
1160
+ readonly aiApiBaseUrl = 'https://api.openai.com/v1';
1161
+ }
1162
+ ```
1163
+
1164
+ ### 6. ✅ 避免在代码中判断环境
1165
+
1166
+ ```typescript
1167
+ // ❌ 不好:在代码中判断环境
1168
+ if (process.env.NODE_ENV === 'production') {
1169
+ apiUrl = 'https://api.production.com';
1170
+ } else {
1171
+ apiUrl = 'http://localhost:3000';
1172
+ }
1173
+
1174
+ // ✅ 好:通过配置管理
1175
+ const config = useIOC('AppConfig');
1176
+ const apiUrl = config.feApiBaseUrl; // 自动根据环境使用正确的值
1177
+ ```
1178
+
1179
+ ### 7. ✅ 配置命名规范
1180
+
1181
+ ```bash
1182
+ # ✅ 好的命名:清晰、具体
1183
+ VITE_FE_API_BASE_URL=https://api.example.com
1184
+ VITE_USER_TOKEN_STORAGE_KEY=__fe_user_token__
1185
+ VITE_AI_API_REQUIRE_TOKEN=true
1186
+
1187
+ # ❌ 不好的命名:模糊、简写
1188
+ VITE_API=https://api.example.com
1189
+ VITE_KEY=__token__
1190
+ VITE_REQ=true
1191
+ ```
1192
+
1193
+ ---
1194
+
1195
+ ## ❓ 常见问题
1196
+
1197
+ ### Q1: 为什么我的环境变量没有注入?
1198
+
1199
+ **A:** 检查以下几点:
442
1200
 
443
- ```tsx
444
- // 检查黑名单配置
1201
+ 1. **环境变量前缀**
1202
+
1203
+ ```bash
1204
+ # ✅ 正确:使用 VITE_ 前缀
1205
+ VITE_APP_NAME=MyApp
1206
+
1207
+ # ❌ 错误:没有前缀
1208
+ APP_NAME=MyApp
1209
+ ```
1210
+
1211
+ 2. **AppConfig 属性名**
1212
+
1213
+ ```typescript
1214
+ // ✅ 正确:属性名存在
1215
+ export class AppConfig {
1216
+ readonly appName = ''; // ← VITE_APP_NAME 会注入这里
1217
+ }
1218
+
1219
+ // ❌ 错误:没有对应的属性
1220
+ export class AppConfig {
1221
+ // 没有 appName 属性,VITE_APP_NAME 不会被注入
1222
+ }
1223
+ ```
1224
+
1225
+ 3. **黑名单配置**
1226
+
1227
+ ```typescript
1228
+ // config/common.ts
445
1229
  export const envBlackList = ['env', 'userNodeEnv'];
446
- // 确保你的环境变量不在黑名单中
1230
+ // 确保你的属性不在黑名单中
447
1231
  ```
448
1232
 
449
- ### 3. 调试工具
1233
+ ### Q2: 如何在不同环境使用不同配置?
1234
+
1235
+ **A:** 使用 `--mode` 参数:
450
1236
 
451
- ```tsx
452
- // 创建调试工具
453
- export class EnvDebugger {
454
- static logEnvVars(config: AppConfig): void {
455
- console.group('Environment Variables Debug');
456
- console.log('Current Mode:', import.meta.env.MODE);
457
- console.log('AppConfig:', config);
458
- console.log('All Env Vars:', import.meta.env);
459
- console.groupEnd();
1237
+ ```json
1238
+ {
1239
+ "scripts": {
1240
+ "dev": "vite --mode localhost", // 加载 .env.localhost
1241
+ "dev:staging": "vite --mode staging", // 加载 .env.staging
1242
+ "build:prod": "vite build --mode production" // 加载 .env.production
460
1243
  }
461
1244
  }
1245
+ ```
462
1246
 
463
- // 在开发环境中使用
464
- if (import.meta.env.DEV) {
465
- EnvDebugger.logEnvVars(IOC(IOCIdentifier.AppConfig));
466
- }
1247
+ ### Q3: 如何处理敏感信息?
1248
+
1249
+ **A:** 使用 `.env.local`:
1250
+
1251
+ ```bash
1252
+ # .env.local(不提交到 git)
1253
+ VITE_AI_API_TOKEN=sk-your-secret-key
1254
+
1255
+ # .gitignore
1256
+ .env.local
1257
+ ```
1258
+
1259
+ ### Q4: 能否在运行时动态修改配置?
1260
+
1261
+ **A:** 可以,但需要在 Bootstrap 初始化前:
1262
+
1263
+ ```typescript
1264
+ const appConfig = new AppConfig();
1265
+
1266
+ // ✅ 在 Bootstrap 初始化前修改
1267
+ (appConfig as any).feApiBaseUrl = 'https://custom-api.com';
1268
+
1269
+ const bootstrap = new Bootstrap({
1270
+ envOptions: {
1271
+ target: appConfig, // 使用修改后的配置
1272
+ source: import.meta.env,
1273
+ prefix: 'VITE_',
1274
+ blackList: envBlackList
1275
+ }
1276
+ });
1277
+
1278
+ await bootstrap.initialize();
467
1279
  ```
468
1280
 
469
- ## 总结
1281
+ ### Q5: 为什么推荐通过 AppConfig 而不是直接使用 import.meta.env?
1282
+
1283
+ **A:**
1284
+
1285
+ | 特性 | import.meta.env | AppConfig |
1286
+ | -------------- | ------------------- | --------------- |
1287
+ | **类型安全** | ❌ 可能为 undefined | ✅ 完整类型定义 |
1288
+ | **默认值** | ❌ 没有 | ✅ 有默认值 |
1289
+ | **可测试性** | ❌ 难以 mock | ✅ 易于 mock |
1290
+ | **集中管理** | ❌ 分散各处 | ✅ 统一管理 |
1291
+ | **运行时修改** | ❌ 不可能 | ✅ 可以 |
1292
+
1293
+ ### Q6: 环境变量和配置文件有什么区别?
1294
+
1295
+ **A:**
1296
+
1297
+ **环境变量:** 适用于:
1298
+
1299
+ - 不同环境的配置(API 地址、Token 等)
1300
+ - 敏感信息
1301
+ - 部署时需要修改的配置
1302
+
1303
+ **配置文件(config/):** 适用于:
1304
+
1305
+ - 应用逻辑配置(路由、主题、i18n 等)
1306
+ - 不随环境变化的配置
1307
+ - 代码级的配置
1308
+
1309
+ ---
1310
+
1311
+ ## 📚 相关文档
1312
+
1313
+ - [项目架构设计](./index.md) - 了解整体架构
1314
+ - [Bootstrap 启动器](./bootstrap.md) - Bootstrap 详解
1315
+ - [IOC 容器](./ioc.md) - 依赖注入详解
1316
+ - [全局变量封装](./global.md) - 浏览器 API 封装
1317
+
1318
+ ---
1319
+
1320
+ ## 🎉 总结
1321
+
1322
+ 环境变量管理系统通过 **Bootstrap + AppConfig + IOC** 的组合,提供了:
1323
+
1324
+ 1. **环境隔离** 🌍 - 不同环境使用不同配置,无需修改代码
1325
+ 2. **类型安全** 🔒 - 通过 TypeScript 提供完整的类型检查
1326
+ 3. **集中管理** 📦 - 所有配置在 AppConfig 中统一管理
1327
+ 4. **自动注入** ⚡ - Bootstrap 自动将环境变量注入到 AppConfig
1328
+ 5. **易于测试** 🧪 - 可以轻松 mock AppConfig 进行测试
1329
+ 6. **灵活扩展** 🚀 - 支持多种配置源和动态修改
470
1330
 
471
- 环境变量注入系统提供了:
1331
+ 通过合理使用环境变量管理,你可以构建一个更加健壮、灵活、易于维护的应用架构。
472
1332
 
473
- 1. **环境隔离**:不同环境使用不同配置
474
- 2. **类型安全**:通过 TypeScript 提供类型检查
475
- 3. **集中管理**:所有配置在 AppConfig 中统一管理
476
- 4. **灵活配置**:支持多种环境变量文件
477
- 5. **安全处理**:敏感信息可以通过 .env.local 本地管理
1333
+ ---
478
1334
 
479
- 通过合理使用环境变量注入,可以让应用在不同环境中正确运行,同时保持配置的灵活性和安全性。
1335
+ **问题反馈:**
1336
+ 如果你对环境变量管理有任何疑问或建议,请在团队频道中讨论或提交 Issue。