@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.
- package/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/templates/react-app/.env +23 -2
- package/templates/react-app/config/common.ts +3 -0
- package/templates/react-app/lib/bootstrap/Bootstrap.ts +36 -0
- package/templates/react-app/lib/bootstrap/BootstrapExecutorPlugin.ts +20 -0
- package/templates/react-app/lib/bootstrap/IOCContainerInterface.ts +33 -0
- package/templates/react-app/lib/bootstrap/IOCManagerInterface.ts +12 -0
- package/templates/react-app/lib/bootstrap/index.ts +7 -0
- package/templates/react-app/lib/bootstrap/plugins/InjectEnv.ts +61 -0
- package/templates/react-app/lib/bootstrap/plugins/InjectGlobal.ts +36 -0
- package/templates/react-app/lib/bootstrap/plugins/InjectIOC.ts +24 -0
- package/templates/react-app/lib/env-config/injectPkgConfig.ts +11 -0
- package/templates/react-app/lib/openAiApi/OpenAIClient.ts +1 -1
- package/templates/react-app/package.json +3 -1
- package/templates/react-app/src/base/consts/IOCIdentifier.ts +16 -0
- package/templates/react-app/src/base/port/IOCFunctionInterface.ts +39 -0
- package/templates/react-app/src/base/port/InversifyIocInterface.ts +9 -0
- package/templates/react-app/src/base/port/StorageTokenInterface.ts +22 -0
- package/templates/react-app/src/base/types/Page.ts +4 -13
- package/templates/react-app/src/base/types/global.d.ts +2 -1
- package/templates/react-app/src/components/ThemeSwitcher.tsx +1 -1
- package/templates/react-app/src/core/AppConfig.ts +27 -0
- package/templates/react-app/src/core/AppIOCContainer.ts +30 -0
- package/templates/react-app/src/core/IOC.ts +48 -0
- package/templates/react-app/src/core/bootstrap.ts +59 -14
- package/templates/react-app/src/core/globals.ts +1 -1
- package/templates/react-app/src/core/registers/RegisterApi.ts +59 -0
- package/templates/react-app/src/core/registers/RegisterCommon.ts +21 -0
- package/templates/react-app/src/core/{feIOC → registers}/RegisterControllers.ts +16 -11
- package/templates/react-app/src/core/registers/RegisterGlobals.ts +20 -0
- package/templates/react-app/src/core/registers/index.ts +17 -0
- package/templates/react-app/src/main.tsx +4 -3
- package/templates/react-app/src/pages/auth/Layout.tsx +1 -1
- package/templates/react-app/src/pages/auth/Login.tsx +4 -4
- package/templates/react-app/src/pages/base/Executor.tsx +1 -1
- package/templates/react-app/src/pages/base/JSONStorage.tsx +1 -1
- package/templates/react-app/src/pages/base/Request.tsx +1 -1
- package/templates/react-app/src/services/I18nService.ts +18 -14
- package/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +7 -1
- package/templates/react-app/src/uikit/providers/ProcessProvider.tsx +1 -1
- package/templates/react-app/src/uikit/utils/RequestLogger.ts +4 -1
- package/templates/react-app/tsconfig.json +2 -1
- package/templates/react-app/tsconfig.node.json +6 -2
- package/templates/react-app/vite.config.ts +14 -0
- package/templates/react-app/config/app.common.ts +0 -52
- package/templates/react-app/src/base/port/IOCInterface.ts +0 -53
- package/templates/react-app/src/core/feIOC/FeIOC.ts +0 -32
- package/templates/react-app/src/core/feIOC/RegisterApi.ts +0 -41
- package/templates/react-app/src/core/feIOC/RegisterCommon.ts +0 -20
- 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
package/templates/react-app/.env
CHANGED
|
@@ -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
|
-
|
|
3
|
-
|
|
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,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
|
+
}
|
|
@@ -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 {
|
|
3
|
-
|
|
4
|
-
import {
|
|
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
|
-
};
|
|
@@ -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
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
7
|
-
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
28
|
+
if (!window) {
|
|
29
|
+
throw new Error('Not Found Window');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const bootstrap = new Bootstrap(new AppIOCContainer());
|
|
14
33
|
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
19
|
-
|
|
61
|
+
try {
|
|
62
|
+
bootstrap.use(bootstrapList).start(root);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error(`${AppConfig.appName} starup error:`, error);
|
|
20
65
|
}
|
|
21
66
|
}
|