@qlover/create-app 1.1.0 → 2.0.2

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 (556) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/index.cjs +9 -9
  3. package/dist/index.js +9 -9
  4. package/package.json +5 -4
  5. package/dist/configs/_common/.editorconfig +0 -23
  6. package/dist/configs/_common/.env.template +0 -13
  7. package/dist/configs/_common/.gitattributes +0 -2
  8. package/dist/configs/_common/.github/workflows/general-check.yml +0 -41
  9. package/dist/configs/_common/.github/workflows/release.yml +0 -81
  10. package/dist/configs/_common/.gitignore.template +0 -64
  11. package/dist/configs/_common/.husky/commit-msg +0 -3
  12. package/dist/configs/_common/.husky/pre-commit +0 -3
  13. package/dist/configs/_common/.prettierignore +0 -17
  14. package/dist/configs/_common/.prettierrc.js +0 -7
  15. package/dist/configs/_common/.vscode/extensions.json +0 -9
  16. package/dist/configs/_common/.vscode/react.code-snippets +0 -19
  17. package/dist/configs/_common/.vscode/settings.json +0 -16
  18. package/dist/configs/_common/commitlint.config.js +0 -10
  19. package/dist/configs/_common/package.json.template +0 -75
  20. package/dist/configs/node-lib/eslint.config.js +0 -50
  21. package/dist/templates/next-app/.env.template +0 -25
  22. package/dist/templates/next-app/.prettierignore +0 -58
  23. package/dist/templates/next-app/README.en.md +0 -130
  24. package/dist/templates/next-app/README.md +0 -130
  25. package/dist/templates/next-app/config/IOCIdentifier.ts +0 -74
  26. package/dist/templates/next-app/config/Identifier/api.ts +0 -41
  27. package/dist/templates/next-app/config/Identifier/common/admint.table.ts +0 -69
  28. package/dist/templates/next-app/config/Identifier/common/common.ts +0 -90
  29. package/dist/templates/next-app/config/Identifier/common/index.ts +0 -3
  30. package/dist/templates/next-app/config/Identifier/common/validators.ts +0 -34
  31. package/dist/templates/next-app/config/Identifier/index.ts +0 -3
  32. package/dist/templates/next-app/config/Identifier/pages/index.ts +0 -7
  33. package/dist/templates/next-app/config/Identifier/pages/page.about.ts +0 -20
  34. package/dist/templates/next-app/config/Identifier/pages/page.admin.home.ts +0 -27
  35. package/dist/templates/next-app/config/Identifier/pages/page.admin.locales.ts +0 -266
  36. package/dist/templates/next-app/config/Identifier/pages/page.admin.user.ts +0 -293
  37. package/dist/templates/next-app/config/Identifier/pages/page.home.ts +0 -56
  38. package/dist/templates/next-app/config/Identifier/pages/page.login.ts +0 -159
  39. package/dist/templates/next-app/config/Identifier/pages/page.register.ts +0 -177
  40. package/dist/templates/next-app/config/adminNavs.ts +0 -19
  41. package/dist/templates/next-app/config/common.ts +0 -43
  42. package/dist/templates/next-app/config/cookies.ts +0 -23
  43. package/dist/templates/next-app/config/i18n/AboutI18n.ts +0 -14
  44. package/dist/templates/next-app/config/i18n/HomeI18n.ts +0 -24
  45. package/dist/templates/next-app/config/i18n/PageI18nInterface.ts +0 -51
  46. package/dist/templates/next-app/config/i18n/admin18n.ts +0 -75
  47. package/dist/templates/next-app/config/i18n/i18nConfig.ts +0 -16
  48. package/dist/templates/next-app/config/i18n/i18nKeyScheam.ts +0 -36
  49. package/dist/templates/next-app/config/i18n/index.ts +0 -7
  50. package/dist/templates/next-app/config/i18n/loginI18n.ts +0 -50
  51. package/dist/templates/next-app/config/i18n/register18n.ts +0 -44
  52. package/dist/templates/next-app/config/route.ts +0 -9
  53. package/dist/templates/next-app/config/theme.ts +0 -28
  54. package/dist/templates/next-app/docs/en/api.md +0 -387
  55. package/dist/templates/next-app/docs/en/component.md +0 -544
  56. package/dist/templates/next-app/docs/en/database.md +0 -496
  57. package/dist/templates/next-app/docs/en/development-guide.md +0 -727
  58. package/dist/templates/next-app/docs/en/env.md +0 -563
  59. package/dist/templates/next-app/docs/en/i18n.md +0 -287
  60. package/dist/templates/next-app/docs/en/index.md +0 -165
  61. package/dist/templates/next-app/docs/en/page.md +0 -457
  62. package/dist/templates/next-app/docs/en/project-structure.md +0 -176
  63. package/dist/templates/next-app/docs/en/router.md +0 -427
  64. package/dist/templates/next-app/docs/en/theme.md +0 -532
  65. package/dist/templates/next-app/docs/en/validator.md +0 -478
  66. package/dist/templates/next-app/docs/zh/api.md +0 -387
  67. package/dist/templates/next-app/docs/zh/component.md +0 -544
  68. package/dist/templates/next-app/docs/zh/database.md +0 -496
  69. package/dist/templates/next-app/docs/zh/development-guide.md +0 -727
  70. package/dist/templates/next-app/docs/zh/env.md +0 -563
  71. package/dist/templates/next-app/docs/zh/i18n.md +0 -287
  72. package/dist/templates/next-app/docs/zh/index.md +0 -165
  73. package/dist/templates/next-app/docs/zh/page.md +0 -457
  74. package/dist/templates/next-app/docs/zh/project-structure.md +0 -176
  75. package/dist/templates/next-app/docs/zh/router.md +0 -427
  76. package/dist/templates/next-app/docs/zh/theme.md +0 -532
  77. package/dist/templates/next-app/docs/zh/validator.md +0 -476
  78. package/dist/templates/next-app/eslint.config.mjs +0 -285
  79. package/dist/templates/next-app/make/generateLocales.ts +0 -32
  80. package/dist/templates/next-app/migrations/schema/LocalesSchema.ts +0 -15
  81. package/dist/templates/next-app/migrations/schema/UserSchema.ts +0 -38
  82. package/dist/templates/next-app/migrations/sql/1694244000000.sql +0 -21
  83. package/dist/templates/next-app/next.config.ts +0 -25
  84. package/dist/templates/next-app/package.json +0 -87
  85. package/dist/templates/next-app/postcss.config.mjs +0 -5
  86. package/dist/templates/next-app/public/favicon.ico +0 -0
  87. package/dist/templates/next-app/public/file.svg +0 -1
  88. package/dist/templates/next-app/public/globe.svg +0 -1
  89. package/dist/templates/next-app/public/locales/en.json +0 -182
  90. package/dist/templates/next-app/public/locales/zh.json +0 -182
  91. package/dist/templates/next-app/public/next.svg +0 -1
  92. package/dist/templates/next-app/public/vercel.svg +0 -1
  93. package/dist/templates/next-app/public/window.svg +0 -1
  94. package/dist/templates/next-app/src/app/[locale]/admin/AdminI18nProvider.tsx +0 -37
  95. package/dist/templates/next-app/src/app/[locale]/admin/layout.tsx +0 -42
  96. package/dist/templates/next-app/src/app/[locale]/admin/locales/page.tsx +0 -153
  97. package/dist/templates/next-app/src/app/[locale]/admin/page.tsx +0 -20
  98. package/dist/templates/next-app/src/app/[locale]/admin/users/page.tsx +0 -67
  99. package/dist/templates/next-app/src/app/[locale]/auth/layout.tsx +0 -18
  100. package/dist/templates/next-app/src/app/[locale]/auth/login/LoginForm.tsx +0 -126
  101. package/dist/templates/next-app/src/app/[locale]/auth/login/page.tsx +0 -90
  102. package/dist/templates/next-app/src/app/[locale]/auth/page.tsx +0 -8
  103. package/dist/templates/next-app/src/app/[locale]/auth/register/RegisterForm.tsx +0 -197
  104. package/dist/templates/next-app/src/app/[locale]/auth/register/page.tsx +0 -90
  105. package/dist/templates/next-app/src/app/[locale]/layout.tsx +0 -63
  106. package/dist/templates/next-app/src/app/[locale]/not-found.tsx +0 -24
  107. package/dist/templates/next-app/src/app/[locale]/page.tsx +0 -98
  108. package/dist/templates/next-app/src/app/api/admin/locales/create/route.ts +0 -13
  109. package/dist/templates/next-app/src/app/api/admin/locales/import/route.ts +0 -13
  110. package/dist/templates/next-app/src/app/api/admin/locales/route.ts +0 -20
  111. package/dist/templates/next-app/src/app/api/admin/locales/update/route.ts +0 -13
  112. package/dist/templates/next-app/src/app/api/admin/users/route.ts +0 -20
  113. package/dist/templates/next-app/src/app/api/ai/completions/route.ts +0 -32
  114. package/dist/templates/next-app/src/app/api/auth/callback/route.ts +0 -11
  115. package/dist/templates/next-app/src/app/api/callback/route.ts +0 -49
  116. package/dist/templates/next-app/src/app/api/locales/json/route.ts +0 -33
  117. package/dist/templates/next-app/src/app/api/user/login/route.ts +0 -10
  118. package/dist/templates/next-app/src/app/api/user/logout/route.ts +0 -8
  119. package/dist/templates/next-app/src/app/api/user/register/route.ts +0 -11
  120. package/dist/templates/next-app/src/app/manifest.ts +0 -16
  121. package/dist/templates/next-app/src/app/robots.txt +0 -2
  122. package/dist/templates/next-app/src/base/cases/AdminPageManager.ts +0 -28
  123. package/dist/templates/next-app/src/base/cases/AppConfig.ts +0 -40
  124. package/dist/templates/next-app/src/base/cases/Datetime.ts +0 -18
  125. package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +0 -57
  126. package/dist/templates/next-app/src/base/cases/DialogHandler.ts +0 -116
  127. package/dist/templates/next-app/src/base/cases/InversifyContainer.ts +0 -45
  128. package/dist/templates/next-app/src/base/cases/NavigateBridge.ts +0 -32
  129. package/dist/templates/next-app/src/base/cases/RequestEncryptPlugin.ts +0 -77
  130. package/dist/templates/next-app/src/base/cases/ResourceState.ts +0 -17
  131. package/dist/templates/next-app/src/base/cases/RouterService.ts +0 -52
  132. package/dist/templates/next-app/src/base/cases/StringEncryptor.ts +0 -73
  133. package/dist/templates/next-app/src/base/cases/TranslateI18nUtil.ts +0 -53
  134. package/dist/templates/next-app/src/base/cases/ZodColumnBuilder.ts +0 -212
  135. package/dist/templates/next-app/src/base/port/AdminLayoutInterface.ts +0 -26
  136. package/dist/templates/next-app/src/base/port/AppApiInterface.ts +0 -36
  137. package/dist/templates/next-app/src/base/port/AppUserApiInterface.ts +0 -27
  138. package/dist/templates/next-app/src/base/port/I18nServiceInterface.ts +0 -25
  139. package/dist/templates/next-app/src/base/port/IOCInterface.ts +0 -33
  140. package/dist/templates/next-app/src/base/port/RouterInterface.ts +0 -11
  141. package/dist/templates/next-app/src/base/port/UserServiceInterface.ts +0 -25
  142. package/dist/templates/next-app/src/base/port/ZodBuilderInterface.ts +0 -8
  143. package/dist/templates/next-app/src/base/services/AdminPageEvent.ts +0 -26
  144. package/dist/templates/next-app/src/base/services/AdminPageScheduler.ts +0 -42
  145. package/dist/templates/next-app/src/base/services/AppApiRequester.ts +0 -67
  146. package/dist/templates/next-app/src/base/services/AppUserGateway.ts +0 -110
  147. package/dist/templates/next-app/src/base/services/I18nService.ts +0 -87
  148. package/dist/templates/next-app/src/base/services/ResourceService.ts +0 -139
  149. package/dist/templates/next-app/src/base/services/UserService.ts +0 -68
  150. package/dist/templates/next-app/src/base/services/adminApi/AdminLocalesApi.ts +0 -106
  151. package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +0 -87
  152. package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +0 -110
  153. package/dist/templates/next-app/src/base/services/appApi/AppUserApiBootstrap.ts +0 -52
  154. package/dist/templates/next-app/src/base/types/AppPageRouter.ts +0 -12
  155. package/dist/templates/next-app/src/base/types/PagesRouter.ts +0 -9
  156. package/dist/templates/next-app/src/core/bootstraps/BootstrapClient.ts +0 -76
  157. package/dist/templates/next-app/src/core/bootstraps/BootstrapServer.ts +0 -125
  158. package/dist/templates/next-app/src/core/bootstraps/BootstrapsRegistry.ts +0 -50
  159. package/dist/templates/next-app/src/core/bootstraps/IocIdentifierTest.ts +0 -26
  160. package/dist/templates/next-app/src/core/bootstraps/PrintBootstrap.ts +0 -18
  161. package/dist/templates/next-app/src/core/clientIoc/ClientIOC.ts +0 -68
  162. package/dist/templates/next-app/src/core/clientIoc/ClientIOCRegister.ts +0 -100
  163. package/dist/templates/next-app/src/core/globals.ts +0 -28
  164. package/dist/templates/next-app/src/core/serverIoc/ServerIOC.ts +0 -80
  165. package/dist/templates/next-app/src/core/serverIoc/ServerIOCRegister.ts +0 -66
  166. package/dist/templates/next-app/src/i18n/loadMessages.ts +0 -103
  167. package/dist/templates/next-app/src/i18n/request.ts +0 -31
  168. package/dist/templates/next-app/src/i18n/routing.ts +0 -35
  169. package/dist/templates/next-app/src/lib/supabase/client.ts +0 -8
  170. package/dist/templates/next-app/src/lib/supabase/conts.ts +0 -2
  171. package/dist/templates/next-app/src/lib/supabase/proxy.ts +0 -84
  172. package/dist/templates/next-app/src/lib/supabase/server.ts +0 -38
  173. package/dist/templates/next-app/src/pages/[locale]/about.tsx +0 -61
  174. package/dist/templates/next-app/src/pages/_app.tsx +0 -50
  175. package/dist/templates/next-app/src/pages/_document.tsx +0 -13
  176. package/dist/templates/next-app/src/proxy.ts +0 -33
  177. package/dist/templates/next-app/src/server/AppErrorApi.ts +0 -10
  178. package/dist/templates/next-app/src/server/AppPageRouteParams.ts +0 -110
  179. package/dist/templates/next-app/src/server/AppSuccessApi.ts +0 -7
  180. package/dist/templates/next-app/src/server/NextApiServer.ts +0 -61
  181. package/dist/templates/next-app/src/server/PagesRouteParams.ts +0 -145
  182. package/dist/templates/next-app/src/server/PasswordEncrypt.ts +0 -18
  183. package/dist/templates/next-app/src/server/ServerAuth.ts +0 -81
  184. package/dist/templates/next-app/src/server/SupabaseBridge.ts +0 -262
  185. package/dist/templates/next-app/src/server/UserCredentialToken.ts +0 -53
  186. package/dist/templates/next-app/src/server/controllers/AdminLocalesController.ts +0 -86
  187. package/dist/templates/next-app/src/server/controllers/AdminUserController.ts +0 -42
  188. package/dist/templates/next-app/src/server/controllers/LocalesController.ts +0 -36
  189. package/dist/templates/next-app/src/server/controllers/UserController.ts +0 -91
  190. package/dist/templates/next-app/src/server/port/AIControllerInterface.ts +0 -8
  191. package/dist/templates/next-app/src/server/port/AdminLocalesControllerInterface.ts +0 -21
  192. package/dist/templates/next-app/src/server/port/AdminUserControllerInterface.ts +0 -11
  193. package/dist/templates/next-app/src/server/port/CrentialTokenInterface.ts +0 -5
  194. package/dist/templates/next-app/src/server/port/DBBridgeInterface.ts +0 -36
  195. package/dist/templates/next-app/src/server/port/DBTableInterface.ts +0 -12
  196. package/dist/templates/next-app/src/server/port/LocalesControllerInterface.ts +0 -10
  197. package/dist/templates/next-app/src/server/port/LocalesRepositoryInterface.ts +0 -43
  198. package/dist/templates/next-app/src/server/port/PaginationInterface.ts +0 -6
  199. package/dist/templates/next-app/src/server/port/RouteParamsnHandlerInterface.ts +0 -18
  200. package/dist/templates/next-app/src/server/port/ServerAuthInterface.ts +0 -15
  201. package/dist/templates/next-app/src/server/port/ServerInterface.ts +0 -23
  202. package/dist/templates/next-app/src/server/port/UserRepositoryInterface.ts +0 -15
  203. package/dist/templates/next-app/src/server/port/UserServiceInterface.ts +0 -14
  204. package/dist/templates/next-app/src/server/port/ValidatorInterface.ts +0 -23
  205. package/dist/templates/next-app/src/server/repositorys/LocalesRepository.ts +0 -216
  206. package/dist/templates/next-app/src/server/repositorys/UserRepository.ts +0 -102
  207. package/dist/templates/next-app/src/server/services/AIService.ts +0 -45
  208. package/dist/templates/next-app/src/server/services/AdminAuthPlugin.ts +0 -21
  209. package/dist/templates/next-app/src/server/services/AdminLocalesService.ts +0 -20
  210. package/dist/templates/next-app/src/server/services/ApiLocaleService.ts +0 -137
  211. package/dist/templates/next-app/src/server/services/ApiUserService.ts +0 -29
  212. package/dist/templates/next-app/src/server/services/UserService.ts +0 -134
  213. package/dist/templates/next-app/src/server/validators/ExtendedExecutorError.ts +0 -6
  214. package/dist/templates/next-app/src/server/validators/LocalesValidator.ts +0 -145
  215. package/dist/templates/next-app/src/server/validators/LoginValidator.ts +0 -82
  216. package/dist/templates/next-app/src/server/validators/PaginationValidator.ts +0 -70
  217. package/dist/templates/next-app/src/server/validators/SignupVerifyValidator.ts +0 -68
  218. package/dist/templates/next-app/src/styles/css/antd-themes/_common/_default.css +0 -280
  219. package/dist/templates/next-app/src/styles/css/antd-themes/_common/dark.css +0 -233
  220. package/dist/templates/next-app/src/styles/css/antd-themes/_common/index.css +0 -3
  221. package/dist/templates/next-app/src/styles/css/antd-themes/_common/pink.css +0 -246
  222. package/dist/templates/next-app/src/styles/css/antd-themes/index.css +0 -4
  223. package/dist/templates/next-app/src/styles/css/antd-themes/menu/_default.css +0 -108
  224. package/dist/templates/next-app/src/styles/css/antd-themes/menu/dark.css +0 -67
  225. package/dist/templates/next-app/src/styles/css/antd-themes/menu/index.css +0 -3
  226. package/dist/templates/next-app/src/styles/css/antd-themes/menu/pink.css +0 -67
  227. package/dist/templates/next-app/src/styles/css/antd-themes/no-context.css +0 -34
  228. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/_default.css +0 -34
  229. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/dark.css +0 -31
  230. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/index.css +0 -3
  231. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/pink.css +0 -36
  232. package/dist/templates/next-app/src/styles/css/antd-themes/table/_default.css +0 -44
  233. package/dist/templates/next-app/src/styles/css/antd-themes/table/dark.css +0 -43
  234. package/dist/templates/next-app/src/styles/css/antd-themes/table/index.css +0 -3
  235. package/dist/templates/next-app/src/styles/css/antd-themes/table/pink.css +0 -43
  236. package/dist/templates/next-app/src/styles/css/index.css +0 -6
  237. package/dist/templates/next-app/src/styles/css/page.css +0 -20
  238. package/dist/templates/next-app/src/styles/css/scrollbar.css +0 -34
  239. package/dist/templates/next-app/src/styles/css/tailwind.css +0 -5
  240. package/dist/templates/next-app/src/styles/css/themes/_default.css +0 -30
  241. package/dist/templates/next-app/src/styles/css/themes/dark.css +0 -30
  242. package/dist/templates/next-app/src/styles/css/themes/index.css +0 -3
  243. package/dist/templates/next-app/src/styles/css/themes/pink.css +0 -30
  244. package/dist/templates/next-app/src/styles/css/zIndex.css +0 -9
  245. package/dist/templates/next-app/src/uikit/components/AdminLayout.tsx +0 -150
  246. package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +0 -39
  247. package/dist/templates/next-app/src/uikit/components/ClientRootProvider.tsx +0 -64
  248. package/dist/templates/next-app/src/uikit/components/ClientSeo.tsx +0 -36
  249. package/dist/templates/next-app/src/uikit/components/ClinetRenderProvider.tsx +0 -42
  250. package/dist/templates/next-app/src/uikit/components/EditableCell.tsx +0 -118
  251. package/dist/templates/next-app/src/uikit/components/FeatureItem.tsx +0 -13
  252. package/dist/templates/next-app/src/uikit/components/IOCProvider.tsx +0 -34
  253. package/dist/templates/next-app/src/uikit/components/LocaleLink.tsx +0 -50
  254. package/dist/templates/next-app/src/uikit/components/With.tsx +0 -17
  255. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportButton.tsx +0 -62
  256. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportEvent.ts +0 -28
  257. package/dist/templates/next-app/src/uikit/components/localesImportButton/import.module.css +0 -6
  258. package/dist/templates/next-app/src/uikit/components-app/AdminButton.tsx +0 -29
  259. package/dist/templates/next-app/src/uikit/components-app/AppBridge.tsx +0 -17
  260. package/dist/templates/next-app/src/uikit/components-app/AppRoutePage.tsx +0 -105
  261. package/dist/templates/next-app/src/uikit/components-app/AuthButton.tsx +0 -20
  262. package/dist/templates/next-app/src/uikit/components-app/LanguageSwitcher.tsx +0 -75
  263. package/dist/templates/next-app/src/uikit/components-app/LogoutButton.tsx +0 -45
  264. package/dist/templates/next-app/src/uikit/components-app/ThemeSwitcher.tsx +0 -144
  265. package/dist/templates/next-app/src/uikit/components-pages/LanguageSwitcher.tsx +0 -98
  266. package/dist/templates/next-app/src/uikit/components-pages/PagesRoutePage.tsx +0 -93
  267. package/dist/templates/next-app/src/uikit/context/IOCContext.ts +0 -25
  268. package/dist/templates/next-app/src/uikit/hook/useI18nInterface.ts +0 -22
  269. package/dist/templates/next-app/src/uikit/hook/useIOC.ts +0 -37
  270. package/dist/templates/next-app/src/uikit/hook/useStrictEffect.ts +0 -32
  271. package/dist/templates/next-app/src/uikit/hook/useWarnTranslations.ts +0 -11
  272. package/dist/templates/next-app/src/uikit/utils/getHashParams.ts +0 -8
  273. package/dist/templates/next-app/src/uikit/utils/getHashVerifyEmailParams.ts +0 -42
  274. package/dist/templates/next-app/tailwind.config.ts +0 -8
  275. package/dist/templates/next-app/tsconfig.json +0 -39
  276. package/dist/templates/node-lib/__tests__/readJson.test.ts +0 -26
  277. package/dist/templates/node-lib/bin/test.js +0 -30
  278. package/dist/templates/node-lib/package.json +0 -66
  279. package/dist/templates/node-lib/rollup.config.js +0 -79
  280. package/dist/templates/node-lib/src/index.ts +0 -7
  281. package/dist/templates/node-lib/src/readJson.ts +0 -12
  282. package/dist/templates/node-lib/tsconfig.json +0 -23
  283. package/dist/templates/pack-app/README.md +0 -108
  284. package/dist/templates/pack-app/eslint.config.js +0 -97
  285. package/dist/templates/pack-app/fe-config.json +0 -35
  286. package/dist/templates/pack-app/package.json +0 -86
  287. package/dist/templates/pack-app/pnpm-workspace.yaml +0 -2
  288. package/dist/templates/pack-app/tsconfig.json +0 -9
  289. package/dist/templates/pack-app/tsconfig.test.json +0 -10
  290. package/dist/templates/pack-app/vite.config.ts +0 -14
  291. package/dist/templates/react-app/.env.template +0 -22
  292. package/dist/templates/react-app/.prettierignore +0 -17
  293. package/dist/templates/react-app/README.en.md +0 -274
  294. package/dist/templates/react-app/README.md +0 -273
  295. package/dist/templates/react-app/__tests__/__mocks__/BootstrapTest.ts +0 -16
  296. package/dist/templates/react-app/__tests__/__mocks__/MockAppConfig.ts +0 -48
  297. package/dist/templates/react-app/__tests__/__mocks__/MockDialogHandler.ts +0 -17
  298. package/dist/templates/react-app/__tests__/__mocks__/MockLogger.ts +0 -14
  299. package/dist/templates/react-app/__tests__/__mocks__/components/TestApp.tsx +0 -38
  300. package/dist/templates/react-app/__tests__/__mocks__/components/TestBootstrapsProvider.tsx +0 -53
  301. package/dist/templates/react-app/__tests__/__mocks__/components/TestRouter.tsx +0 -46
  302. package/dist/templates/react-app/__tests__/__mocks__/components/index.ts +0 -12
  303. package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +0 -96
  304. package/dist/templates/react-app/__tests__/__mocks__/i18nextHttpBackend.ts +0 -110
  305. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOC.ts +0 -55
  306. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOCRegister.ts +0 -74
  307. package/dist/templates/react-app/__tests__/setup/index.ts +0 -1
  308. package/dist/templates/react-app/__tests__/setup/setupGlobal.ts +0 -64
  309. package/dist/templates/react-app/__tests__/src/App.structure.test.tsx +0 -115
  310. package/dist/templates/react-app/__tests__/src/base/cases/AppConfig.test.ts +0 -288
  311. package/dist/templates/react-app/__tests__/src/base/cases/DialogHandler.test.ts +0 -226
  312. package/dist/templates/react-app/__tests__/src/base/cases/I18nKeyErrorPlugin.test.ts +0 -178
  313. package/dist/templates/react-app/__tests__/src/base/cases/InversifyContainer.test.ts +0 -181
  314. package/dist/templates/react-app/__tests__/src/base/cases/PublicAssetsPath.test.ts +0 -61
  315. package/dist/templates/react-app/__tests__/src/base/cases/RequestLogger.test.ts +0 -177
  316. package/dist/templates/react-app/__tests__/src/base/cases/RequestStatusCatcher.test.ts +0 -191
  317. package/dist/templates/react-app/__tests__/src/base/cases/RouterLoader.test.ts +0 -245
  318. package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +0 -240
  319. package/dist/templates/react-app/__tests__/src/core/IOC.test.ts +0 -242
  320. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapClient.test.ts +0 -135
  321. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapsApp.test.ts +0 -74
  322. package/dist/templates/react-app/__tests__/src/main.test.tsx +0 -46
  323. package/dist/templates/react-app/__tests__/src/uikit/components/BaseHeader.test.tsx +0 -97
  324. package/dist/templates/react-app/__tests__/src/uikit/components/chatMessage/ChatRoot.test.tsx +0 -274
  325. package/dist/templates/react-app/config/IOCIdentifier.ts +0 -91
  326. package/dist/templates/react-app/config/Identifier/common/common.error.ts +0 -34
  327. package/dist/templates/react-app/config/Identifier/common/common.ts +0 -62
  328. package/dist/templates/react-app/config/Identifier/common/index.ts +0 -2
  329. package/dist/templates/react-app/config/Identifier/components/component.chatMessage.ts +0 -56
  330. package/dist/templates/react-app/config/Identifier/components/component.messageBaseList.ts +0 -103
  331. package/dist/templates/react-app/config/Identifier/index.ts +0 -2
  332. package/dist/templates/react-app/config/Identifier/pages/index.ts +0 -9
  333. package/dist/templates/react-app/config/Identifier/pages/page.about.ts +0 -189
  334. package/dist/templates/react-app/config/Identifier/pages/page.executor.ts +0 -275
  335. package/dist/templates/react-app/config/Identifier/pages/page.home.ts +0 -71
  336. package/dist/templates/react-app/config/Identifier/pages/page.identifiter.ts +0 -102
  337. package/dist/templates/react-app/config/Identifier/pages/page.jsonStorage.ts +0 -77
  338. package/dist/templates/react-app/config/Identifier/pages/page.login.ts +0 -162
  339. package/dist/templates/react-app/config/Identifier/pages/page.message.ts +0 -20
  340. package/dist/templates/react-app/config/Identifier/pages/page.register.ts +0 -159
  341. package/dist/templates/react-app/config/Identifier/pages/page.request.ts +0 -169
  342. package/dist/templates/react-app/config/app.router.ts +0 -338
  343. package/dist/templates/react-app/config/common.ts +0 -85
  344. package/dist/templates/react-app/config/feapi.mock.json +0 -34
  345. package/dist/templates/react-app/config/i18n/PageI18nInterface.ts +0 -53
  346. package/dist/templates/react-app/config/i18n/aboutI18n.ts +0 -42
  347. package/dist/templates/react-app/config/i18n/chatMessageI18n.ts +0 -17
  348. package/dist/templates/react-app/config/i18n/executorI18n.ts +0 -51
  349. package/dist/templates/react-app/config/i18n/homeI18n.ts +0 -24
  350. package/dist/templates/react-app/config/i18n/i18nConfig.ts +0 -30
  351. package/dist/templates/react-app/config/i18n/identifiter18n.ts +0 -30
  352. package/dist/templates/react-app/config/i18n/jsonStorage18n.ts +0 -27
  353. package/dist/templates/react-app/config/i18n/login18n.ts +0 -42
  354. package/dist/templates/react-app/config/i18n/messageBaseListI18n.ts +0 -22
  355. package/dist/templates/react-app/config/i18n/messageI18n.ts +0 -14
  356. package/dist/templates/react-app/config/i18n/notFoundI18n.ts +0 -34
  357. package/dist/templates/react-app/config/i18n/register18n.ts +0 -40
  358. package/dist/templates/react-app/config/i18n/request18n.ts +0 -41
  359. package/dist/templates/react-app/config/theme.ts +0 -21
  360. package/dist/templates/react-app/docs/en/bootstrap.md +0 -1891
  361. package/dist/templates/react-app/docs/en/components/chat-message-component.md +0 -320
  362. package/dist/templates/react-app/docs/en/components/chat-message-refactor.md +0 -283
  363. package/dist/templates/react-app/docs/en/components/message-base-list-component.md +0 -171
  364. package/dist/templates/react-app/docs/en/development-guide.md +0 -1199
  365. package/dist/templates/react-app/docs/en/env.md +0 -1336
  366. package/dist/templates/react-app/docs/en/global.md +0 -509
  367. package/dist/templates/react-app/docs/en/i18n.md +0 -979
  368. package/dist/templates/react-app/docs/en/index.md +0 -802
  369. package/dist/templates/react-app/docs/en/ioc.md +0 -1365
  370. package/dist/templates/react-app/docs/en/playwright/e2e-tests.md +0 -321
  371. package/dist/templates/react-app/docs/en/playwright/index.md +0 -19
  372. package/dist/templates/react-app/docs/en/playwright/installation-summary.md +0 -332
  373. package/dist/templates/react-app/docs/en/playwright/overview.md +0 -222
  374. package/dist/templates/react-app/docs/en/playwright/quickstart.md +0 -325
  375. package/dist/templates/react-app/docs/en/playwright/reorganization-notes.md +0 -340
  376. package/dist/templates/react-app/docs/en/playwright/setup-complete.md +0 -290
  377. package/dist/templates/react-app/docs/en/playwright/testing-guide.md +0 -565
  378. package/dist/templates/react-app/docs/en/request.md +0 -423
  379. package/dist/templates/react-app/docs/en/router.md +0 -404
  380. package/dist/templates/react-app/docs/en/store.md +0 -1331
  381. package/dist/templates/react-app/docs/en/test-guide.md +0 -976
  382. package/dist/templates/react-app/docs/en/theme.md +0 -424
  383. package/dist/templates/react-app/docs/en/typescript-guide.md +0 -473
  384. package/dist/templates/react-app/docs/en/why-no-globals.md +0 -797
  385. package/dist/templates/react-app/docs/zh/bootstrap.md +0 -1891
  386. package/dist/templates/react-app/docs/zh/components/chat-message-component.md +0 -320
  387. package/dist/templates/react-app/docs/zh/components/chat-message-refactor.md +0 -283
  388. package/dist/templates/react-app/docs/zh/components/message-base-list-component.md +0 -171
  389. package/dist/templates/react-app/docs/zh/development-guide.md +0 -1199
  390. package/dist/templates/react-app/docs/zh/env.md +0 -1336
  391. package/dist/templates/react-app/docs/zh/global.md +0 -511
  392. package/dist/templates/react-app/docs/zh/i18n.md +0 -979
  393. package/dist/templates/react-app/docs/zh/index.md +0 -786
  394. package/dist/templates/react-app/docs/zh/ioc.md +0 -1364
  395. package/dist/templates/react-app/docs/zh/playwright/e2e-tests.md +0 -321
  396. package/dist/templates/react-app/docs/zh/playwright/index.md +0 -19
  397. package/dist/templates/react-app/docs/zh/playwright/installation-summary.md +0 -332
  398. package/dist/templates/react-app/docs/zh/playwright/overview.md +0 -222
  399. package/dist/templates/react-app/docs/zh/playwright/quickstart.md +0 -325
  400. package/dist/templates/react-app/docs/zh/playwright/reorganization-notes.md +0 -340
  401. package/dist/templates/react-app/docs/zh/playwright/setup-complete.md +0 -290
  402. package/dist/templates/react-app/docs/zh/playwright/testing-guide.md +0 -565
  403. package/dist/templates/react-app/docs/zh/request.md +0 -427
  404. package/dist/templates/react-app/docs/zh/router.md +0 -408
  405. package/dist/templates/react-app/docs/zh/store.md +0 -1329
  406. package/dist/templates/react-app/docs/zh/test-guide.md +0 -976
  407. package/dist/templates/react-app/docs/zh/theme.md +0 -424
  408. package/dist/templates/react-app/docs/zh/typescript-guide.md +0 -473
  409. package/dist/templates/react-app/docs/zh/why-no-globals.md +0 -797
  410. package/dist/templates/react-app/e2e/App.spec.ts +0 -319
  411. package/dist/templates/react-app/e2e/fixtures/base.fixture.ts +0 -40
  412. package/dist/templates/react-app/e2e/main.spec.ts +0 -20
  413. package/dist/templates/react-app/e2e/utils/test-helpers.ts +0 -19
  414. package/dist/templates/react-app/eslint.config.mjs +0 -325
  415. package/dist/templates/react-app/index.html +0 -13
  416. package/dist/templates/react-app/makes/generateTs2LocalesOptions.ts +0 -26
  417. package/dist/templates/react-app/package.json +0 -125
  418. package/dist/templates/react-app/playwright.config.ts +0 -79
  419. package/dist/templates/react-app/postcss.config.js +0 -5
  420. package/dist/templates/react-app/public/locales/en/common.json +0 -235
  421. package/dist/templates/react-app/public/locales/zh/common.json +0 -235
  422. package/dist/templates/react-app/public/logo.svg +0 -1
  423. package/dist/templates/react-app/public/router-root/logo.svg +0 -1
  424. package/dist/templates/react-app/src/App.tsx +0 -35
  425. package/dist/templates/react-app/src/assets/react.svg +0 -1
  426. package/dist/templates/react-app/src/base/apis/AiApi.ts +0 -68
  427. package/dist/templates/react-app/src/base/apis/feApi/FeApi.ts +0 -29
  428. package/dist/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +0 -14
  429. package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +0 -86
  430. package/dist/templates/react-app/src/base/apis/feApi/FeApiType.ts +0 -21
  431. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +0 -142
  432. package/dist/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +0 -14
  433. package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +0 -86
  434. package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +0 -70
  435. package/dist/templates/react-app/src/base/cases/AppConfig.ts +0 -123
  436. package/dist/templates/react-app/src/base/cases/DialogHandler.ts +0 -115
  437. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +0 -64
  438. package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +0 -45
  439. package/dist/templates/react-app/src/base/cases/PublicAssetsPath.ts +0 -23
  440. package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +0 -55
  441. package/dist/templates/react-app/src/base/cases/RequestLogger.ts +0 -80
  442. package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +0 -40
  443. package/dist/templates/react-app/src/base/cases/ResourceState.ts +0 -23
  444. package/dist/templates/react-app/src/base/cases/RouterLoader.ts +0 -173
  445. package/dist/templates/react-app/src/base/cases/TranslateI18nInterface.ts +0 -26
  446. package/dist/templates/react-app/src/base/port/ExecutorPageBridgeInterface.ts +0 -23
  447. package/dist/templates/react-app/src/base/port/I18nServiceInterface.ts +0 -10
  448. package/dist/templates/react-app/src/base/port/IOCInterface.ts +0 -38
  449. package/dist/templates/react-app/src/base/port/JSONStoragePageBridgeInterface.ts +0 -21
  450. package/dist/templates/react-app/src/base/port/RequestPageBridgeInterface.ts +0 -23
  451. package/dist/templates/react-app/src/base/port/RequestStatusInterface.ts +0 -5
  452. package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +0 -29
  453. package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +0 -20
  454. package/dist/templates/react-app/src/base/services/BaseLayoutService.ts +0 -61
  455. package/dist/templates/react-app/src/base/services/I18nService.ts +0 -146
  456. package/dist/templates/react-app/src/base/services/IdentifierService.ts +0 -162
  457. package/dist/templates/react-app/src/base/services/RouteService.ts +0 -115
  458. package/dist/templates/react-app/src/base/services/UserBootstrap.ts +0 -45
  459. package/dist/templates/react-app/src/base/services/UserService.ts +0 -88
  460. package/dist/templates/react-app/src/base/types/Page.ts +0 -47
  461. package/dist/templates/react-app/src/base/types/deprecated-antd.d.ts +0 -60
  462. package/dist/templates/react-app/src/base/types/global.d.ts +0 -8
  463. package/dist/templates/react-app/src/core/IOC.ts +0 -28
  464. package/dist/templates/react-app/src/core/bootstraps/BootstrapClient.ts +0 -108
  465. package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +0 -54
  466. package/dist/templates/react-app/src/core/bootstraps/IocIdentifierTest.ts +0 -26
  467. package/dist/templates/react-app/src/core/bootstraps/PrintBootstrap.ts +0 -14
  468. package/dist/templates/react-app/src/core/bootstraps/SaveAppInfo.ts +0 -28
  469. package/dist/templates/react-app/src/core/clientIoc/ClientIOC.ts +0 -47
  470. package/dist/templates/react-app/src/core/clientIoc/ClientIOCRegister.ts +0 -142
  471. package/dist/templates/react-app/src/core/globals.ts +0 -47
  472. package/dist/templates/react-app/src/main.tsx +0 -19
  473. package/dist/templates/react-app/src/pages/404.tsx +0 -19
  474. package/dist/templates/react-app/src/pages/500.tsx +0 -18
  475. package/dist/templates/react-app/src/pages/NoRouteFound.tsx +0 -5
  476. package/dist/templates/react-app/src/pages/auth/Layout.tsx +0 -27
  477. package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +0 -166
  478. package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +0 -226
  479. package/dist/templates/react-app/src/pages/base/AboutPage.tsx +0 -123
  480. package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +0 -467
  481. package/dist/templates/react-app/src/pages/base/HomePage.tsx +0 -81
  482. package/dist/templates/react-app/src/pages/base/IdentifierPage.tsx +0 -117
  483. package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +0 -132
  484. package/dist/templates/react-app/src/pages/base/Layout.tsx +0 -20
  485. package/dist/templates/react-app/src/pages/base/MessagePage.tsx +0 -71
  486. package/dist/templates/react-app/src/pages/base/RedirectPathname.tsx +0 -18
  487. package/dist/templates/react-app/src/pages/base/RequestPage.tsx +0 -193
  488. package/dist/templates/react-app/src/styles/css/antd-themes/_common/_default.css +0 -280
  489. package/dist/templates/react-app/src/styles/css/antd-themes/_common/dark.css +0 -233
  490. package/dist/templates/react-app/src/styles/css/antd-themes/_common/index.css +0 -3
  491. package/dist/templates/react-app/src/styles/css/antd-themes/_common/pink.css +0 -246
  492. package/dist/templates/react-app/src/styles/css/antd-themes/index.css +0 -4
  493. package/dist/templates/react-app/src/styles/css/antd-themes/menu/_default.css +0 -108
  494. package/dist/templates/react-app/src/styles/css/antd-themes/menu/dark.css +0 -67
  495. package/dist/templates/react-app/src/styles/css/antd-themes/menu/index.css +0 -3
  496. package/dist/templates/react-app/src/styles/css/antd-themes/menu/pink.css +0 -67
  497. package/dist/templates/react-app/src/styles/css/antd-themes/no-context.css +0 -34
  498. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/_default.css +0 -34
  499. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/dark.css +0 -31
  500. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/index.css +0 -3
  501. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/pink.css +0 -36
  502. package/dist/templates/react-app/src/styles/css/antd-themes/table/_default.css +0 -44
  503. package/dist/templates/react-app/src/styles/css/antd-themes/table/dark.css +0 -43
  504. package/dist/templates/react-app/src/styles/css/antd-themes/table/index.css +0 -3
  505. package/dist/templates/react-app/src/styles/css/antd-themes/table/pink.css +0 -43
  506. package/dist/templates/react-app/src/styles/css/index.css +0 -6
  507. package/dist/templates/react-app/src/styles/css/page.css +0 -20
  508. package/dist/templates/react-app/src/styles/css/scrollbar.css +0 -34
  509. package/dist/templates/react-app/src/styles/css/tailwind.css +0 -5
  510. package/dist/templates/react-app/src/styles/css/themes/_default.css +0 -30
  511. package/dist/templates/react-app/src/styles/css/themes/dark.css +0 -30
  512. package/dist/templates/react-app/src/styles/css/themes/index.css +0 -3
  513. package/dist/templates/react-app/src/styles/css/themes/pink.css +0 -30
  514. package/dist/templates/react-app/src/styles/css/zIndex.css +0 -9
  515. package/dist/templates/react-app/src/uikit/bridges/ExecutorPageBridge.ts +0 -72
  516. package/dist/templates/react-app/src/uikit/bridges/JSONStoragePageBridge.ts +0 -41
  517. package/dist/templates/react-app/src/uikit/bridges/NavigateBridge.ts +0 -22
  518. package/dist/templates/react-app/src/uikit/bridges/RequestPageBridge.ts +0 -136
  519. package/dist/templates/react-app/src/uikit/components/AppRouterProvider.tsx +0 -35
  520. package/dist/templates/react-app/src/uikit/components/BaseHeader.tsx +0 -51
  521. package/dist/templates/react-app/src/uikit/components/BaseLayoutProvider.tsx +0 -44
  522. package/dist/templates/react-app/src/uikit/components/BaseRouteProvider.tsx +0 -21
  523. package/dist/templates/react-app/src/uikit/components/BaseRouteSeo.tsx +0 -18
  524. package/dist/templates/react-app/src/uikit/components/BootstrapsProvider.tsx +0 -11
  525. package/dist/templates/react-app/src/uikit/components/ClientSeo.tsx +0 -62
  526. package/dist/templates/react-app/src/uikit/components/ComboProvider.tsx +0 -38
  527. package/dist/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +0 -78
  528. package/dist/templates/react-app/src/uikit/components/Loading.tsx +0 -49
  529. package/dist/templates/react-app/src/uikit/components/LocaleLink.tsx +0 -43
  530. package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +0 -58
  531. package/dist/templates/react-app/src/uikit/components/MessageBaseList.tsx +0 -258
  532. package/dist/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +0 -19
  533. package/dist/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +0 -137
  534. package/dist/templates/react-app/src/uikit/components/With.tsx +0 -17
  535. package/dist/templates/react-app/src/uikit/components/chatMessage/ChatMessageBridge.ts +0 -205
  536. package/dist/templates/react-app/src/uikit/components/chatMessage/ChatRoot.tsx +0 -21
  537. package/dist/templates/react-app/src/uikit/components/chatMessage/FocusBar.tsx +0 -108
  538. package/dist/templates/react-app/src/uikit/components/chatMessage/MessageApi.ts +0 -282
  539. package/dist/templates/react-app/src/uikit/components/chatMessage/MessageItem.tsx +0 -102
  540. package/dist/templates/react-app/src/uikit/components/chatMessage/MessagesList.tsx +0 -86
  541. package/dist/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +0 -42
  542. package/dist/templates/react-app/src/uikit/contexts/IOCContext.ts +0 -13
  543. package/dist/templates/react-app/src/uikit/hooks/useAppTranslation.ts +0 -26
  544. package/dist/templates/react-app/src/uikit/hooks/useI18nInterface.ts +0 -25
  545. package/dist/templates/react-app/src/uikit/hooks/useIOC.ts +0 -35
  546. package/dist/templates/react-app/src/uikit/hooks/useNavigateBridge.ts +0 -21
  547. package/dist/templates/react-app/src/uikit/hooks/useRouterI18nGuard.ts +0 -25
  548. package/dist/templates/react-app/src/uikit/hooks/useStrictEffect.ts +0 -31
  549. package/dist/templates/react-app/src/vite-env.d.ts +0 -1
  550. package/dist/templates/react-app/tailwind.config.js +0 -4
  551. package/dist/templates/react-app/tsconfig.app.json +0 -36
  552. package/dist/templates/react-app/tsconfig.e2e.json +0 -24
  553. package/dist/templates/react-app/tsconfig.json +0 -22
  554. package/dist/templates/react-app/tsconfig.node.json +0 -27
  555. package/dist/templates/react-app/tsconfig.test.json +0 -18
  556. package/dist/templates/react-app/vite.config.ts +0 -144
