@qlover/create-app 0.1.11 → 0.1.12

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 (51) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/package.json +1 -1
  3. package/templates/react-app/.env +23 -2
  4. package/templates/react-app/config/common.ts +3 -0
  5. package/templates/react-app/lib/bootstrap/Bootstrap.ts +36 -0
  6. package/templates/react-app/lib/bootstrap/BootstrapExecutorPlugin.ts +20 -0
  7. package/templates/react-app/lib/bootstrap/IOCContainerInterface.ts +33 -0
  8. package/templates/react-app/lib/bootstrap/IOCManagerInterface.ts +12 -0
  9. package/templates/react-app/lib/bootstrap/index.ts +7 -0
  10. package/templates/react-app/lib/bootstrap/plugins/InjectEnv.ts +61 -0
  11. package/templates/react-app/lib/bootstrap/plugins/InjectGlobal.ts +36 -0
  12. package/templates/react-app/lib/bootstrap/plugins/InjectIOC.ts +24 -0
  13. package/templates/react-app/lib/env-config/injectPkgConfig.ts +11 -0
  14. package/templates/react-app/lib/openAiApi/OpenAIClient.ts +1 -1
  15. package/templates/react-app/package.json +3 -1
  16. package/templates/react-app/src/base/consts/IOCIdentifier.ts +16 -0
  17. package/templates/react-app/src/base/port/IOCFunctionInterface.ts +39 -0
  18. package/templates/react-app/src/base/port/InversifyIocInterface.ts +9 -0
  19. package/templates/react-app/src/base/port/StorageTokenInterface.ts +22 -0
  20. package/templates/react-app/src/base/types/Page.ts +4 -13
  21. package/templates/react-app/src/base/types/global.d.ts +2 -1
  22. package/templates/react-app/src/components/ThemeSwitcher.tsx +1 -1
  23. package/templates/react-app/src/core/AppConfig.ts +27 -0
  24. package/templates/react-app/src/core/AppIOCContainer.ts +30 -0
  25. package/templates/react-app/src/core/IOC.ts +48 -0
  26. package/templates/react-app/src/core/bootstrap.ts +59 -14
  27. package/templates/react-app/src/core/globals.ts +1 -1
  28. package/templates/react-app/src/core/registers/RegisterApi.ts +59 -0
  29. package/templates/react-app/src/core/registers/RegisterCommon.ts +21 -0
  30. package/templates/react-app/src/core/{feIOC → registers}/RegisterControllers.ts +16 -11
  31. package/templates/react-app/src/core/registers/RegisterGlobals.ts +20 -0
  32. package/templates/react-app/src/core/registers/index.ts +17 -0
  33. package/templates/react-app/src/main.tsx +4 -3
  34. package/templates/react-app/src/pages/auth/Layout.tsx +1 -1
  35. package/templates/react-app/src/pages/auth/Login.tsx +4 -4
  36. package/templates/react-app/src/pages/base/Executor.tsx +1 -1
  37. package/templates/react-app/src/pages/base/JSONStorage.tsx +1 -1
  38. package/templates/react-app/src/pages/base/Request.tsx +1 -1
  39. package/templates/react-app/src/services/I18nService.ts +18 -14
  40. package/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +7 -1
  41. package/templates/react-app/src/uikit/providers/ProcessProvider.tsx +1 -1
  42. package/templates/react-app/src/uikit/utils/RequestLogger.ts +4 -1
  43. package/templates/react-app/tsconfig.json +2 -1
  44. package/templates/react-app/tsconfig.node.json +6 -2
  45. package/templates/react-app/vite.config.ts +14 -0
  46. package/templates/react-app/config/app.common.ts +0 -52
  47. package/templates/react-app/src/base/port/IOCInterface.ts +0 -53
  48. package/templates/react-app/src/core/feIOC/FeIOC.ts +0 -32
  49. package/templates/react-app/src/core/feIOC/RegisterApi.ts +0 -41
  50. package/templates/react-app/src/core/feIOC/RegisterCommon.ts +0 -20
  51. package/templates/react-app/src/core/index.ts +0 -31
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
 
2
2
 
