@qlover/create-app 0.6.1 → 0.6.3

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 (68) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/templates/react-app/README.en.md +257 -0
  5. package/dist/templates/react-app/README.md +29 -231
  6. package/dist/templates/react-app/config/IOCIdentifier.ts +13 -0
  7. package/dist/templates/react-app/docs/en/bootstrap.md +562 -0
  8. package/dist/templates/react-app/docs/en/development-guide.md +523 -0
  9. package/dist/templates/react-app/docs/en/env.md +482 -0
  10. package/dist/templates/react-app/docs/en/global.md +509 -0
  11. package/dist/templates/react-app/docs/en/i18n.md +268 -0
  12. package/dist/templates/react-app/docs/en/index.md +173 -0
  13. package/dist/templates/react-app/docs/en/ioc.md +424 -0
  14. package/dist/templates/react-app/docs/en/project-structure.md +434 -0
  15. package/dist/templates/react-app/docs/en/request.md +425 -0
  16. package/dist/templates/react-app/docs/en/router.md +404 -0
  17. package/dist/templates/react-app/docs/en/store.md +321 -0
  18. package/dist/templates/react-app/docs/en/theme.md +424 -0
  19. package/dist/templates/react-app/docs/en/typescript-guide.md +473 -0
  20. package/dist/templates/react-app/docs/zh/bootstrap.md +562 -0
  21. package/dist/templates/react-app/docs/zh/development-guide.md +523 -0
  22. package/dist/templates/react-app/docs/zh/env.md +479 -0
  23. package/dist/templates/react-app/docs/zh/global.md +511 -0
  24. package/dist/templates/react-app/docs/zh/i18n.md +268 -0
  25. package/dist/templates/react-app/docs/zh/index.md +173 -0
  26. package/dist/templates/react-app/docs/zh/ioc.md +422 -0
  27. package/dist/templates/react-app/docs/zh/project-structure.md +434 -0
  28. package/dist/templates/react-app/docs/zh/request.md +429 -0
  29. package/dist/templates/react-app/docs/zh/router.md +408 -0
  30. package/dist/templates/react-app/docs/zh/store.md +321 -0
  31. package/dist/templates/react-app/docs/zh/theme.md +424 -0
  32. package/dist/templates/react-app/docs/zh/typescript-guide.md +473 -0
  33. package/dist/templates/react-app/package.json +2 -2
  34. package/dist/templates/react-app/src/base/apis/AiApi.ts +10 -5
  35. package/dist/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +1 -1
  36. package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +1 -1
  37. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +10 -17
  38. package/dist/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +1 -1
  39. package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +2 -1
  40. package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +7 -5
  41. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +3 -2
  42. package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +33 -0
  43. package/dist/templates/react-app/src/base/cases/RequestLogger.ts +1 -1
  44. package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +2 -2
  45. package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +1 -1
  46. package/dist/templates/react-app/src/base/services/RouteService.ts +5 -2
  47. package/dist/templates/react-app/src/base/services/UserService.ts +8 -10
  48. package/dist/templates/react-app/src/core/IOC.ts +73 -83
  49. package/dist/templates/react-app/src/core/bootstraps/BootstrapApp.ts +52 -4
  50. package/dist/templates/react-app/src/core/bootstraps/{index.ts → BootstrapsRegistry.ts} +2 -3
  51. package/dist/templates/react-app/src/core/registers/IocRegisterImpl.ts +25 -0
  52. package/dist/templates/react-app/src/core/registers/RegisterCommon.ts +11 -17
  53. package/dist/templates/react-app/src/core/registers/RegisterControllers.ts +10 -4
  54. package/dist/templates/react-app/src/core/registers/RegisterGlobals.ts +6 -15
  55. package/dist/templates/react-app/src/main.tsx +2 -5
  56. package/dist/templates/react-app/src/styles/css/antd-themes/dark.css +3 -1
  57. package/dist/templates/react-app/src/styles/css/antd-themes/index.css +1 -1
  58. package/dist/templates/react-app/src/styles/css/antd-themes/pink.css +6 -1
  59. package/dist/templates/react-app/src/styles/css/page.css +1 -1
  60. package/dist/templates/react-app/src/uikit/controllers/JSONStorageController.ts +1 -1
  61. package/dist/templates/react-app/tsconfig.app.json +2 -1
  62. package/dist/templates/react-app/tsconfig.node.json +2 -1
  63. package/package.json +2 -2
  64. package/dist/templates/react-app/src/base/port/ApiTransactionInterface.ts +0 -7
  65. package/dist/templates/react-app/src/base/port/RequestCatcherInterface.ts +0 -12
  66. package/dist/templates/react-app/src/core/bootstrap.ts +0 -58
  67. package/dist/templates/react-app/src/core/registers/RegisterApi.ts +0 -5
  68. package/dist/templates/react-app/src/core/registers/index.ts +0 -32