@@ -1,1891 +0,0 @@
1
- # Bootstrap Initializer
2
-
3
- ## 📋 Table of Contents
4
-
5
- - [What is Bootstrap](#-what-is-bootstrap)
6
- - [Why Bootstrap is Needed](#-why-bootstrap-is-needed)
7
- - [Core Concepts](#-core-concepts)
8
- - [Workflow](#-workflow)
9
- - [Implementation in the Project](#-implementation-in-the-project)
10
- - [Plugin System](#-plugin-system)
11
- - [Practical Examples](#-practical-examples)
12
- - [Testing: Core Advantage of Bootstrap](#-testing-core-advantage-of-bootstrap)
13
- - [Best Practices](#-best-practices)
14
- - [FAQ](#-faq)
15
-
16
- ---
17
-
18
- ## 🎯 What is Bootstrap
19
-
20
- Bootstrap (Initializer) is the application's **initialization manager**, responsible for executing all necessary initialization logic before the application renders.
21
-
22
- ### Core Responsibilities
23
-
24
- ```
25
- ┌──────────────────────────────────────────────────┐
26
- │ Bootstrap Initializer │
27
- │ ┌────────────────────────────────────────────┐ │
28
- │ │ 1. Create IOC Container │ │
29
- │ │ 2. Inject Environment Variables │ │
30
- │ │ 3. Encapsulate Global Variables │ │
31
- │ │ 4. Register Business Plugins │ │
32
- │ │ 5. Execute Initialization Logic │ │
33
- │ └────────────────────────────────────────────┘ │
34
- └──────────────────────────────────────────────────┘
35
-
36
- Application Starts Rendering
37
- ```
38
-
39
- ### Understanding by Analogy
40
-
41
- Just like when a computer boots up, it needs to:
42
-
43
- - ✅ Load drivers
44
- - ✅ Start system services
45
- - ✅ Check hardware status
46
- - ✅ Initialize user environment
47
-
48
- Bootstrap does similar things when the application starts:
49
-
50
- - ✅ Initialize IOC container (dependency management)
51
- - ✅ Inject environment configuration
52
- - ✅ Encapsulate browser APIs
53
- - ✅ Execute business initialization (user authentication, API configuration, etc.)
54
-
55
- ---
56
-
57
- ## 🤔 Why Bootstrap is Needed
58
-
59
- ### Problem: Pain Points of Traditional Approaches
60
-
61
- #### Example 1: Components Mixed with Initialization Logic
62
-
63
- ```typescript
64
- // ❌ Traditional approach: handling initialization in components
65
- function App() {
66
- const [loading, setLoading] = useState(true);
67
- const [user, setUser] = useState(null);
68
- const [error, setError] = useState(null);
69
-
70
- useEffect(() => {
71
- // Initialization logic mixed in component
72
- fetchUserInfo()
73
- .then(user => {
74
- setUser(user);
75
- // Also need to check permissions
76
- if (!user.hasPermission) {
77
- window.location.href = '/login';
78
- }
79
- })
80
- .catch(error => {
81
- setError(error);
82
- })
83
- .finally(() => {
84
- setLoading(false);
85
- });
86
- }, []);
87
-
88
- if (loading) return <div>Loading...</div>;
89
- if (error) return <div>Error: {error.message}</div>;
90
-
91
- return <Router />;
92
- }
93
- ```
94
-
95
- **Problems:**
96
-
97
- - 😰 **Component overload**: UI components shouldn't handle business initialization
98
- - 😰 **Complex state management**: Need to manage multiple states (loading, user, error)
99
- - 😰 **Hard to test**: Initialization logic coupled with UI logic
100
- - 😰 **Hard to reuse**: Initialization logic cannot be reused in other projects
101
- - 😰 **Difficult to maintain**: Business logic changes affect component structure
102
-
103
- #### Example 2: Multi-condition Initialization
104
-
105
- ```typescript
106
- // ❌ More complex scenario: multiple initialization steps
107
- function App() {
108
- const [loading, setLoading] = useState(true);
109
- const [userInfo, setUserInfo] = useState(null);
110
- const [permissions, setPermissions] = useState([]);
111
- const [i18nLoaded, setI18nLoaded] = useState(false);
112
- const [apiConfigured, setApiConfigured] = useState(false);
113
- const location = useLocation();
114
-
115
- useEffect(() => {
116
- const init = async () => {
117
- try {
118
- // Step 1: Configure API
119
- await configureAPI();
120
- setApiConfigured(true);
121
-
122
- // Step 2: Load internationalization
123
- await loadI18n();
124
- setI18nLoaded(true);
125
-
126
- // Step 3: Check user authentication
127
- if (location.pathname !== '/login') {
128
- const user = await fetchUserInfo();
129
- setUserInfo(user);
130
-
131
- // Step 4: Load permissions
132
- const perms = await fetchPermissions(user.id);
133
- setPermissions(perms);
134
-
135
- // Step 5: Permission check
136
- if (!hasRequiredPermission(perms, location.pathname)) {
137
- window.location.href = '/403';
138
- return;
139
- }
140
- }
141
- } catch (error) {
142
- console.error('Initialization failed:', error);
143
- window.location.href = '/error';
144
- } finally {
145
- setLoading(false);
146
- }
147
- };
148
-
149
- init();
150
- }, [location.pathname]);
151
-
152
- // Also need to handle various loading states...
153
- if (loading || !apiConfigured || !i18nLoaded) {
154
- return <LoadingScreen />;
155
- }
156
-
157
- return <Router />;
158
- }
159
- ```
160
-
161
- **Problems Further Aggravated:**
162
-
163
- - 😰😰😰 **State explosion**: Need to manage multiple initialization states
164
- - 😰😰😰 **Hard to extend**: Adding new initialization steps makes code more complex
165
- - 😰😰😰 **Complex error handling**: Each step may fail, requiring extensive error handling code
166
- - 😰😰😰 **Implicit dependencies**: Dependencies between steps are not clear
167
-
168
- ### Solution: Using Bootstrap
169
-
170
- ```typescript
171
- // ✅ Using Bootstrap: components become cleaner
172
- function App() {
173
- return (
174
- <BootstrapsProvider>
175
- <ComboProvider themeConfig={themeConfig}>
176
- <AppRouterProvider pages={allPages} />
177
- </ComboProvider>
178
- </BootstrapsProvider>
179
- );
180
- }
181
-
182
- // All initialization logic handled in Bootstrap
183
- const bootstrap = new Bootstrap({
184
- root: window,
185
- logger,
186
- ioc: { manager: IOC, register: new IocRegisterImpl({ pathname, appConfig }) },
187
- envOptions: { /* environment variable config */ },
188
- globalOptions: { /* global variable config */ }
189
- });
190
-
191
- // Register initialization plugins
192
- bootstrap.use([
193
- IOC(I18nService), // Internationalization service
194
- new UserApiBootstrap(), // User API configuration
195
- new FeApiBootstrap(), // Business API configuration
196
- IOC(UserService) // User authentication service
197
- ]);
198
-
199
- // Start application
200
- await bootstrap.initialize();
201
- await bootstrap.start();
202
- ```
203
-
204
- **Advantages:**
205
-
206
- - ✅ **Clear component responsibilities**: UI components only responsible for rendering
207
- - ✅ **Logic separation**: Initialization logic independent of UI
208
- - ✅ **Easy to test**: Can independently test each initialization step
209
- - ✅ **Easy to extend**: Adding new initialization steps only requires adding new plugins
210
- - ✅ **Easy to reuse**: Same initialization logic can be used in different projects
211
-
212
- ---
213
-
214
- ## 💡 Core Concepts
215
-
216
- ### 1. Plugin Architecture
217
-
218
- Bootstrap adopts a plugin design where each plugin is responsible for a specific initialization task.
219
-
220
- ```typescript
221
- // Plugin interface
222
- export interface BootstrapExecutorPlugin {
223
- readonly pluginName: string;
224
-
225
- // Execute before initialization
226
- onBefore?(context: BootstrapContext): void | Promise<void>;
227
-
228
- // Execute during initialization
229
- onExecute?(context: BootstrapContext): void | Promise<void>;
230
-
231
- // Execute after initialization
232
- onAfter?(context: BootstrapContext): void | Promise<void>;
233
-
234
- // Error handling
235
- onError?(error: Error, context: BootstrapContext): void | Promise<void>;
236
- }
237
- ```
238
-
239
- ### 2. Lifecycle
240
-
241
- ```
242
- ┌────────────────────────────────────────────────┐
243
- │ Bootstrap Lifecycle │
244
- │ │
245
- │ initialize() │
246
- │ ├── Create IOC container │
247
- │ ├── Inject environment variables │
248
- │ └── Encapsulate global variables │
249
- │ │
250
- │ start() │
251
- │ ├── onBefore: Pre-initialization │
252
- │ │ ├── Configure API │
253
- │ │ ├── Load internationalization │
254
- │ │ └── Check user authentication │
255
- │ │ │
256
- │ ├── onExecute: Execute main logic │
257
- │ │ └── Execute business initialization │
258
- │ │ │
259
- │ ├── onAfter: Post-processing │
260
- │ │ └── Cleanup resources, log records │
261
- │ │ │
262
- │ └── onError: Error handling │
263
- │ └── Error capture and handling │
264
- └────────────────────────────────────────────────┘
265
- ```
266
-
267
- ### 3. Dependency Injection
268
-
269
- Bootstrap is deeply integrated with the IOC container, and all plugins can obtain services through dependency injection.
270
-
271
- ```typescript
272
- @injectable()
273
- export class UserService implements ExecutorPlugin {
274
- readonly pluginName = 'UserService';
275
-
276
- constructor(
277
- @inject(UserApi) private api: UserApi,
278
- @inject(IOCIdentifier.AppConfig) private config: AppConfig,
279
- @inject(IOCIdentifier.LocalStorageEncrypt) private storage: Storage
280
- ) {}
281
-
282
- async onBefore(): Promise<void> {
283
- // Use injected dependencies to execute initialization
284
- const token = this.storage.getItem('token');
285
- if (token) {
286
- await this.api.getUserInfo(token);
287
- }
288
- }
289
- }
290
- ```
291
-
292
- ---
293
-
294
- ## 🔄 Workflow
295
-
296
- ### Complete Workflow Diagram
297
-
298
- ```
299
- ┌─────────────────────────────────────────────────────────────┐
300
- │ 1. main.tsx: Application entry point │
301
- │ BootstrapClient.main({ root: window, bootHref, ioc }) │
302
- └────────────────────┬────────────────────────────────────────┘
303
-
304
- ┌─────────────────────────────────────────────────────────────┐
305
- │ 2. BootstrapClient: Create Bootstrap instance │
306
- │ - Create IOC container │
307
- │ - Configure environment variable injection │
308
- │ - Configure global variable encapsulation │
309
- └────────────────────┬────────────────────────────────────────┘
310
-
311
- ┌─────────────────────────────────────────────────────────────┐
312
- │ 3. Bootstrap.initialize(): Initialize │
313
- │ ✅ IOC container initialization │
314
- │ ✅ Environment variables injected to AppConfig │
315
- │ ✅ Global variables encapsulated (localStorage, window) │
316
- └────────────────────┬────────────────────────────────────────┘
317
-
318
- ┌─────────────────────────────────────────────────────────────┐
319
- │ 4. BootstrapsRegistry: Register business plugins │
320
- │ - I18nService: Internationalization service │
321
- │ - UserApiBootstrap: User API configuration │
322
- │ - FeApiBootstrap: Business API configuration │
323
- │ - UserService: User authentication service │
324
- └────────────────────┬────────────────────────────────────────┘
325
-
326
- ┌─────────────────────────────────────────────────────────────┐
327
- │ 5. Bootstrap.start(): Start │
328
- │ ↓ │
329
- │ onBefore phase: │
330
- │ ├── I18nService.onBefore() → Load translation resources │
331
- │ ├── UserApiBootstrap.onBefore() → Configure API plugins │
332
- │ ├── FeApiBootstrap.onBefore() → Configure business API │
333
- │ └── UserService.onBefore() → Check user authentication │
334
- │ ↓ │
335
- │ onExecute phase: │
336
- │ └── Execute plugin main logic │
337
- │ ↓ │
338
- │ onAfter phase: │
339
- │ └── Cleanup and logging │
340
- └────────────────────┬────────────────────────────────────────┘
341
-
342
- ┌─────────────────────────────────────────────────────────────┐
343
- │ 6. React rendering │
344
- │ ReactDOM.render(<App />) │
345
- └─────────────────────────────────────────────────────────────┘
346
- ```
347
-
348
- ---
349
-
350
- ## 🛠️ Implementation in the Project
351
-
352
- ### File Structure
353
-
354
- ```
355
- src/
356
- ├── main.tsx # Application entry point
357
- ├── core/
358
- │ ├── bootstraps/
359
- │ │ ├── BootstrapClient.ts # Bootstrap initializer
360
- │ │ ├── BootstrapsRegistry.ts # Plugin registry
361
- │ │ ├── PrintBootstrap.ts # Print logging plugin
362
- │ │ └── IocIdentifierTest.ts # IOC test plugin
363
- │ ├── globals.ts # Global variable encapsulation
364
- │ └── clientIoc/
365
- │ ├── ClientIOC.ts # IOC container
366
- │ └── ClientIOCRegister.ts # IOC registrar
367
- ├── base/
368
- │ ├── services/
369
- │ │ ├── UserService.ts # User service (plugin)
370
- │ │ └── I18nService.ts # Internationalization service (plugin)
371
- │ └── apis/
372
- │ ├── userApi/
373
- │ │ └── UserApiBootstrap.ts # User API configuration plugin
374
- │ └── feApi/
375
- │ └── FeApiBootstrap.ts # Business API configuration plugin
376
- └── uikit/
377
- └── components/
378
- └── BootstrapsProvider.tsx # Bootstrap Provider
379
- ```
380
-
381
- ### 1. Entry File: main.tsx
382
-
383
- ```typescript
384
- // src/main.tsx
385
- import 'reflect-metadata';
386
- import { StrictMode } from 'react';
387
- import { createRoot } from 'react-dom/client';
388
- import App from './App.tsx';
389
- import { BootstrapClient } from './core/bootstraps/BootstrapClient';
390
- import { clientIOC } from './core/clientIoc/ClientIOC.ts';
391
-
392
- // 🚀 Start Bootstrap
393
- BootstrapClient.main({
394
- root: window, // Inject browser environment
395
- bootHref: window.location.href, // Inject startup URL
396
- ioc: clientIOC // Inject IOC container
397
- });
398
-
399
- // Render React application
400
- createRoot(document.getElementById('root')!).render(
401
- <StrictMode>
402
- <App />
403
- </StrictMode>
404
- );
405
- ```
406
-
407
- ### 2. Bootstrap Initializer: BootstrapClient.ts
408
-
409
- ```typescript
410
- // src/core/bootstraps/BootstrapClient.ts
411
- import { Bootstrap } from '@qlover/corekit-bridge';
412
- import { envBlackList, envPrefix, browserGlobalsName } from '@config/common';
413
- import * as globals from '../globals';
414
- import { BootstrapsRegistry } from './BootstrapsRegistry';
415
-
416
- export class BootstrapClient {
417
- static async main(args: BootstrapClientArgs): Promise<BootstrapClientArgs> {
418
- const { root, bootHref, ioc, iocRegister } = args;
419
- const { logger, appConfig } = globals;
420
-
421
- // 1️⃣ Create IOC container
422
- const IOC = ioc.create({
423
- pathname: bootHref,
424
- appConfig: appConfig
425
- });
426
-
427
- // 2️⃣ Create Bootstrap instance
428
- const bootstrap = new Bootstrap({
429
- root,
430
- logger,
431
- // IOC container configuration
432
- ioc: {
433
- manager: IOC,
434
- register: iocRegister
435
- },
436
- // Environment variable injection configuration
437
- envOptions: {
438
- target: appConfig, // Inject to AppConfig
439
- source: Object.assign({}, import.meta.env, {
440
- [envPrefix + 'BOOT_HREF']: bootHref // Add startup URL
441
- }),
442
- prefix: envPrefix, // Environment variable prefix
443
- blackList: envBlackList // Blacklist
444
- },
445
- // Global variable encapsulation configuration
446
- globalOptions: {
447
- sources: globals, // Encapsulated global variables
448
- target: browserGlobalsName // Mount target
449
- }
450
- });
451
-
452
- try {
453
- logger.info('bootstrap start...');
454
-
455
- // 3️⃣ Initialize Bootstrap
456
- await bootstrap.initialize();
457
-
458
- // 4️⃣ Register business plugins
459
- const bootstrapsRegistry = new BootstrapsRegistry(IOC);
460
-
461
- // 5️⃣ Start application
462
- await bootstrap.use(bootstrapsRegistry.register()).start();
463
-
464
- logger.info('bootstrap completed successfully');
465
- } catch (error) {
466
- logger.error(`${appConfig.appName} startup error:`, error);
467
- }
468
-
469
- return args;
470
- }
471
- }
472
- ```
473
-
474
- **Key Step Analysis:**
475
-
476
- 1. **Create IOC Container** - Manage all dependencies uniformly
477
- 2. **Create Bootstrap Instance** - Configure initialization parameters
478
- 3. **Initialize** - Execute IOC, environment variables, and global variable initialization
479
- 4. **Register Plugins** - Add business initialization logic
480
- 5. **Start** - Execute lifecycle methods of all plugins
481
-
482
- ### 3. Plugin Registry: BootstrapsRegistry.ts
483
-
484
- ```typescript
485
- // src/core/bootstraps/BootstrapsRegistry.ts
486
- import { IOCIdentifier } from '@config/IOCIdentifier';
487
- import { UserApiBootstarp } from '@/base/apis/userApi/UserApiBootstarp';
488
- import { FeApiBootstarp } from '@/base/apis/feApi/FeApiBootstarp';
489
- import { AiApiBootstarp } from '@/base/apis/AiApi';
490
-
491
- export class BootstrapsRegistry {
492
- constructor(
493
- protected IOC: IOCFunctionInterface<IOCIdentifierMap, IOCContainerInterface>
494
- ) {}
495
-
496
- get appConfig(): EnvConfigInterface {
497
- return this.IOC(IOCIdentifier.AppConfig);
498
- }
499
-
500
- /**
501
- * Register all business plugins
502
- */
503
- register(): BootstrapExecutorPlugin[] {
504
- const IOC = this.IOC;
505
-
506
- const bootstrapList = [
507
- // 1. Internationalization service (needs to be initialized first)
508
- IOC(IOCIdentifier.I18nServiceInterface),
509
-
510
- // 2. API configuration plugins
511
- new UserApiBootstarp(), // User API
512
- new FeApiBootstarp(), // Business API
513
- AiApiBootstarp, // AI API
514
-
515
- // 3. Other plugins
516
- IOC(IOCIdentifier.I18nKeyErrorPlugin),
517
- IOC(IOCIdentifier.ProcesserExecutorInterface)
518
- ];
519
-
520
- // Development environment: Add debug plugins
521
- if (!this.appConfig.isProduction) {
522
- bootstrapList.push(printBootstrap);
523
- }
524
-
525
- return bootstrapList;
526
- }
527
- }
528
- ```
529
-
530
- **Plugin Order is Important:**
531
-
532
- - ✅ Internationalization service initialized first (other plugins may need translations)
533
- - ✅ API configuration before business logic
534
- - ✅ Development tools only loaded in development environment
535
-
536
- ---
537
-
538
- ## 🔌 Plugin System
539
-
540
- ### Plugin Types
541
-
542
- #### 1. Service Plugins (via IOC Injection)
543
-
544
- ```typescript
545
- // src/base/services/I18nService.ts
546
- @injectable()
547
- export class I18nService implements ExecutorPlugin {
548
- readonly pluginName = 'I18nService';
549
-
550
- constructor(@inject(IOCIdentifier.AppConfig) private config: AppConfig) {}
551
-
552
- /**
553
- * Load translation resources before Bootstrap starts
554
- */
555
- async onBefore(): Promise<void> {
556
- await i18next.init({
557
- lng: this.config.defaultLanguage,
558
- fallbackLng: 'en',
559
- resources: this.loadResources()
560
- });
561
- }
562
-
563
- private loadResources() {
564
- // Load translation resources
565
- return {
566
- /* ... */
567
- };
568
- }
569
- }
570
-
571
- // Registration method
572
- bootstrap.use([
573
- IOC(IOCIdentifier.I18nServiceInterface) // Get from IOC container
574
- ]);
575
- ```
576
-
577
- #### 2. Configuration Plugins (Independent Instances)
578
-
579
- ```typescript
580
- // src/base/apis/userApi/UserApiBootstrap.ts
581
- export class UserApiBootstarp implements BootstrapExecutorPlugin {
582
- readonly pluginName = 'UserApiBootstarp';
583
-
584
- /**
585
- * Configure User API plugins
586
- */
587
- onBefore({ parameters: { ioc } }: BootstrapContext): void {
588
- const userApi = ioc.get<UserApi>(UserApi);
589
-
590
- // Add URL handling plugin
591
- userApi.usePlugin(new FetchURLPlugin());
592
-
593
- // Add Mock plugin (development environment)
594
- userApi.usePlugin(ioc.get(IOCIdentifier.ApiMockPlugin));
595
-
596
- // Add request logging plugin
597
- userApi.usePlugin(ioc.get(RequestLogger));
598
- }
599
- }
600
-
601
- // Registration method
602
- bootstrap.use([
603
- new UserApiBootstarp() // Create instance directly
604
- ]);
605
- ```
606
-
607
- #### 3. Business Logic Plugins
608
-
609
- ```typescript
610
- // src/base/services/UserService.ts
611
- @injectable()
612
- export class UserService
613
- extends UserAuthService<UserInfo>
614
- implements ExecutorPlugin
615
- {
616
- readonly pluginName = 'UserService';
617
-
618
- constructor(
619
- @inject(IOCIdentifier.RouteServiceInterface)
620
- protected routerService: RouteServiceInterface,
621
- @inject(UserApi)
622
- userApi: UserAuthApiInterface<UserInfo>,
623
- @inject(IOCIdentifier.AppConfig) appConfig: AppConfig,
624
- @inject(IOCIdentifier.LocalStorageEncrypt)
625
- storage: SyncStorageInterface<string, string>
626
- ) {
627
- super(userApi, {
628
- userStorage: {
629
- key: appConfig.userInfoStorageKey,
630
- storage: storage
631
- },
632
- credentialStorage: {
633
- key: appConfig.userTokenStorageKey,
634
- storage: storage
635
- }
636
- });
637
- }
638
-
639
- /**
640
- * Check user authentication status on application startup
641
- */
642
- async onBefore(): Promise<void> {
643
- // If already logged in, return directly
644
- if (this.isAuthenticated()) {
645
- return;
646
- }
647
-
648
- // Try to restore user info from storage
649
- const userToken = this.getToken();
650
- if (!userToken) {
651
- throw new AppError('NO_USER_TOKEN');
652
- }
653
-
654
- // Get user info
655
- await this.userInfo();
656
- }
657
-
658
- getToken(): string | null {
659
- return this.credential();
660
- }
661
- }
662
- ```
663
-
664
- ### Plugin Lifecycle Details
665
-
666
- ```typescript
667
- export interface BootstrapExecutorPlugin {
668
- readonly pluginName: string;
669
-
670
- /**
671
- * onBefore: Execute before initialization
672
- *
673
- * Use cases:
674
- * - Configure API clients
675
- * - Load resources (translations, themes, etc.)
676
- * - Check user authentication
677
- * - Initialize third-party libraries
678
- */
679
- onBefore?(context: BootstrapContext): void | Promise<void>;
680
-
681
- /**
682
- * onExecute: Execute during initialization
683
- *
684
- * Use cases:
685
- * - Execute main business logic
686
- * - Start background tasks
687
- */
688
- onExecute?(context: BootstrapContext): void | Promise<void>;
689
-
690
- /**
691
- * onAfter: Execute after initialization
692
- *
693
- * Use cases:
694
- * - Cleanup temporary resources
695
- * - Record startup logs
696
- * - Send analytics data
697
- */
698
- onAfter?(context: BootstrapContext): void | Promise<void>;
699
-
700
- /**
701
- * onError: Error handling
702
- *
703
- * Use cases:
704
- * - Capture plugin errors
705
- * - Error logging
706
- * - Error recovery
707
- */
708
- onError?(error: Error, context: BootstrapContext): void | Promise<void>;
709
- }
710
- ```
711
-
712
- ---
713
-
714
- ## 🎯 Practical Examples
715
-
716
- ### Example 1: Internationalization Plugin
717
-
718
- ```typescript
719
- // src/base/services/I18nService.ts
720
- import i18next from 'i18next';
721
- import { injectable, inject } from 'inversify';
722
- import { IOCIdentifier } from '@config/IOCIdentifier';
723
- import type { AppConfig } from '@/base/cases/AppConfig';
724
-
725
- @injectable()
726
- export class I18nService implements ExecutorPlugin {
727
- readonly pluginName = 'I18nService';
728
-
729
- constructor(@inject(IOCIdentifier.AppConfig) private config: AppConfig) {}
730
-
731
- async onBefore(): Promise<void> {
732
- // Load translation resources
733
- const resources = this.loadAllResources();
734
-
735
- // Initialize i18next
736
- await i18next.init({
737
- lng: this.config.defaultLanguage || 'zh',
738
- fallbackLng: 'en',
739
- resources,
740
- interpolation: {
741
- escapeValue: false
742
- }
743
- });
744
-
745
- console.log('✅ I18n initialized:', i18next.language);
746
- }
747
-
748
- private loadAllResources() {
749
- // Load all translation resources from config files
750
- return {
751
- zh: {
752
- translation: require('@config/i18n/zh').default
753
- },
754
- en: {
755
- translation: require('@config/i18n/en').default
756
- }
757
- };
758
- }
759
-
760
- t(key: string, options?: any): string {
761
- return i18next.t(key, options);
762
- }
763
- }
764
- ```
765
-
766
- ### Example 2: API Configuration Plugin
767
-
768
- ```typescript
769
- // src/base/apis/feApi/FeApiBootstrap.ts
770
- export class FeApiBootstarp implements BootstrapExecutorPlugin {
771
- readonly pluginName = 'FeApiBootstarp';
772
-
773
- onBefore({ parameters: { ioc } }: BootstrapContext): void {
774
- const feApi = ioc.get<FeApi>(FeApi);
775
- const appConfig = ioc.get<AppConfig>(IOCIdentifier.AppConfig);
776
-
777
- // 1. Configure base URL
778
- feApi.setBaseURL(appConfig.apiBaseUrl);
779
-
780
- // 2. Add authentication plugin
781
- feApi.usePlugin(
782
- new AuthTokenPlugin({
783
- getToken: () => {
784
- const storage = ioc.get(IOCIdentifier.LocalStorageEncrypt);
785
- return storage.getItem('token');
786
- }
787
- })
788
- );
789
-
790
- // 3. Add error handling plugin
791
- feApi.usePlugin(
792
- new ErrorHandlerPlugin({
793
- onError: (error) => {
794
- if (error.status === 401) {
795
- // Unauthorized, redirect to login
796
- const router = ioc.get(IOCIdentifier.RouteServiceInterface);
797
- router.push('/login');
798
- }
799
- }
800
- })
801
- );
802
-
803
- // 4. Add request logging plugin (development environment)
804
- if (!appConfig.isProduction) {
805
- feApi.usePlugin(new RequestLoggerPlugin());
806
- }
807
- }
808
- }
809
- ```
810
-
811
- ### Example 3: User Authentication Plugin
812
-
813
- ```typescript
814
- // src/base/services/UserService.ts
815
- @injectable()
816
- export class UserService
817
- extends UserAuthService<UserInfo>
818
- implements ExecutorPlugin
819
- {
820
- readonly pluginName = 'UserService';
821
-
822
- constructor(
823
- @inject(IOCIdentifier.RouteServiceInterface)
824
- protected routerService: RouteServiceInterface,
825
- @inject(UserApi) userApi: UserAuthApiInterface<UserInfo>,
826
- @inject(IOCIdentifier.AppConfig) appConfig: AppConfig,
827
- @inject(IOCIdentifier.LocalStorageEncrypt) storage: SyncStorageInterface
828
- ) {
829
- super(userApi, {
830
- userStorage: {
831
- key: appConfig.userInfoStorageKey,
832
- storage: storage
833
- },
834
- credentialStorage: {
835
- key: appConfig.userTokenStorageKey,
836
- storage: storage
837
- }
838
- });
839
- }
840
-
841
- /**
842
- * Automatically restore user login state on application startup
843
- */
844
- async onBefore(): Promise<void> {
845
- try {
846
- // Check if on login page
847
- if (this.routerService.isLoginPage()) {
848
- return;
849
- }
850
-
851
- // If already have user info, return directly
852
- if (this.isAuthenticated()) {
853
- console.log('✅ User already authenticated');
854
- return;
855
- }
856
-
857
- // Try to restore token from storage
858
- const token = this.getToken();
859
- if (!token) {
860
- // No token, redirect to login
861
- throw new AppError('NO_USER_TOKEN');
862
- }
863
-
864
- // Use token to get user info
865
- const userInfo = await this.userInfo();
866
- console.log('✅ User authenticated:', userInfo.name);
867
- } catch (error) {
868
- // Authentication failed, clear storage and redirect to login
869
- this.clearAuth();
870
- this.routerService.push('/login');
871
- console.log('❌ User authentication failed, redirecting to login');
872
- }
873
- }
874
-
875
- getToken(): string | null {
876
- return this.credential();
877
- }
878
-
879
- private clearAuth() {
880
- this.setCredential(null);
881
- this.setUser(null);
882
- }
883
- }
884
- ```
885
-
886
- ### Example 4: Development Tools Plugin
887
-
888
- ```typescript
889
- // src/core/bootstraps/PrintBootstrap.ts
890
- export const printBootstrap: BootstrapExecutorPlugin = {
891
- pluginName: 'PrintBootstrap',
892
-
893
- onAfter({ parameters: { logger, ioc } }: BootstrapContext): void {
894
- const appConfig = ioc.get<AppConfig>(IOCIdentifier.AppConfig);
895
-
896
- // Print application info
897
- logger.info('🚀 Application started successfully!');
898
- logger.info('📦 App Name:', appConfig.appName);
899
- logger.info('🌍 Environment:', appConfig.env);
900
- logger.info('🔗 API Base URL:', appConfig.apiBaseUrl);
901
-
902
- // Print registered services
903
- logger.info('📋 Registered Services:');
904
- logger.info(' - UserService');
905
- logger.info(' - I18nService');
906
- logger.info(' - RouteService');
907
-
908
- // Print warnings (if any)
909
- if (!appConfig.isProduction && appConfig.mockEnabled) {
910
- logger.warn('⚠️ Mock API is enabled');
911
- }
912
- }
913
- };
914
- ```
915
-
916
- ---
917
-
918
- ## 🧪 Testing: Core Advantage of Bootstrap
919
-
920
- ### Why is Testing So Important?
921
-
922
- One of the **most important advantages** of Bootstrap architecture is **testability**. By separating initialization logic from UI, we can:
923
-
924
- - ✅ Test each plugin independently
925
- - ✅ Easily mock dependencies
926
- - ✅ Run tests quickly (no need to render UI)
927
- - ✅ Improve test coverage
928
-
929
- ### Traditional Approach vs Bootstrap Approach
930
-
931
- #### ❌ Traditional Approach: Components Mixed with Initialization Logic
932
-
933
- ```typescript
934
- // ❌ Traditional component: hard to test
935
- function App() {
936
- const [loading, setLoading] = useState(true);
937
- const [user, setUser] = useState(null);
938
- const [i18nReady, setI18nReady] = useState(false);
939
- const [error, setError] = useState(null);
940
-
941
- useEffect(() => {
942
- const init = async () => {
943
- try {
944
- // 1. Initialize internationalization
945
- await i18next.init({
946
- lng: 'zh',
947
- resources: { /* ... */ }
948
- });
949
- setI18nReady(true);
950
-
951
- // 2. Configure API
952
- api.setBaseURL('https://api.example.com');
953
- api.usePlugin(new AuthPlugin());
954
-
955
- // 3. Check user authentication
956
- const token = localStorage.getItem('token');
957
- if (token) {
958
- const userInfo = await fetch('/api/user', {
959
- headers: { Authorization: `Bearer ${token}` }
960
- }).then(res => res.json());
961
- setUser(userInfo);
962
- }
963
- } catch (err) {
964
- setError(err);
965
- } finally {
966
- setLoading(false);
967
- }
968
- };
969
-
970
- init();
971
- }, []);
972
-
973
- if (loading) return <div>Loading...</div>;
974
- if (error) return <div>Error: {error.message}</div>;
975
-
976
- return <Router />;
977
- }
978
- ```
979
-
980
- **Test Code (Traditional Approach): 😰😰😰 Very Difficult**
981
-
982
- ```typescript
983
- // ❌ Traditional approach testing: full of tricks and hacks
984
- import { describe, it, expect, vi, beforeEach } from 'vitest';
985
- import { render, screen, waitFor } from '@testing-library/react';
986
- import App from './App';
987
-
988
- describe('App (Traditional)', () => {
989
- beforeEach(() => {
990
- // 😰 Need to mock global variables
991
- global.localStorage = {
992
- getItem: vi.fn(),
993
- setItem: vi.fn(),
994
- removeItem: vi.fn(),
995
- clear: vi.fn()
996
- };
997
-
998
- // 😰 Need to mock fetch
999
- global.fetch = vi.fn();
1000
-
1001
- // 😰 Need to mock i18next
1002
- vi.mock('i18next', () => ({
1003
- init: vi.fn().mockResolvedValue(undefined),
1004
- t: vi.fn(key => key)
1005
- }));
1006
- });
1007
-
1008
- it('should initialize and load user', async () => {
1009
- // 😰 Setup complex mocks
1010
- vi.mocked(localStorage.getItem).mockReturnValue('mock-token');
1011
- vi.mocked(fetch).mockResolvedValueOnce({
1012
- ok: true,
1013
- json: async () => ({ id: '1', name: 'John' })
1014
- });
1015
-
1016
- render(<App />);
1017
-
1018
- // 😰 Need to wait for multiple async operations
1019
- await waitFor(() => {
1020
- expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
1021
- }, { timeout: 3000 });
1022
-
1023
- // 😰 Hard to verify intermediate states
1024
- expect(fetch).toHaveBeenCalledWith('/api/user', expect.any(Object));
1025
- });
1026
-
1027
- it('should handle error', async () => {
1028
- // 😰 Each test needs to reset mocks
1029
- vi.mocked(fetch).mockRejectedValueOnce(new Error('Network error'));
1030
-
1031
- render(<App />);
1032
-
1033
- await waitFor(() => {
1034
- expect(screen.getByText(/Error/)).toBeInTheDocument();
1035
- });
1036
- });
1037
-
1038
- // 😰 Problems:
1039
- // 1. Need to mock many global variables (localStorage, fetch, i18next)
1040
- // 2. Tests run slowly (need to render components)
1041
- // 3. Hard to test error scenarios
1042
- // 4. Tests may interfere with each other
1043
- // 5. Hard to test individual initialization steps
1044
- });
1045
- ```
1046
-
1047
- #### ✅ Bootstrap Approach: Independent Plugin Testing
1048
-
1049
- ```typescript
1050
- // ✅ Bootstrap approach: logic and UI separated
1051
- // 1. Plugin implementation
1052
- @injectable()
1053
- export class UserService implements ExecutorPlugin {
1054
- readonly pluginName = 'UserService';
1055
-
1056
- constructor(
1057
- @inject(UserApi) private api: UserApi,
1058
- @inject(IOCIdentifier.LocalStorageEncrypt) private storage: Storage,
1059
- @inject(IOCIdentifier.RouteServiceInterface) private router: RouteService
1060
- ) {}
1061
-
1062
- async onBefore(): Promise<void> {
1063
- const token = this.storage.getItem('token');
1064
- if (!token) {
1065
- throw new AppError('NO_USER_TOKEN');
1066
- }
1067
-
1068
- const userInfo = await this.api.getUserInfo(token);
1069
- this.setUser(userInfo);
1070
- }
1071
- }
1072
-
1073
- // 2. UI component becomes simple
1074
- function App() {
1075
- return (
1076
- <BootstrapsProvider>
1077
- <ComboProvider themeConfig={themeConfig}>
1078
- <AppRouterProvider pages={allPages} />
1079
- </ComboProvider>
1080
- </BootstrapsProvider>
1081
- );
1082
- }
1083
- ```
1084
-
1085
- **Test Code (Bootstrap Approach): 😊😊😊 Very Simple**
1086
-
1087
- ```typescript
1088
- // ✅ Bootstrap approach testing: clear, simple, fast
1089
- import { describe, it, expect, vi, beforeEach } from 'vitest';
1090
- import { UserService } from '@/base/services/UserService';
1091
- import { AppError } from '@/base/cases/AppError';
1092
-
1093
- describe('UserService Plugin', () => {
1094
- let userService: UserService;
1095
- let mockApi: any;
1096
- let mockStorage: any;
1097
- let mockRouter: any;
1098
-
1099
- beforeEach(() => {
1100
- // ✅ Only need to mock dependency interfaces, no global variables
1101
- mockApi = {
1102
- getUserInfo: vi.fn()
1103
- };
1104
-
1105
- mockStorage = {
1106
- getItem: vi.fn(),
1107
- setItem: vi.fn()
1108
- };
1109
-
1110
- mockRouter = {
1111
- push: vi.fn()
1112
- };
1113
-
1114
- // ✅ Create service instance
1115
- userService = new UserService(mockApi, mockStorage, mockRouter);
1116
- });
1117
-
1118
- it('should load user when token exists', async () => {
1119
- // ✅ Setup test data
1120
- mockStorage.getItem.mockReturnValue('mock-token');
1121
- mockApi.getUserInfo.mockResolvedValue({
1122
- id: '1',
1123
- name: 'John Doe'
1124
- });
1125
-
1126
- // ✅ Execute plugin lifecycle
1127
- await userService.onBefore();
1128
-
1129
- // ✅ Clear assertions
1130
- expect(mockStorage.getItem).toHaveBeenCalledWith('token');
1131
- expect(mockApi.getUserInfo).toHaveBeenCalledWith('mock-token');
1132
- expect(userService.getUser()).toEqual({
1133
- id: '1',
1134
- name: 'John Doe'
1135
- });
1136
- });
1137
-
1138
- it('should throw error when token is missing', async () => {
1139
- // ✅ Easy to test error scenarios
1140
- mockStorage.getItem.mockReturnValue(null);
1141
-
1142
- // ✅ Verify errors
1143
- await expect(userService.onBefore()).rejects.toThrow(AppError);
1144
- await expect(userService.onBefore()).rejects.toThrow('NO_USER_TOKEN');
1145
- });
1146
-
1147
- it('should handle API error', async () => {
1148
- // ✅ Easy to simulate API errors
1149
- mockStorage.getItem.mockReturnValue('mock-token');
1150
- mockApi.getUserInfo.mockRejectedValue(new Error('Network error'));
1151
-
1152
- // ✅ Verify error handling
1153
- await expect(userService.onBefore()).rejects.toThrow('Network error');
1154
- });
1155
-
1156
- // ✅ Advantages:
1157
- // 1. No need to mock global variables
1158
- // 2. Tests run fast (no need to render UI)
1159
- // 3. Easy to test error scenarios
1160
- // 4. Tests are completely independent
1161
- // 5. Can test each initialization step individually
1162
- });
1163
- ```
1164
-
1165
- ### Test Complexity Comparison
1166
-
1167
- | Test Scenario | Traditional Approach | Bootstrap Approach | Improvement |
1168
- | ------------------------ | ---------------------------------------------------------- | ------------------------------------------ | ----------- |
1169
- | **Mock Complexity** | 😰😰😰 Need to mock global variables, fetch, i18next, etc. | 😊 Only need to mock dependency interfaces | **80%** |
1170
- | **Test Run Speed** | 😰😰 Slow (need to render components, wait for async) | 😊😊😊 Fast (pure logic testing) | **5-10x** |
1171
- | **Test Error Scenarios** | 😰😰😰 Difficult (need complex mock setups) | 😊😊😊 Simple (directly mock reject) | **90%** |
1172
- | **Test Isolation** | 😰😰 Poor (global variables may interfere) | 😊😊😊 Good (each test independent) | **100%** |
1173
- | **Test Readability** | 😰😰 Poor (full of mocks and hacks) | 😊😊😊 Good (clear inputs/outputs) | **80%** |
1174
- | **Coverage** | 😰😰 Low (hard to cover all branches) | 😊😊😊 High (easy to cover all scenarios) | **50%** |
1175
-
1176
- ### Actual Project Test Examples
1177
-
1178
- #### Example 1: Testing I18n Plugin
1179
-
1180
- ```typescript
1181
- // src/base/services/I18nService.test.ts
1182
- import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
1183
- import { I18nService } from '@/base/services/I18nService';
1184
- import i18n from 'i18next';
1185
-
1186
- // Mock i18next
1187
- vi.mock('i18next', () => ({
1188
- default: {
1189
- use: vi.fn().mockReturnThis(),
1190
- init: vi.fn(),
1191
- t: vi.fn(),
1192
- changeLanguage: vi.fn(),
1193
- language: 'en',
1194
- services: {
1195
- languageDetector: {
1196
- addDetector: vi.fn()
1197
- }
1198
- }
1199
- }
1200
- }));
1201
-
1202
- describe('I18nService', () => {
1203
- let service: I18nService;
1204
-
1205
- beforeEach(() => {
1206
- service = new I18nService('/en/test/path');
1207
- vi.clearAllMocks();
1208
- });
1209
-
1210
- describe('onBefore', () => {
1211
- it('should initialize i18n with correct configuration', () => {
1212
- // ✅ Execute plugin lifecycle
1213
- service.onBefore();
1214
-
1215
- // ✅ Verify initialization configuration
1216
- expect(i18n.use).toHaveBeenCalledTimes(3);
1217
- expect(i18n.init).toHaveBeenCalledWith(
1218
- expect.objectContaining({
1219
- debug: false,
1220
- detection: {
1221
- order: ['pathLanguageDetector', 'navigator', 'localStorage'],
1222
- caches: []
1223
- }
1224
- })
1225
- );
1226
- });
1227
-
1228
- it('should detect language from path correctly', () => {
1229
- service.onBefore();
1230
-
1231
- const detector = vi.mocked(i18n.services.languageDetector.addDetector)
1232
- .mock.calls[0][0];
1233
-
1234
- // ✅ Test language detection logic
1235
- const language = detector.lookup();
1236
- expect(language).toBe('en');
1237
- });
1238
-
1239
- it('should return fallback language for invalid path', () => {
1240
- const invalidService = new I18nService('/invalid/path');
1241
- invalidService.onBefore();
1242
-
1243
- const detector = vi.mocked(i18n.services.languageDetector.addDetector)
1244
- .mock.calls[0][0];
1245
-
1246
- // ✅ Test edge cases
1247
- const language = detector.lookup();
1248
- expect(language).toBe('zh'); // fallback language
1249
- });
1250
- });
1251
-
1252
- describe('changeLanguage', () => {
1253
- it('should change language using i18n', async () => {
1254
- await service.changeLanguage('en');
1255
- expect(i18n.changeLanguage).toHaveBeenCalledWith('en');
1256
- });
1257
-
1258
- it('should handle language change error', async () => {
1259
- // ✅ Test error scenarios
1260
- vi.mocked(i18n.changeLanguage).mockRejectedValueOnce(
1261
- new Error('Change failed')
1262
- );
1263
-
1264
- await expect(service.changeLanguage('en')).rejects.toThrow(
1265
- 'Change failed'
1266
- );
1267
- });
1268
- });
1269
- });
1270
- ```
1271
-
1272
- #### Example 2: Testing Bootstrap Startup Process
1273
-
1274
- ```typescript
1275
- // __tests__/src/core/bootstraps/BootstrapsApp.test.ts
1276
- import { describe, it, expect, beforeEach, vi } from 'vitest';
1277
- import { BootstrapClient } from '@/core/bootstraps/BootstrapClient';
1278
- import type { BootstrapClientArgs } from '@/core/bootstraps/BootstrapClient';
1279
- import { InversifyContainer } from '@/base/cases/InversifyContainer';
1280
- import { createIOCFunction } from '@qlover/corekit-bridge';
1281
- import { browserGlobalsName } from '@config/common';
1282
-
1283
- // Mock dependencies
1284
- vi.mock('@/core/registers/IocRegisterImpl', () => ({
1285
- IocRegisterImpl: vi.fn().mockImplementation(() => ({
1286
- getRegisterList: vi.fn().mockReturnValue([]),
1287
- register: vi.fn()
1288
- }))
1289
- }));
1290
-
1291
- vi.mock('@/core/bootstraps/BootstrapsRegistry', () => ({
1292
- BootstrapsRegistry: vi.fn().mockImplementation(() => ({
1293
- register: vi.fn().mockReturnValue([])
1294
- }))
1295
- }));
1296
-
1297
- describe('BootstrapClient', () => {
1298
- let mockArgs: BootstrapClientArgs;
1299
- let mockIOC: ReturnType<typeof createIOCFunction>;
1300
-
1301
- beforeEach(() => {
1302
- vi.clearAllMocks();
1303
-
1304
- const container = new InversifyContainer();
1305
- mockIOC = createIOCFunction(container);
1306
-
1307
- mockArgs = {
1308
- root: {},
1309
- bootHref: 'http://localhost:3000',
1310
- ioc: {
1311
- create: vi.fn().mockReturnValue(mockIOC)
1312
- }
1313
- };
1314
- });
1315
-
1316
- describe('main', () => {
1317
- it('should initialize bootstrap successfully', async () => {
1318
- // ✅ Execute startup process
1319
- const result = await BootstrapClient.main(mockArgs);
1320
-
1321
- // ✅ Verify startup result
1322
- expect(result.bootHref).toBe('http://localhost:3000');
1323
-
1324
- // ✅ Verify global variable injection
1325
- expect(
1326
- (mockArgs.root as Record<string, unknown>)[browserGlobalsName]
1327
- ).toBeDefined();
1328
-
1329
- const injectedGlobals = (mockArgs.root as Record<string, unknown>)[
1330
- browserGlobalsName
1331
- ] as Record<string, unknown>;
1332
-
1333
- expect(injectedGlobals).toHaveProperty('logger');
1334
- expect(injectedGlobals).toHaveProperty('appConfig');
1335
- });
1336
-
1337
- it('should handle initialization error', async () => {
1338
- // ✅ Test error scenarios
1339
- mockArgs.ioc.create = vi.fn().mockImplementation(() => {
1340
- throw new Error('IOC creation failed');
1341
- });
1342
-
1343
- // ✅ Verify error doesn't crash application
1344
- await expect(BootstrapClient.main(mockArgs)).rejects.toThrow(
1345
- 'IOC creation failed'
1346
- );
1347
- });
1348
- });
1349
- });
1350
- ```
1351
-
1352
- #### Example 3: Testing API Configuration Plugin
1353
-
1354
- ```typescript
1355
- // __tests__/src/base/apis/UserApiBootstrap.test.ts
1356
- import { describe, it, expect, vi, beforeEach } from 'vitest';
1357
- import { UserApiBootstarp } from '@/base/apis/userApi/UserApiBootstarp';
1358
-
1359
- describe('UserApiBootstrap', () => {
1360
- let plugin: UserApiBootstarp;
1361
- let mockContext: any;
1362
- let mockUserApi: any;
1363
-
1364
- beforeEach(() => {
1365
- plugin = new UserApiBootstarp();
1366
-
1367
- // ✅ Create mock context
1368
- mockUserApi = {
1369
- usePlugin: vi.fn()
1370
- };
1371
-
1372
- mockContext = {
1373
- parameters: {
1374
- ioc: {
1375
- get: vi.fn().mockReturnValue(mockUserApi)
1376
- }
1377
- }
1378
- };
1379
- });
1380
-
1381
- it('should have correct plugin name', () => {
1382
- expect(plugin.pluginName).toBe('UserApiBootstarp');
1383
- });
1384
-
1385
- it('should configure API plugins in onBefore', () => {
1386
- // ✅ Execute plugin lifecycle
1387
- plugin.onBefore(mockContext);
1388
-
1389
- // ✅ Verify API configuration
1390
- expect(mockContext.parameters.ioc.get).toHaveBeenCalled();
1391
- expect(mockUserApi.usePlugin).toHaveBeenCalled();
1392
- });
1393
-
1394
- it('should add multiple plugins to API', () => {
1395
- plugin.onBefore(mockContext);
1396
-
1397
- // ✅ Verify multiple plugins added
1398
- expect(mockUserApi.usePlugin).toHaveBeenCalledTimes(3);
1399
- });
1400
- });
1401
- ```
1402
-
1403
- ### Testing Best Practices
1404
-
1405
- #### 1. ✅ Use Vitest Testing Tools
1406
-
1407
- ```typescript
1408
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
1409
-
1410
- describe('MyPlugin', () => {
1411
- beforeEach(() => {
1412
- // ✅ Reset mocks before each test
1413
- vi.clearAllMocks();
1414
- });
1415
-
1416
- afterEach(() => {
1417
- // ✅ Cleanup resources
1418
- vi.restoreAllMocks();
1419
- });
1420
-
1421
- it('should do something', () => {
1422
- // Test logic
1423
- });
1424
- });
1425
- ```
1426
-
1427
- #### 2. ✅ Test Plugin Lifecycle
1428
-
1429
- ```typescript
1430
- describe('UserService Plugin', () => {
1431
- it('should execute onBefore lifecycle', async () => {
1432
- const service = new UserService(mockApi, mockStorage, mockRouter);
1433
-
1434
- // ✅ Test onBefore
1435
- await service.onBefore();
1436
-
1437
- expect(mockApi.getUserInfo).toHaveBeenCalled();
1438
- });
1439
-
1440
- it('should execute onAfter lifecycle', async () => {
1441
- const service = new UserService(mockApi, mockStorage, mockRouter);
1442
-
1443
- // ✅ Test onAfter
1444
- await service.onAfter?.();
1445
-
1446
- // Verify cleanup logic
1447
- });
1448
-
1449
- it('should handle onError lifecycle', async () => {
1450
- const service = new UserService(mockApi, mockStorage, mockRouter);
1451
- const error = new Error('Test error');
1452
-
1453
- // ✅ Test onError
1454
- await service.onError?.(error, mockContext);
1455
-
1456
- // Verify error handling
1457
- });
1458
- });
1459
- ```
1460
-
1461
- #### 3. ✅ Test Edge Cases and Error Scenarios
1462
-
1463
- ```typescript
1464
- describe('UserService Error Handling', () => {
1465
- it('should handle missing token', async () => {
1466
- mockStorage.getItem.mockReturnValue(null);
1467
-
1468
- // ✅ Verify errors
1469
- await expect(service.onBefore()).rejects.toThrow('NO_USER_TOKEN');
1470
- });
1471
-
1472
- it('should handle network error', async () => {
1473
- mockStorage.getItem.mockReturnValue('token');
1474
- mockApi.getUserInfo.mockRejectedValue(new Error('Network error'));
1475
-
1476
- // ✅ Verify error handling
1477
- await expect(service.onBefore()).rejects.toThrow('Network error');
1478
- });
1479
-
1480
- it('should handle invalid token', async () => {
1481
- mockStorage.getItem.mockReturnValue('invalid-token');
1482
- mockApi.getUserInfo.mockRejectedValue(new Error('401 Unauthorized'));
1483
-
1484
- // ✅ Verify 401 error handling
1485
- await expect(service.onBefore()).rejects.toThrow('401 Unauthorized');
1486
- });
1487
- });
1488
- ```
1489
-
1490
- #### 4. ✅ Test Plugin Dependencies
1491
-
1492
- ```typescript
1493
- describe('Plugin Dependencies', () => {
1494
- it('should ensure I18n is initialized before UserService', async () => {
1495
- const i18nService = new I18nService('/en/path');
1496
- const userService = new UserService(mockApi, mockStorage, mockRouter);
1497
-
1498
- // ✅ I18n initialized first
1499
- await i18nService.onBefore();
1500
-
1501
- // ✅ Then initialize UserService
1502
- await userService.onBefore();
1503
-
1504
- // ✅ Verify UserService can use translations
1505
- expect(i18n.t('some.key')).toBeDefined();
1506
- });
1507
- });
1508
- ```
1509
-
1510
- ### Running Tests
1511
-
1512
- ```bash
1513
- # Run all tests
1514
- npm run test
1515
-
1516
- # Run tests and watch for file changes
1517
- npm run test -- --watch
1518
-
1519
- # Run tests for specific file
1520
- npm run test -- UserService.test.ts
1521
-
1522
- # Generate test coverage report
1523
- npm run test -- --coverage
1524
- ```
1525
-
1526
- ### Test Coverage Goals
1527
-
1528
- With Bootstrap architecture, we can easily achieve high coverage:
1529
-
1530
- - **Plugin Logic**: > 90% coverage
1531
- - **Service Layer**: > 85% coverage
1532
- - **API Adapters**: > 80% coverage
1533
- - **Overall Application**: > 75% coverage
1534
-
1535
- ### Summary: Value of Testing
1536
-
1537
- Bootstrap architecture makes testing:
1538
-
1539
- 1. **Simpler** - No need to mock global variables and complex environments
1540
- 2. **Faster** - Pure logic testing, no need to render UI
1541
- 3. **More Reliable** - Tests are completely independent, no interference
1542
- 4. **More Comprehensive** - Easy to test all edge cases and error scenarios
1543
- 5. **More Confident** - High coverage ensures code quality
1544
-
1545
- > 💡 **Important Note**: Testability is one of the biggest advantages of Bootstrap architecture. If you find a plugin hard to test, it's likely a design problem requiring reconsideration of responsibility distribution.
1546
-
1547
- ---
1548
-
1549
- ## 💎 Best Practices
1550
-
1551
- ### 1. Plugin Design Principles
1552
-
1553
- #### ✅ Single Responsibility
1554
-
1555
- ```typescript
1556
- // ✅ Good plugin design: does one thing
1557
- export class ApiConfigPlugin implements BootstrapExecutorPlugin {
1558
- readonly pluginName = 'ApiConfigPlugin';
1559
-
1560
- onBefore({ parameters: { ioc } }: BootstrapContext): void {
1561
- // Only responsible for configuring API
1562
- const api = ioc.get<FeApi>(FeApi);
1563
- api.setBaseURL(config.apiBaseUrl);
1564
- api.usePlugin(new AuthPlugin());
1565
- }
1566
- }
1567
-
1568
- // ❌ Bad plugin design: does too many things
1569
- export class BadPlugin implements BootstrapExecutorPlugin {
1570
- readonly pluginName = 'BadPlugin';
1571
-
1572
- onBefore({ parameters: { ioc } }: BootstrapContext): void {
1573
- // Configure API
1574
- const api = ioc.get<FeApi>(FeApi);
1575
- api.setBaseURL(config.apiBaseUrl);
1576
-
1577
- // Initialize internationalization
1578
- i18next.init({
1579
- /* ... */
1580
- });
1581
-
1582
- // Check user authentication
1583
- checkAuth();
1584
-
1585
- // Configure router
1586
- configureRouter();
1587
-
1588
- // Too many responsibilities! ❌
1589
- }
1590
- }
1591
- ```
1592
-
1593
- #### ✅ Explicit Dependencies
1594
-
1595
- ```typescript
1596
- // ✅ Inject dependencies through constructor
1597
- @injectable()
1598
- export class UserService implements ExecutorPlugin {
1599
- constructor(
1600
- @inject(UserApi) private api: UserApi,
1601
- @inject(IOCIdentifier.AppConfig) private config: AppConfig
1602
- ) {}
1603
- }
1604
-
1605
- // ❌ Create dependencies directly
1606
- export class BadUserService implements ExecutorPlugin {
1607
- private api = new UserApi(); // ❌ Hardcoded dependency
1608
- private config = new AppConfig(); // ❌ Hard to test
1609
- }
1610
- ```
1611
-
1612
- ### 2. Error Handling
1613
-
1614
- ```typescript
1615
- export class UserService implements ExecutorPlugin {
1616
- readonly pluginName = 'UserService';
1617
-
1618
- async onBefore(): Promise<void> {
1619
- try {
1620
- await this.initializeUser();
1621
- } catch (error) {
1622
- // ✅ Graceful error handling
1623
- if (error instanceof AppError) {
1624
- // Business error
1625
- this.handleBusinessError(error);
1626
- } else if (error instanceof NetworkError) {
1627
- // Network error
1628
- this.handleNetworkError(error);
1629
- } else {
1630
- // Unknown error
1631
- this.logger.error('Unknown error:', error);
1632
- }
1633
-
1634
- // Don't let errors propagate and crash the app
1635
- // Instead, perform appropriate degradation
1636
- }
1637
- }
1638
-
1639
- private handleBusinessError(error: AppError) {
1640
- if (error.code === 'NO_USER_TOKEN') {
1641
- // Redirect to login page
1642
- this.router.push('/login');
1643
- } else if (error.code === 'TOKEN_EXPIRED') {
1644
- // Refresh token
1645
- this.refreshToken();
1646
- }
1647
- }
1648
- }
1649
- ```
1650
-
1651
- ### 3. Performance Optimization
1652
-
1653
- ```typescript
1654
- // ✅ Load plugins on demand
1655
- export class BootstrapsRegistry {
1656
- register(): BootstrapExecutorPlugin[] {
1657
- const plugins: BootstrapExecutorPlugin[] = [
1658
- // Required plugins
1659
- IOC(IOCIdentifier.I18nServiceInterface),
1660
- new UserApiBootstarp()
1661
- ];
1662
-
1663
- // Development environment plugins
1664
- if (!this.appConfig.isProduction) {
1665
- plugins.push(new DevToolsPlugin(), new MockDataPlugin());
1666
- }
1667
-
1668
- // Feature toggle plugins
1669
- if (this.appConfig.features.analytics) {
1670
- plugins.push(new AnalyticsPlugin());
1671
- }
1672
-
1673
- return plugins;
1674
- }
1675
- }
1676
- ```
1677
-
1678
- ### 4. Logging
1679
-
1680
- ```typescript
1681
- export class ApiConfigPlugin implements BootstrapExecutorPlugin {
1682
- readonly pluginName = 'ApiConfigPlugin';
1683
-
1684
- async onBefore({ parameters: { logger } }: BootstrapContext): Promise<void> {
1685
- logger.info(`[${this.pluginName}] Configuring API...`);
1686
-
1687
- try {
1688
- await this.configureAPI();
1689
- logger.info(`[${this.pluginName}] ✅ API configured successfully`);
1690
- } catch (error) {
1691
- logger.error(`[${this.pluginName}] ❌ API configuration failed:`, error);
1692
- throw error;
1693
- }
1694
- }
1695
- }
1696
- ```
1697
-
1698
- ---
1699
-
1700
- ## ❓ FAQ
1701
-
1702
- ### Q1: What's the relationship between Bootstrap and React lifecycle?
1703
-
1704
- **A:** Bootstrap executes before React renders.
1705
-
1706
- ```
1707
- Bootstrap initialization → Bootstrap startup → React rendering
1708
- ```
1709
-
1710
- ### Q2: Is plugin execution order important?
1711
-
1712
- **A:** Very important! Plugins execute in registration order.
1713
-
1714
- ```typescript
1715
- // ✅ Correct order
1716
- bootstrap.use([
1717
- IOC(I18nService), // 1. Initialize i18n first (other plugins may need it)
1718
- new ApiConfigPlugin(), // 2. Then configure API
1719
- IOC(UserService) // 3. Finally check user auth (depends on API)
1720
- ]);
1721
-
1722
- // ❌ Wrong order
1723
- bootstrap.use([
1724
- IOC(UserService), // ❌ UserService depends on API, but API not configured yet
1725
- new ApiConfigPlugin(), // Configure API
1726
- IOC(I18nService) // I18n at the end (too late)
1727
- ]);
1728
- ```
1729
-
1730
- ### Q3: How to debug Bootstrap?
1731
-
1732
- ```typescript
1733
- // Method 1: Use logging
1734
- export class MyPlugin implements BootstrapExecutorPlugin {
1735
- readonly pluginName = 'MyPlugin';
1736
-
1737
- async onBefore({ parameters: { logger } }: BootstrapContext): Promise<void> {
1738
- logger.info(`[${this.pluginName}] Starting...`);
1739
- // ... your logic
1740
- logger.info(`[${this.pluginName}] Completed`);
1741
- }
1742
- }
1743
-
1744
- // Method 2: Use debug plugin
1745
- export const debugPlugin: BootstrapExecutorPlugin = {
1746
- pluginName: 'DebugPlugin',
1747
-
1748
- onBefore(context) {
1749
- console.log('onBefore context:', context);
1750
- },
1751
-
1752
- onAfter(context) {
1753
- console.log('onAfter context:', context);
1754
- }
1755
- };
1756
- ```
1757
-
1758
- ### Q4: How to test plugins?
1759
-
1760
- ```typescript
1761
- describe('UserService Plugin', () => {
1762
- it('should initialize user on startup', async () => {
1763
- // Create mock dependencies
1764
- const mockApi = {
1765
- getUserInfo: jest.fn().mockResolvedValue({ name: 'John' })
1766
- };
1767
- const mockStorage = {
1768
- getItem: jest.fn().mockReturnValue('mock-token')
1769
- };
1770
-
1771
- // Create service
1772
- const userService = new UserService(
1773
- mockRouter,
1774
- mockApi,
1775
- mockConfig,
1776
- mockStorage
1777
- );
1778
-
1779
- // Execute plugin lifecycle
1780
- await userService.onBefore();
1781
-
1782
- // Verify
1783
- expect(mockApi.getUserInfo).toHaveBeenCalledWith('mock-token');
1784
- });
1785
- });
1786
- ```
1787
-
1788
- ### Q5: Is Bootstrap suitable for all projects?
1789
-
1790
- **A:** Not necessarily. Bootstrap is more suitable for:
1791
-
1792
- ✅ **Suitable scenarios:**
1793
-
1794
- - Medium to large applications
1795
- - Complex initialization logic required
1796
- - Multi-platform applications (Web, mobile, mini-programs)
1797
- - Modularity and testability needed
1798
- - Team collaborative development
1799
-
1800
- ❌ **Not suitable scenarios:**
1801
-
1802
- - Simple display pages
1803
- - Prototype projects
1804
- - Projects without complex initialization logic
1805
-
1806
- ### Q6: How to ensure test coverage?
1807
-
1808
- **A:** Bootstrap architecture naturally supports high coverage:
1809
-
1810
- ```typescript
1811
- // ✅ Each plugin can be tested independently
1812
- describe('UserService', () => {
1813
- it('should initialize user', async () => {
1814
- const service = new UserService(mockApi, mockStorage, mockRouter);
1815
- await service.onBefore();
1816
- expect(mockApi.getUserInfo).toHaveBeenCalled();
1817
- });
1818
-
1819
- // Easy to test all edge cases
1820
- it('should handle missing token', async () => {
1821
- mockStorage.getItem.mockReturnValue(null);
1822
- await expect(service.onBefore()).rejects.toThrow('NO_USER_TOKEN');
1823
- });
1824
-
1825
- it('should handle API error', async () => {
1826
- mockApi.getUserInfo.mockRejectedValue(new Error('Network error'));
1827
- await expect(service.onBefore()).rejects.toThrow('Network error');
1828
- });
1829
- });
1830
- ```
1831
-
1832
- **Coverage Goals:**
1833
-
1834
- - Plugin logic: > 90%
1835
- - Service layer: > 85%
1836
- - API adapters: > 80%
1837
-
1838
- ### Q7: What's the difference between Vitest and Jest?
1839
-
1840
- **A:** This project uses Vitest, a testing framework in the Vite ecosystem:
1841
-
1842
- | Feature | Vitest | Jest |
1843
- | ----------------- | ---------------------------------- | ---------------------------- |
1844
- | **Speed** | ⚡ Very fast (based on Vite) | Slow |
1845
- | **Configuration** | 🎯 Zero config (reuse vite.config) | Needs separate configuration |
1846
- | **ESM Support** | ✅ Native support | ⚠️ Experimental |
1847
- | **API** | Jest compatible | - |
1848
- | **HMR** | ✅ Supported | ❌ Not supported |
1849
-
1850
- ```typescript
1851
- // Vitest usage (almost identical to Jest)
1852
- import { describe, it, expect, vi, beforeEach } from 'vitest';
1853
-
1854
- describe('MyTest', () => {
1855
- beforeEach(() => {
1856
- vi.clearAllMocks();
1857
- });
1858
-
1859
- it('should work', () => {
1860
- expect(true).toBe(true);
1861
- });
1862
- });
1863
- ```
1864
-
1865
- ---
1866
-
1867
- ## 📚 Related Documentation
1868
-
1869
- - [Project Architecture Design](./index.md) - Understand overall architecture
1870
- - [IOC Container](./ioc.md) - Dependency injection details
1871
- - [Environment Variables](./env.md) - Environment configuration management
1872
- - [Global Variable Encapsulation](./global.md) - Browser API encapsulation
1873
-
1874
- ---
1875
-
1876
- ## 🎉 Summary
1877
-
1878
- Bootstrap initializer is an important component of modern frontend architecture, helping us:
1879
-
1880
- 1. **Separation of Concerns** - UI and initialization logic separated
1881
- 2. **Improved Maintainability** - Modular design, clear responsibilities
1882
- 3. **Enhanced Testability** - Each plugin can be tested independently
1883
- 4. **Support Team Collaboration** - Different developers can develop plugins independently
1884
- 5. **Adapt to Changes** - Easy to extend and modify
1885
-
1886
- Through Bootstrap, we build a more robust, maintainable, and testable frontend application architecture.
1887
-
1888
- ---
1889
-
1890
- **Feedback:**
1891
- If you have any questions or suggestions about Bootstrap, please discuss in the team channel or submit an Issue.