3
+ ## [0.1.12](https://github.com/qlover/fe-base/compare/create-app-v0.1.11...create-app-v0.1.12) (2025-03-18)
4
+
5
+
6
+ ### Features
7
+
8
+ * add inversify ioc ([#270](https://github.com/qlover/fe-base/issues/270)) ([8c7ba06](https://github.com/qlover/fe-base/commit/8c7ba06bc5bef63d85c59a94737afac9be59138f))
9
+
3
10
  ## [0.1.11](https://github.com/qlover/fe-base/compare/create-app-v0.1.10...create-app-v0.1.11) (2025-03-12)
4
11
 
5
12
  ## [0.1.10](https://github.com/qlover/fe-base/compare/create-app-v0.1.9...create-app-v0.1.10) (2025-02-20)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qlover/create-app",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "main": "./dist/es/index.js",
@@ -1,3 +1,24 @@
1
+ NODE_ENV=production
2
+
3
+ # ci
4
+ NPM_TOKEN=
5
+ GITHUB_TOKEN=
6
+
7
+ # fe-scripts
8
+ FE_RELEASE_BRANCH=master
9
+ FE_RELEASE=false
10
+ FE_RELEASE_ENV=production
11
+
12
+ # ===== build
13
+ VITE_PUBLIC_PATH=
1
14
  VITE_SERVER_PORT=3200
2
- VITE_OPENAI_API_URL=
3
- VITE_OPENAI_API_KEY=
15
+
16
+ # ===== app config
17
+ VITE_USER_TOKEN_STORAGE_KEY=fe_user_token
18
+ VITE_OPEN_AI_MODELS='["gpt-4o-mini","gpt-3.5-turbo","gpt-3.5-turbo-2","gpt-4","gpt-4-32k"]'
19
+ VITE_OPEN_AI_BASE_URL=https://api.openai.com/v1
20
+ VITE_OPEN_AI_TOKEN=sk-proj-1234567890
21
+ VITE_OPEN_AI_TOKEN_PREFIX=Bearer
22
+ VITE_OPEN_AI_REQUIRE_TOKEN=true
23
+ VITE_LOGIN_USER=admin
24
+ VITE_LOGIN_PASSWORD=123456
@@ -0,0 +1,3 @@
1
+ export const envPrefix = 'VITE_';
2
+
3
+ export const browserGlobalsName = 'feGlobals';
@@ -0,0 +1,36 @@
1
+ import type { IOCContainerInterface } from './IOCContainerInterface';
2
+ import { SyncExecutor } from '@qlover/fe-utils';
3
+ import { BootstrapExecutorPlugin } from './BootstrapExecutorPlugin';
4
+
5
+ export class Bootstrap extends SyncExecutor {
6
+ constructor(private IOCContainer: IOCContainerInterface) {
7
+ super();
8
+ }
9
+
10
+ getIOCContainer(): IOCContainerInterface {
11
+ return this.IOCContainer;
12
+ }
13
+
14
+ use(plugin: BootstrapExecutorPlugin | BootstrapExecutorPlugin[]): this {
15
+ if (Array.isArray(plugin)) {
16
+ plugin.forEach((p) => super.use(p));
17
+ return this;
18
+ }
19
+
20
+ super.use(plugin);
21
+
22
+ return this;
23
+ }
24
+
25
+ start(root: unknown): void {
26
+ this.exec({ root, ioc: this.IOCContainer }, () => {
27
+ // nothing to do
28
+ });
29
+ }
30
+
31
+ startNoError(root: unknown): void {
32
+ this.execNoError({ root, ioc: this.IOCContainer }, () => {
33
+ // nothing to do
34
+ });
35
+ }
36
+ }
@@ -0,0 +1,20 @@
1
+ import { IOCContainerInterface } from './IOCContainerInterface';
2
+ import { ExecutorContext, ExecutorPlugin } from '@qlover/fe-utils';
3
+
4
+ export type BootstrapArgs = {
5
+ /**
6
+ * starup global object
7
+ *
8
+ * maybe window or globalThis
9
+ */
10
+ root: unknown;
11
+ /**
12
+ * IOC container
13
+ */
14
+ ioc: IOCContainerInterface;
15
+ };
16
+
17
+ export interface BootstrapExecutorPlugin
18
+ extends ExecutorPlugin<BootstrapArgs> {}
19
+
20
+ export type BootstrapContext = ExecutorContext<BootstrapArgs>;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * IOC container
3
+ *
4
+ */
5
+ export interface IOCContainerInterface {
6
+ /**
7
+ * configure IOC container
8
+ *
9
+ * eg. may need to manually bind implementation classes
10
+ */
11
+ configure(): void;
12
+ configure<Container>(registers?: IOCRegisterInterface<Container>[]): void;
13
+
14
+ /**
15
+ * bind instance
16
+ *
17
+ * @param serviceIdentifier
18
+ * @param value
19
+ */
20
+ bind<T>(serviceIdentifier: unknown, value: T): void;
21
+
22
+ /**
23
+ * get instance
24
+ *
25
+ * @param serviceIdentifier
26
+ * @returns
27
+ */
28
+ get<T>(serviceIdentifier: unknown): T;
29
+ }
30
+
31
+ export interface IOCRegisterInterface<T> {
32
+ register(container: T, thisArg: IOCContainerInterface): void;
33
+ }
@@ -0,0 +1,12 @@
1
+ import type { IOCContainerInterface } from './IOCContainerInterface';
2
+
3
+ export interface IOCManagerInterface {
4
+ get<T>(identifier: unknown): T;
5
+
6
+ /**
7
+ * implement IOC container
8
+ */
9
+ implement(container: IOCContainerInterface): void;
10
+
11
+ get implemention(): IOCContainerInterface | null;
12
+ }
@@ -0,0 +1,7 @@
1
+ export * from './Bootstrap';
2
+ export * from './BootstrapExecutorPlugin';
3
+ export * from './plugins/InjectIOC';
4
+ export * from './plugins/InjectEnv';
5
+ export * from './plugins/InjectGlobal';
6
+ export * from './IOCContainerInterface';
7
+ export * from './IOCManagerInterface';
@@ -0,0 +1,61 @@
1
+ import type { BootstrapExecutorPlugin } from '../BootstrapExecutorPlugin';
2
+
3
+ export interface EnvConfigInterface {
4
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
+ [key: string]: any;
6
+ }
7
+
8
+ export class InjectEnv implements BootstrapExecutorPlugin {
9
+ readonly pluginName = 'InjectEnv';
10
+
11
+ constructor(
12
+ private target: EnvConfigInterface,
13
+ private source: Record<string, unknown>,
14
+ private envPrefix: string = '',
15
+ private envWhiteList: string[] = ['env', 'userNodeEnv']
16
+ ) {}
17
+
18
+ static isJSONString(value: string): boolean {
19
+ return (
20
+ typeof value === 'string' &&
21
+ value !== '' &&
22
+ (value === 'true' ||
23
+ value === 'false' ||
24
+ value.startsWith('{') ||
25
+ value.startsWith('['))
26
+ );
27
+ }
28
+
29
+ env<D>(key: string, defaultValue?: D): D {
30
+ // transform key to env key
31
+ const formattedKey = key.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase();
32
+
33
+ const envKey = `${this.envPrefix}${formattedKey}`;
34
+ const value = this.source[envKey];
35
+ // if it is a json string, parse it
36
+ if (typeof value === 'string' && InjectEnv.isJSONString(value)) {
37
+ return JSON.parse(value);
38
+ }
39
+
40
+ return (value ?? defaultValue) as D;
41
+ }
42
+
43
+ inject(config: EnvConfigInterface): void {
44
+ for (const key in config) {
45
+ if (this.envWhiteList.includes(key)) {
46
+ continue;
47
+ }
48
+
49
+ const value = config[key as keyof typeof config];
50
+
51
+ config[key as keyof typeof config] = this.env(key, value);
52
+ }
53
+ }
54
+
55
+ onBefore(): void {
56
+ this.inject(this.target);
57
+
58
+ // transform readonly to writable
59
+ Object.freeze(this.target);
60
+ }
61
+ }
@@ -0,0 +1,36 @@
1
+ import type { ExecutorContext } from '@qlover/fe-utils';
2
+ import type {
3
+ BootstrapArgs,
4
+ BootstrapExecutorPlugin
5
+ } from '../BootstrapExecutorPlugin';
6
+
7
+ export class InjectGlobal implements BootstrapExecutorPlugin {
8
+ readonly pluginName = 'InjectGlobal';
9
+
10
+ constructor(
11
+ private sources: Record<string, unknown>,
12
+ private target?: string | Record<string, unknown>
13
+ ) {}
14
+
15
+ onBefore(context: ExecutorContext<BootstrapArgs>): void {
16
+ // if target is provided, inject globals to target
17
+ if (typeof this.target === 'string') {
18
+ Object.assign(context.parameters.root!, {
19
+ [this.target]: Object.freeze(Object.assign({}, this.sources))
20
+ });
21
+ return;
22
+ }
23
+
24
+ const target = this.target || context.parameters.root;
25
+
26
+ if (typeof target !== 'object' || target === null) {
27
+ throw new Error('target must be an object');
28
+ }
29
+
30
+ // inject globals to root
31
+ for (const key in this.sources) {
32
+ const element = this.sources[key];
33
+ Object.assign(target, { [key]: element });
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,24 @@
1
+ import type { IOCRegisterInterface } from '../IOCContainerInterface';
2
+ import type { IOCManagerInterface } from '../IOCManagerInterface';
3
+ import type {
4
+ BootstrapContext,
5
+ BootstrapExecutorPlugin
6
+ } from '../BootstrapExecutorPlugin';
7
+ import { Container } from 'inversify';
8
+
9
+ export class InjectIOC implements BootstrapExecutorPlugin {
10
+ readonly pluginName = 'InjectIOC';
11
+
12
+ constructor(
13
+ private IOC: IOCManagerInterface,
14
+ private registeres: IOCRegisterInterface<Container>[]
15
+ ) {}
16
+
17
+ onBefore(context: BootstrapContext): void {
18
+ const { ioc } = context.parameters;
19
+ this.IOC.implement(ioc);
20
+
21
+ // maybe runtimes configure
22
+ ioc.configure(this.registeres);
23
+ }
24
+ }
@@ -0,0 +1,11 @@
1
+ export function injectPkgConfig(
2
+ options: [string, string][],
3
+ envPrefix: string = ''
4
+ ) {
5
+ options.forEach(([key, value]) => {
6
+ const envKey = `${envPrefix}${key}`;
7
+ if (!process.env[envKey]) {
8
+ process.env[envKey] = value;
9
+ }
10
+ });
11
+ }
@@ -25,7 +25,7 @@ export interface OpenAIChatParmas {
25
25
 
26
26
  export type OpenAIAargs = {
27
27
  commonPluginConfig: RequestCommonPluginConfig;
28
- models: readonly string[];
28
+ models: string[];
29
29
  };
30
30
 
31
31
  export type OpenAIClientConfig = Partial<RequestAdapterFetchConfig> &
@@ -56,11 +56,13 @@
56
56
  "i18next": "^24.2.0",
57
57
  "i18next-browser-languagedetector": "^8.0.2",
58
58
  "i18next-http-backend": "^3.0.1",
59
+ "inversify": "^7.1.0",
59
60
  "lodash": "^4.17.21",
60
61
  "react": "^18.3.1",
61
62
  "react-dom": "^18.3.1",
62
63
  "react-i18next": "^15.2.0",
63
- "react-router-dom": "^7.1.5"
64
+ "react-router-dom": "^7.1.5",
65
+ "reflect-metadata": "^0.2.2"
64
66
  },
65
67
  "devDependencies": {
66
68
  "@eslint/js": "^9.11.1",
@@ -0,0 +1,16 @@
1
+ /**
2
+ * IOC identifier
3
+ *
4
+ * @description
5
+ * IOC identifier is used to identify the service in the IOC container.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const a = IOC(IOCIdentifier.JSON);
10
+ * ```
11
+ */
12
+ export const IOCIdentifier = Object.freeze({
13
+ JSON: 'JSON',
14
+ JSONStorage: 'JSONStorage',
15
+ Logger: 'Logger'
16
+ });
@@ -0,0 +1,39 @@
1
+ import type { IOCManagerInterface } from '@lib/bootstrap';
2
+ import type { JSONSerializer, JSONStorage, Logger } from '@qlover/fe-utils';
3
+ import type { ServiceIdentifier } from 'inversify';
4
+ import type { IOCIdentifier } from '@/base/consts/IOCIdentifier';
5
+
6
+ export type IOCIdentifierMap = {
7
+ [IOCIdentifier.JSON]: JSONSerializer;
8
+ [IOCIdentifier.JSONStorage]: JSONStorage;
9
+ [IOCIdentifier.Logger]: Logger;
10
+ };
11
+
12
+ /**
13
+ * IOC function
14
+ *
15
+ * eg.
16
+ * ```ts
17
+ * const a = IOC(A);
18
+ * const logger = IOC(ConstanstIdentifier.Logger);
19
+ * ```
20
+ *
21
+ */
22
+ export interface IOCFunctionInterface extends IOCManagerInterface {
23
+ /**
24
+ * get constant identifier
25
+ *
26
+ * Preferred match for simple types
27
+ */
28
+ <K extends keyof IOCIdentifierMap>(serviceIdentifier: K): IOCIdentifierMap[K];
29
+
30
+ /**
31
+ * get service identifier
32
+ */
33
+ <T>(serviceIdentifier: ServiceIdentifier<T>): T;
34
+
35
+ get<K extends keyof IOCIdentifierMap>(
36
+ serviceIdentifier: K
37
+ ): IOCIdentifierMap[K];
38
+ get<T>(serviceIdentifier: ServiceIdentifier<T>): T;
39
+ }
@@ -0,0 +1,9 @@
1
+ import type { IOCRegisterInterface } from '@lib/bootstrap';
2
+ import type { Container } from 'inversify';
3
+
4
+ export type InversifyRegisterContainer = Container;
5
+ /**
6
+ * Inversify register interface.
7
+ */
8
+ export interface InversifyRegisterInterface
9
+ extends IOCRegisterInterface<InversifyRegisterContainer> {}
@@ -1,5 +1,27 @@
1
+ /**
2
+ * Storage token interface
3
+ *
4
+ * @description
5
+ * Storage token interface is used to store and retrieve token from the storage.
6
+ */
1
7
  export interface StorageTokenInterface {
8
+ /**
9
+ * Get token
10
+ *
11
+ * @returns {string} token
12
+ */
2
13
  getToken(): string;
14
+
15
+ /**
16
+ * Set token
17
+ *
18
+ * @param {string} token
19
+ * @param {number} expireTime
20
+ */
3
21
  setToken(token: string, expireTime?: number): void;
22
+
23
+ /**
24
+ * Remove token
25
+ */
4
26
  removeToken(): void;
5
27
  }
@@ -1,9 +1,7 @@
1
- import { LazyExoticComponent, PropsWithChildren } from 'react';
2
- import { RouteObject } from 'react-router-dom';
3
-
4
- import { TFunction } from 'i18next';
5
- import { UseTranslationResponse } from 'react-i18next';
6
- import { RouteConfigValue } from '@lib/router-loader/RouterLoader';
1
+ import type { LazyExoticComponent, PropsWithChildren } from 'react';
2
+ import type { TFunction } from 'i18next';
3
+ import type { UseTranslationResponse } from 'react-i18next';
4
+ import type { RouteConfigValue } from '@lib/router-loader/RouterLoader';
7
5
 
8
6
  export interface BasePageProvider {
9
7
  meta: RouteMeta;
@@ -37,10 +35,3 @@ export type PagesMaps = Record<
37
35
  | (() => LazyExoticComponent<React.ComponentType<unknown>>)
38
36
  | (() => React.ComponentType<unknown>)
39
37
  >;
40
-
41
- export type LoadProps = {
42
- pagesMaps: PagesMaps;
43
- componentPath: string;
44
- route: RouteType;
45
- Provider?: React.ComponentType<PropsWithChildren<RouteMeta>>;
46
- };
@@ -1,7 +1,8 @@
1
1
  import * as feGlobals from '@/core/globals';
2
+ import type { browserGlobalsName } from '@config/common';
2
3
 
3
4
  declare global {
4
5
  interface Window {
5
- feGlobals: Readonly<typeof feGlobals>;
6
+ [browserGlobalsName]: Readonly<typeof feGlobals>;
6
7
  }
7
8
  }
@@ -1,4 +1,4 @@
1
- import { IOC } from '@/core';
1
+ import { IOC } from '@/core/IOC';
2
2
  import { useController } from '@lib/fe-react-controller';
3
3
  import { ThemeController } from '@lib/fe-react-theme/ThemeController';
4
4
  import { useTranslation } from 'react-i18next';
@@ -0,0 +1,27 @@
1
+ import type { EnvConfigInterface } from '@lib/bootstrap';
2
+
3
+ class AppConfig implements EnvConfigInterface {
4
+ readonly appName = '';
5
+ readonly appVersion = '';
6
+ /**
7
+ * vite mode
8
+ */
9
+ readonly env = import.meta.env.VITE_USER_NODE_ENV;
10
+
11
+ readonly userTokenStorageKey = 'fe_user_token';
12
+ readonly openAiModels = [
13
+ 'gpt-4o-mini',
14
+ 'gpt-3.5-turbo',
15
+ 'gpt-3.5-turbo-2',
16
+ 'gpt-4',
17
+ 'gpt-4-32k'
18
+ ];
19
+ readonly openAiBaseUrl = '';
20
+ readonly openAiToken = '';
21
+ readonly openAiTokenPrefix = '';
22
+ readonly openAiRequireToken = true;
23
+ readonly loginUser = '';
24
+ readonly loginPassword = '';
25
+ }
26
+
27
+ export default new AppConfig();
@@ -0,0 +1,30 @@
1
+ import type { InversifyRegisterInterface } from '@/base/port/InversifyIocInterface';
2
+ import type { IOCContainerInterface } from '@lib/bootstrap';
3
+ import { ServiceIdentifier, Container } from 'inversify';
4
+
5
+ export class AppIOCContainer implements IOCContainerInterface {
6
+ private container: Container;
7
+
8
+ constructor() {
9
+ this.container = new Container({
10
+ // allow `@injectable` decorator, auto bind injectable classes
11
+ autobind: true,
12
+ // use singleton scope
13
+ defaultScope: 'Singleton'
14
+ });
15
+ }
16
+
17
+ configure(registers?: InversifyRegisterInterface[]): void {
18
+ if (registers) {
19
+ registers.forEach((register) => register.register(this.container, this));
20
+ }
21
+ }
22
+
23
+ bind<T>(key: ServiceIdentifier<T>, value: T): void {
24
+ this.container.bind<T>(key).toConstantValue(value);
25
+ }
26
+
27
+ get<T>(key: string): T {
28
+ return this.container.get<T>(key);
29
+ }
30
+ }
@@ -0,0 +1,48 @@
1
+ // ! dont't import tsx, only ts file
2
+ import type { IOCContainerInterface } from '@lib/bootstrap';
3
+ import type {
4
+ IOCIdentifierMap,
5
+ IOCFunctionInterface
6
+ } from '@/base/port/IOCFunctionInterface';
7
+ import type { ServiceIdentifier } from 'inversify';
8
+
9
+ let implemention: IOCContainerInterface | null;
10
+
11
+ function ioc<T>(serviceIdentifier: ServiceIdentifier<T>): T;
12
+ function ioc<K extends keyof IOCIdentifierMap>(
13
+ serviceIdentifier: K
14
+ ): IOCIdentifierMap[K];
15
+ function ioc<T, K extends keyof IOCIdentifierMap>(
16
+ serviceIdentifier: ServiceIdentifier<T> | K
17
+ ): T | IOCIdentifierMap[K] {
18
+ if (!implemention) {
19
+ throw new Error('IOC is not implemented');
20
+ }
21
+ return implemention.get(serviceIdentifier);
22
+ }
23
+
24
+ /**
25
+ * IOC manager function.
26
+ *
27
+ * eg.
28
+ * ```ts
29
+ * class A {}
30
+ * const a = IOC(A);
31
+ * ```
32
+ *
33
+ * or
34
+ * ```ts
35
+ * const a = IOC<A>();
36
+ * ```
37
+ *
38
+ * or use get(),
39
+ */
40
+ export const IOC: IOCFunctionInterface = Object.assign(ioc, {
41
+ get implemention() {
42
+ return implemention;
43
+ },
44
+ implement: (container: IOCContainerInterface) => {
45
+ implemention = container;
46
+ },
47
+ get: ioc
48
+ });
@@ -1,21 +1,66 @@
1
- import * as feGlobals from '@/core/globals';
2
- import { IOC } from '.';
3
- import { IOCInterface } from '@/base/port/IOCInterface';
1
+ import {
2
+ Bootstrap,
3
+ BootstrapExecutorPlugin,
4
+ InjectEnv,
5
+ InjectIOC,
6
+ InjectGlobal
7
+ } from '@lib/bootstrap';
8
+ import { AppIOCContainer } from '@/core/AppIOCContainer';
9
+ import AppConfig from '@/core/AppConfig';
10
+ import { envPrefix, browserGlobalsName } from '@config/common';
11
+ import { IOC } from './IOC';
12
+ import * as globals from '@/core/globals';
4
13
  import { I18nService } from '@/services/I18nService';
14
+ import { registerList } from './registers';
5
15
 
6
- export class Bootstrap {
7
- constructor(private IOCContainer: IOCInterface) {}
16
+ /**
17
+ * Bootstrap
18
+ *
19
+ * 1. inject env config to AppConfig
20
+ * 2. inject IOC to Application
21
+ * 3. inject globals to window
22
+ *
23
+ */
24
+ export default function startup(root: typeof globalThis) {
25
+ const window =
26
+ typeof root !== 'undefined' && root instanceof Window ? root : undefined;
8
27
 
9
- start(): void {
10
- // set global feGlobals
11
- if (typeof window !== 'undefined') {
12
- window.feGlobals = Object.freeze(Object.assign({}, feGlobals));
13
- }
28
+ if (!window) {
29
+ throw new Error('Not Found Window');
30
+ }
31
+
32
+ const bootstrap = new Bootstrap(new AppIOCContainer());
14
33
 
15
- // startup IOC
16
- IOC.implement(this.IOCContainer);
34
+ /**
35
+ * bootstrap start list
36
+ *
37
+ * - inject env config to AppConfig
38
+ * - inject IOC to Application
39
+ * - inject globals to window
40
+ * - inject i18n service to Application
41
+ */
42
+ const bootstrapList: BootstrapExecutorPlugin[] = [
43
+ new InjectEnv(AppConfig, import.meta.env, envPrefix),
44
+ new InjectIOC(IOC, registerList),
45
+ new InjectGlobal(globals, browserGlobalsName),
46
+ new I18nService(window.location.pathname)
47
+ ];
48
+
49
+ if (AppConfig.env !== 'production') {
50
+ bootstrapList.push({
51
+ pluginName: 'InjectDevTools',
52
+ onBefore() {
53
+ console.log(AppConfig);
54
+ },
55
+ onError({ error }) {
56
+ console.error(`${AppConfig.appName} starup error:`, error);
57
+ }
58
+ });
59
+ }
17
60
 
18
- // startup i18n
19
- I18nService.init();
61
+ try {
62
+ bootstrap.use(bootstrapList).start(root);
63
+ } catch (error) {
64
+ console.error(`${AppConfig.appName} starup error:`, error);
20
65
  }
21
66
  }
@@ -6,7 +6,7 @@ import {
6
6
  SyncStorage
7
7
  } from '@qlover/fe-utils';
8
8
 
9
- export const env = import.meta.env.VITE_NODE_ENV;
9
+ export const env = import.meta.env.VITE_USER_NODE_ENV;
10
10
  export const isProduction = env === 'production';
11
11
 
12
12
  /**