@@ -0,0 +1,422 @@
1
+ # IOC 容器
2
+
3
+ ## 什么是 IOC?
4
+
5
+ IOC(Inversion of Control,控制反转)是一种设计模式,它将对象的创建和依赖关系的管理交给容器来处理,而不是在代码中直接创建对象。
6
+
7
+ **简单来说**:就像工厂生产产品一样,你不需要知道产品是如何制造的,只需要告诉工厂你需要什么产品,工厂就会给你提供。
8
+
9
+ ## 项目中的 IOC 实现
10
+
11
+ ### 核心技术栈
12
+
13
+ - **InversifyJS**:作为 IOC 容器的实现(你也可以手动实现自己的容器)
14
+ - **TypeScript**:提供类型安全
15
+ - **装饰器模式**:使用 `@injectable()` 和 `@inject()` 装饰器
16
+
17
+ ### 核心文件结构
18
+
19
+ ```
20
+ config/
21
+ ├── IOCIdentifier.ts # IOC 标识符定义
22
+ src/
23
+ ├── core/
24
+ │ ├── IOC.ts # IOC 主入口
25
+ │ ├── registers/ # 注册器目录
26
+ │ │ ├── RegisterGlobals.ts # 全局服务注册
27
+ │ │ ├── RegisterCommon.ts # 通用服务注册
28
+ │ │ └── RegisterControllers.ts # 控制器注册
29
+ │ └── globals.ts # 全局实例
30
+ ├── base/
31
+ │ └── cases/
32
+ │ └── InversifyContainer.ts # Inversify 容器实现
33
+ ```
34
+
35
+ ## 基本概念
36
+
37
+ ### 1. IOC 标识符
38
+
39
+ ```tsx
40
+ // config/IOCIdentifier.ts
41
+ export const IOCIdentifier = Object.freeze({
42
+ JSON: 'JSON',
43
+ LocalStorage: 'LocalStorage',
44
+ Logger: 'Logger',
45
+ AppConfig: 'AppConfig'
46
+ // ... 更多标识符
47
+ });
48
+ ```
49
+
50
+ ### 2. IOC 标识符映射
51
+
52
+ ```tsx
53
+ // core/IOC.ts
54
+ export interface IOCIdentifierMap {
55
+ [IOCIdentifier.JSON]: import('@qlover/fe-corekit').JSONSerializer;
56
+ [IOCIdentifier.LocalStorage]: import('@qlover/fe-corekit').ObjectStorage<
57
+ string,
58
+ string
59
+ >;
60
+ [IOCIdentifier.Logger]: import('@qlover/logger').LoggerInterface;
61
+ [IOCIdentifier.AppConfig]: import('@qlover/corekit-bridge').EnvConfigInterface;
62
+ // ... 更多映射
63
+ }
64
+ ```
65
+
66
+ ### 3. IOC 函数
67
+
68
+ ```tsx
69
+ // core/IOC.ts
70
+ export const IOC = createIOCFunction<IOCIdentifierMap>(
71
+ new InversifyContainer()
72
+ );
73
+ ```
74
+
75
+ ## 使用方法
76
+
77
+ ### 1. 获取服务实例
78
+
79
+ ```tsx
80
+ // 使用类名获取
81
+ const userService = IOC(UserService);
82
+
83
+ // 使用字符串标识符获取
84
+ const logger = IOC('Logger');
85
+ // 或者
86
+ const logger = IOC(IOCIdentifier.Logger);
87
+
88
+ // 使用 AppConfig
89
+ const appConfig = IOC(IOCIdentifier.AppConfig);
90
+ ```
91
+
92
+ ### 2. 在服务中使用依赖注入
93
+
94
+ ```tsx
95
+ import { inject, injectable } from 'inversify';
96
+ import { UserApi } from '@/base/apis/userApi/UserApi';
97
+ import { RouteService } from './RouteService';
98
+ import { IOCIdentifier } from '@config/IOCIdentifier';
99
+
100
+ @injectable()
101
+ export class UserService extends UserAuthService<UserInfo> {
102
+ constructor(
103
+ @inject(RouteService) protected routerService: RouteService,
104
+ @inject(UserApi) userApi: UserAuthApiInterface<UserInfo>,
105
+ @inject(IOCIdentifier.AppConfig) appConfig: AppConfig,
106
+ @inject(IOCIdentifier.LocalStorageEncrypt)
107
+ storage: SyncStorageInterface<string, string>
108
+ ) {
109
+ super(userApi, {
110
+ userStorage: {
111
+ key: appConfig.userInfoStorageKey,
112
+ storage: storage
113
+ },
114
+ credentialStorage: {
115
+ key: appConfig.userTokenStorageKey,
116
+ storage: storage
117
+ }
118
+ });
119
+ }
120
+ }
121
+ ```
122
+
123
+ ### 3. 在 Bootstrap 中使用
124
+
125
+ ```tsx
126
+ // 在启动器中注册服务
127
+ bootstrap.use([
128
+ IOC(UserService), // 用户服务
129
+ IOC(I18nService), // 国际化服务
130
+ new UserApiBootstarp() // API 配置
131
+ ]);
132
+ ```
133
+
134
+ ## 服务注册
135
+
136
+ ### 1. 全局服务注册
137
+
138
+ ```tsx
139
+ // core/registers/RegisterGlobals.ts
140
+ export const RegisterGlobals: IOCRegister = {
141
+ register(container, _, options): void {
142
+ // 注册应用配置
143
+ container.bind(IOCIdentifier.AppConfig, options!.appConfig);
144
+
145
+ // 注册日志服务
146
+ container.bind(Logger, logger);
147
+ container.bind(IOCIdentifier.Logger, logger);
148
+
149
+ // 注册存储服务
150
+ container.bind(IOCIdentifier.LocalStorage, localStorage);
151
+ container.bind(IOCIdentifier.LocalStorageEncrypt, localStorageEncrypt);
152
+ container.bind(IOCIdentifier.CookieStorage, cookieStorage);
153
+ }
154
+ };
155
+ ```
156
+
157
+ ### 2. 通用服务注册
158
+
159
+ ```tsx
160
+ // core/registers/RegisterCommon.ts
161
+ export const RegisterCommon: IOCRegister = {
162
+ register(container, _, options): void {
163
+ const AppConfig = container.get(IOCIdentifier.AppConfig);
164
+
165
+ // 注册 API 相关服务
166
+ const feApiToken = new TokenStorage(AppConfig.userTokenStorageKey, {
167
+ storage: container.get(IOCIdentifier.LocalStorageEncrypt)
168
+ });
169
+
170
+ container.bind(IOCIdentifier.FeApiToken, feApiToken);
171
+ container.bind(IOCIdentifier.FeApiCommonPlugin, feApiRequestCommonPlugin);
172
+
173
+ // 注册主题服务
174
+ container.bind(
175
+ ThemeService,
176
+ new ThemeService({
177
+ ...themeConfig,
178
+ storage: localStorage
179
+ })
180
+ );
181
+
182
+ // 注册路由服务
183
+ container.bind(
184
+ RouteService,
185
+ new RouteService({
186
+ routes: baseRoutes,
187
+ logger
188
+ })
189
+ );
190
+
191
+ // 注册国际化服务
192
+ container.bind(I18nService, new I18nService(options!.pathname));
193
+ }
194
+ };
195
+ ```
196
+
197
+ ### 3. 控制器注册
198
+
199
+ ```tsx
200
+ // core/registers/RegisterControllers.ts
201
+ export class RegisterControllers implements IOCRegister {
202
+ register(
203
+ container: IOCContainer,
204
+ _: IOCManagerInterface<IOCContainer>
205
+ ): void {
206
+ // 注册控制器
207
+ const jsonStorageController = new JSONStorageController(localStorage);
208
+ container.bind(JSONStorageController, jsonStorageController);
209
+
210
+ // 配置处理器
211
+ container
212
+ .get(ProcesserExecutor)
213
+ .use(container.get(I18nKeyErrorPlugin))
214
+ .use(container.get(UserService));
215
+ }
216
+ }
217
+ ```
218
+
219
+ ## 实际应用场景
220
+
221
+ ### 1. 用户认证服务
222
+
223
+ ```tsx
224
+ @injectable()
225
+ export class UserService extends UserAuthService<UserInfo> {
226
+ constructor(
227
+ @inject(RouteService) protected routerService: RouteService,
228
+ @inject(UserApi) userApi: UserAuthApiInterface<UserInfo>,
229
+ @inject(IOCIdentifier.AppConfig) appConfig: AppConfig,
230
+ @inject(IOCIdentifier.LocalStorageEncrypt)
231
+ storage: SyncStorageInterface<string, string>
232
+ ) {
233
+ super(userApi, {
234
+ userStorage: {
235
+ key: appConfig.userInfoStorageKey,
236
+ storage: storage
237
+ },
238
+ credentialStorage: {
239
+ key: appConfig.userTokenStorageKey,
240
+ storage: storage
241
+ }
242
+ });
243
+ }
244
+
245
+ async onBefore(): Promise<void> {
246
+ if (this.isAuthenticated()) {
247
+ return;
248
+ }
249
+
250
+ const userToken = this.getToken();
251
+ if (!userToken) {
252
+ throw new AppError('NO_USER_TOKEN');
253
+ }
254
+
255
+ await this.userInfo();
256
+ this.store.authSuccess();
257
+ }
258
+ }
259
+ ```
260
+
261
+ ### 2. API 配置服务
262
+
263
+ ```tsx
264
+ export class UserApiBootstarp implements BootstrapExecutorPlugin {
265
+ readonly pluginName = 'UserApiBootstarp';
266
+
267
+ onBefore({ parameters: { ioc } }: BootstrapContext): void {
268
+ // 通过 IOC 获取 UserApi 实例并配置插件
269
+ ioc
270
+ .get<UserApi>(UserApi)
271
+ .usePlugin(new FetchURLPlugin())
272
+ .usePlugin(IOC.get(IOCIdentifier.ApiMockPlugin))
273
+ .usePlugin(IOC.get(RequestLogger));
274
+ }
275
+ }
276
+ ```
277
+
278
+ ### 3. 在组件中使用
279
+
280
+ ```tsx
281
+ // 在 React 组件中使用 IOC 服务
282
+ function UserProfile() {
283
+ const userService = IOC(UserService);
284
+ const { user } = useStore(userService.store);
285
+
286
+ return (
287
+ <div>
288
+ <h1>欢迎, {user?.name}</h1>
289
+ <button onClick={() => userService.logout()}>退出登录</button>
290
+ </div>
291
+ );
292
+ }
293
+ ```
294
+
295
+ ## 最佳实践
296
+
297
+ ### 1. 服务设计原则
298
+
299
+ ```tsx
300
+ // ✅ 好的设计:单一职责
301
+ @injectable()
302
+ export class UserService {
303
+ constructor(
304
+ @inject(UserApi) private userApi: UserApi,
305
+ @inject(IOCIdentifier.AppConfig) private appConfig: AppConfig
306
+ ) {}
307
+ async getUserInfo(): Promise<UserInfo> {
308
+ return this.userApi.getUserInfo();
309
+ }
310
+ }
311
+
312
+ // ❌ 不好的设计:职责过多
313
+ @injectable()
314
+ export class BadService {
315
+ constructor(
316
+ @inject(UserApi) private userApi: UserApi,
317
+ @inject(RouteService) private routeService: RouteService,
318
+ @inject(ThemeService) private themeService: ThemeService,
319
+ @inject(I18nService) private i18nService: I18nService
320
+ ) {}
321
+ // 一个服务做了太多事情
322
+ async handleUserAction(): Promise<void> {
323
+ // 处理用户逻辑
324
+ // 处理路由逻辑
325
+ // 处理主题逻辑
326
+ // 处理国际化逻辑
327
+ }
328
+ }
329
+ ```
330
+
331
+ ### 2. 依赖注入的最佳实践
332
+
333
+ ```tsx
334
+ // ✅ 使用接口而不是具体实现
335
+ @injectable()
336
+ export class UserService {
337
+ constructor(
338
+ @inject('UserApiInterface') private userApi: UserAuthApiInterface<UserInfo>
339
+ ) {}
340
+ }
341
+
342
+ // ✅ 使用标识符而不是类名
343
+ @injectable()
344
+ export class SomeService {
345
+ constructor(
346
+ @inject(IOCIdentifier.Logger) private logger: LoggerInterface,
347
+ @inject(IOCIdentifier.AppConfig) private appConfig: AppConfig
348
+ ) {}
349
+ }
350
+ ```
351
+
352
+ ### 3. 错误处理
353
+
354
+ ```tsx
355
+ @injectable()
356
+ export class SafeService {
357
+ constructor(@inject(IOCIdentifier.Logger) private logger: LoggerInterface) {}
358
+
359
+ async doSomething(): Promise<void> {
360
+ try {
361
+ // 业务逻辑
362
+ } catch (error) {
363
+ this.logger.error('操作失败:', error);
364
+ throw error;
365
+ }
366
+ }
367
+ }
368
+ ```
369
+
370
+ ## 调试和测试
371
+
372
+ ### 1. 调试 IOC 容器
373
+
374
+ ```tsx
375
+ // 检查服务是否已注册
376
+ const container = IOC.implemention;
377
+ const isRegistered = container.isBound(UserService);
378
+
379
+ // 获取所有已注册的服务
380
+ const bindings = container.getAll(UserService);
381
+ ```
382
+
383
+ ### 2. 单元测试
384
+
385
+ ```tsx
386
+ import { Container } from 'inversify';
387
+
388
+ describe('UserService', () => {
389
+ let container: Container;
390
+ let userService: UserService;
391
+
392
+ beforeEach(() => {
393
+ container = new Container();
394
+
395
+ // 注册测试依赖
396
+ container.bind('UserApiInterface').toConstantValue(mockUserApi);
397
+ container.bind(IOCIdentifier.AppConfig).toConstantValue(mockAppConfig);
398
+ container
399
+ .bind(IOCIdentifier.LocalStorageEncrypt)
400
+ .toConstantValue(mockStorage);
401
+
402
+ userService = container.get(UserService);
403
+ });
404
+
405
+ it('should authenticate user successfully', async () => {
406
+ const result = await userService.onBefore();
407
+ expect(result).toBeDefined();
408
+ });
409
+ });
410
+ ```
411
+
412
+ ## 总结
413
+
414
+ IOC 容器在项目中的作用:
415
+
416
+ 1. **依赖管理**:统一管理所有服务的依赖关系
417
+ 2. **类型安全**:通过 TypeScript 提供编译时类型检查
418
+ 3. **可测试性**:便于进行单元测试和模拟
419
+ 4. **可维护性**:清晰的依赖关系,易于理解和修改
420
+ 5. **可扩展性**:轻松添加新的服务和依赖
421
+
422
+ 通过合理使用 IOC 容器,可以让代码更加模块化、可测试和可维护。