@qlover/create-app 0.1.4 → 0.1.6

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 (113) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/bin/create-app.js +44 -4
  3. package/{templates/pack-app → configs/_common}/.env.template +8 -1
  4. package/{templates/pack-app → configs/_common}/.github/workflows/general-check.yml +9 -9
  5. package/{templates/pack-app → configs/_common}/.github/workflows/release.yml.template +26 -26
  6. package/configs/_common/.prettierrc.js +7 -0
  7. package/configs/_common/.release-it.json.template +42 -0
  8. package/configs/_common/.vscode/extensions.json +9 -0
  9. package/configs/_common/.vscode/react.code-snippets +19 -0
  10. package/configs/_common/.vscode/settings.json +11 -0
  11. package/configs/_common/package.json.template +61 -0
  12. package/configs/node-lib/eslint.config.js +50 -0
  13. package/configs/react-app/eslint.config.js +66 -0
  14. package/dist/cjs/index.d.ts +58 -38
  15. package/dist/cjs/index.js +1 -1
  16. package/dist/es/index.d.ts +58 -38
  17. package/dist/es/index.js +1 -1
  18. package/package.json +3 -1
  19. package/templates/node-lib/__tests__/readJson.test.ts +1 -0
  20. package/templates/node-lib/bin/test.js +30 -0
  21. package/templates/node-lib/package.json +22 -6
  22. package/templates/node-lib/rollup.config.js +12 -22
  23. package/templates/node-lib/src/readJson.ts +9 -3
  24. package/templates/node-lib/tsconfig.json +19 -1
  25. package/templates/pack-app/eslint.config.js +81 -61
  26. package/templates/pack-app/fe-config.json +1 -5
  27. package/templates/pack-app/package.json +19 -11
  28. package/templates/pack-app/tsconfig.json +1 -1
  29. package/templates/pack-app/vite.config.ts +14 -0
  30. package/templates/react-app/README.md +177 -40
  31. package/templates/react-app/config/i18n.ts +1 -1
  32. package/templates/react-app/lib/fe-react-controller/FeController.ts +7 -3
  33. package/templates/react-app/lib/fe-react-theme/ThemeController.ts +1 -1
  34. package/templates/react-app/package.json +53 -9
  35. package/templates/react-app/src/App.tsx +4 -5
  36. package/templates/react-app/src/{services → base/apis}/feApi/FeApiMockPlugin.ts +1 -1
  37. package/templates/react-app/src/base/cases/UserToken.ts +47 -0
  38. package/templates/react-app/src/base/port/IOCInterface.ts +53 -0
  39. package/templates/react-app/src/base/port/StorageTokenInterface.ts +5 -0
  40. package/templates/react-app/src/{types → base/port}/UIDependenciesInterface.ts +6 -0
  41. package/templates/react-app/src/{types → base/types}/global.d.ts +1 -1
  42. package/templates/react-app/src/components/ThemeSwitcher.tsx +3 -2
  43. package/templates/react-app/src/core/bootstrap.ts +21 -0
  44. package/templates/react-app/src/core/feIOC/FeIOC.ts +32 -0
  45. package/templates/react-app/src/core/feIOC/RegisterApi.ts +41 -0
  46. package/templates/react-app/src/core/feIOC/RegisterCommon.ts +20 -0
  47. package/templates/react-app/src/core/feIOC/RegisterControllers.ts +53 -0
  48. package/templates/react-app/src/core/index.ts +31 -0
  49. package/templates/react-app/src/main.tsx +8 -10
  50. package/templates/react-app/src/pages/404.tsx +2 -2
  51. package/templates/react-app/src/pages/500.tsx +1 -1
  52. package/templates/react-app/src/pages/auth/Layout.tsx +3 -2
  53. package/templates/react-app/src/pages/auth/Login.tsx +6 -4
  54. package/templates/react-app/src/pages/base/About.tsx +1 -1
  55. package/templates/react-app/src/pages/base/Executor.tsx +8 -4
  56. package/templates/react-app/src/pages/base/Home.tsx +1 -1
  57. package/templates/react-app/src/pages/base/JSONStorage.tsx +6 -4
  58. package/templates/react-app/src/pages/base/Layout.tsx +1 -1
  59. package/templates/react-app/src/pages/base/RedirectPathname.tsx +1 -1
  60. package/templates/react-app/src/pages/base/Request.tsx +8 -3
  61. package/templates/react-app/src/pages/index.tsx +7 -2
  62. package/templates/react-app/src/services/{pageProcesser/PageProcesser.ts → processer/ProcesserService.ts} +3 -3
  63. package/templates/react-app/src/{containers/context → uikit/contexts}/BaseRouteContext.ts +4 -4
  64. package/templates/react-app/src/{services → uikit}/controllers/ExecutorController.ts +5 -5
  65. package/templates/react-app/src/{services → uikit}/controllers/JSONStorageController.ts +2 -2
  66. package/templates/react-app/src/{services → uikit}/controllers/RequestController.ts +3 -3
  67. package/templates/react-app/src/{services → uikit}/controllers/RouterController.ts +2 -2
  68. package/templates/react-app/src/{services → uikit}/controllers/UserController.ts +25 -51
  69. package/templates/react-app/src/{containers/context → uikit/providers}/BaseRouteProvider.tsx +2 -2
  70. package/templates/react-app/src/{components → uikit/providers}/ProcessProvider.tsx +13 -7
  71. package/templates/react-app/tsconfig.json +27 -5
  72. package/templates/react-app/tsconfig.node.json +3 -15
  73. package/templates/react-app/vite.config.ts +15 -12
  74. package/templates/pack-app/.env +0 -5
  75. package/templates/pack-app/.gitignore.template +0 -50
  76. package/templates/pack-app/.prettierrc.js +0 -3
  77. package/templates/pack-app/CHANGELOG.md +0 -0
  78. package/templates/pack-app/jest.config.js +0 -31
  79. package/templates/react-app/eslint.config.js +0 -31
  80. package/templates/react-app/src/containers/index.ts +0 -71
  81. package/templates/react-app/src/services/pageProcesser/index.ts +0 -1
  82. package/templates/react-app/tsconfig.app.json +0 -29
  83. package/templates/react-vite-lib/.gitignore.template +0 -27
  84. package/templates/react-vite-lib/README.md +0 -50
  85. package/templates/react-vite-lib/__tests__/Sum.test.ts +0 -9
  86. package/templates/react-vite-lib/__tests__/Text.test.tsx +0 -11
  87. package/templates/react-vite-lib/eslint.config.js +0 -28
  88. package/templates/react-vite-lib/index.html +0 -13
  89. package/templates/react-vite-lib/package.json +0 -30
  90. package/templates/react-vite-lib/public/vite.svg +0 -1
  91. package/templates/react-vite-lib/src/calc.ts +0 -3
  92. package/templates/react-vite-lib/src/commponents/Text.tsx +0 -7
  93. package/templates/react-vite-lib/src/index.ts +0 -2
  94. package/templates/react-vite-lib/src/vite-env.d.ts +0 -1
  95. package/templates/react-vite-lib/tsconfig.json +0 -25
  96. package/templates/react-vite-lib/vite.config.ts +0 -24
  97. /package/{templates/pack-app → configs/_common}/.editorconfig +0 -0
  98. /package/{templates/pack-app → configs/_common}/.gitattributes +0 -0
  99. /package/{templates/react-app → configs/_common}/.gitignore.template +0 -0
  100. /package/{templates/pack-app → configs/_common}/.prettierignore +0 -0
  101. /package/templates/react-app/src/{services → base/apis}/feApi/FeApi.ts +0 -0
  102. /package/templates/react-app/src/{services → base/apis}/feApi/FeApiType.ts +0 -0
  103. /package/templates/react-app/src/{services → base/apis}/feApi/index.ts +0 -0
  104. /package/templates/react-app/src/{types → base/types}/Page.ts +0 -0
  105. /package/templates/react-app/src/{containers → core}/globals.ts +0 -0
  106. /package/templates/react-app/src/{hooks → uikit/hooks}/useLanguageGuard.ts +0 -0
  107. /package/templates/react-app/src/{hooks → uikit/hooks}/useStrictEffect.ts +0 -0
  108. /package/templates/react-app/src/{styles → uikit/styles}/css/index.css +0 -0
  109. /package/templates/react-app/src/{styles → uikit/styles}/css/page.css +0 -0
  110. /package/templates/react-app/src/{styles → uikit/styles}/css/tailwind.css +0 -0
  111. /package/templates/react-app/src/{utils → uikit/utils}/RequestLogger.ts +0 -0
  112. /package/templates/react-app/src/{utils → uikit/utils}/datetime.ts +0 -0
  113. /package/templates/react-app/src/{utils → uikit/utils}/thread.ts +0 -0
@@ -1,10 +1,6 @@
1
1
  {
2
2
  "protectedBranches": ["master", "develop"],
3
3
  "release": {
4
- "packagesDirectories": [
5
- "packages/browser",
6
- "packages/node",
7
- "packages/react-vite-lib"
8
- ]
4
+ "packagesDirectories": []
9
5
  }
10
6
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "@qlover/pack-app",
2
+ "name": "pack-app",
3
3
  "version": "0.0.0",
4
4
  "description": "A template for fe-pack-app",
5
5
  "type": "module",
@@ -10,11 +10,10 @@
10
10
  },
11
11
  "homepage": "https://github.com/qlover/fe-base#readme",
12
12
  "scripts": {
13
- "build": "pnpm run build:[PKG_NAME]",
14
- "build:[PKG_NAME]": "pnpm run build --filter=@qlover/${PKG_NAME}",
13
+ "build": "pnpm -r run build",
15
14
  "prettier": "prettier --ignore-path .prettierignore **/*.{js,ts,json,cjs,mjs} --write",
16
15
  "lint": "eslint . --fix",
17
- "test": "jest",
16
+ "test": "pnpm run test",
18
17
  "clean": "fe-clean",
19
18
  "clean:build": "fe-clean -f packages/*/dist -r",
20
19
  "check-packages": "fe-check-packages",
@@ -39,25 +38,34 @@
39
38
  "@rollup/plugin-node-resolve": "^15.3.0",
40
39
  "@rollup/plugin-terser": "^0.4.4",
41
40
  "@rollup/plugin-typescript": "^12.1.1",
42
- "@testing-library/jest-dom": "^6.6.3",
43
41
  "@testing-library/react": "^16.1.0",
44
- "@types/jest": "^29.5.11",
45
42
  "eslint": "^9.17.0",
46
- "jest": "^29.7.0",
47
- "jest-environment-jsdom": "^29.7.0",
43
+ "eslint-plugin-react": "^7.37.4",
44
+ "eslint-plugin-react-hooks": "^5.0.0",
45
+ "eslint-plugin-react-refresh": "^0.4.14",
46
+ "globals": "^15.12.0",
47
+ "husky": "^9.1.7",
48
+ "jsdom": "^26.0.0",
49
+ "prettier": "^3.5.0",
48
50
  "rollup": "^4.24.2",
49
51
  "rollup-plugin-delete": "^2.1.0",
50
52
  "rollup-plugin-dts": "^6.1.1",
51
53
  "rollup-plugin-typescript2": "^0.36.0",
52
54
  "ts-node": "^10.9.2",
53
- "typescript": "~5.4.0"
55
+ "typescript": "~5.4.0",
56
+ "vite": "^5.4.8",
57
+ "vitest": "^3.0.5"
54
58
  },
55
59
  "workspaces": [
56
60
  "packages/*"
57
61
  ],
58
62
  "lint-staged": {
59
- "*.{js,jsx,ts,tsx}": [
60
- "eslint --fix"
63
+ "packages/**/*.{js,jsx,ts,tsx}": [
64
+ "eslint --cache --fix --quiet",
65
+ "prettier --write"
66
+ ],
67
+ "packages/**/*.{json,css,scss,md}": [
68
+ "prettier --write"
61
69
  ]
62
70
  },
63
71
  "packageManager": "pnpm@9.1.0"
@@ -4,6 +4,6 @@
4
4
  "jsx": "react-jsx",
5
5
  "rootDir": "./"
6
6
  },
7
- "include": ["./packages"],
7
+ "include": ["./packages", "configs/node-lib/eslint.config.js"],
8
8
  "exclude": ["**/node_modules/*", "**/dist", "**/build"]
9
9
  }
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ build: {
5
+ outDir: 'dist',
6
+ sourcemap: true
7
+ },
8
+ plugins: [],
9
+ test: {
10
+ environment: 'jsdom',
11
+ globals: true,
12
+ include: ['**/__tests__/**/*.test.{ts,tsx}']
13
+ }
14
+ });
@@ -1,50 +1,187 @@
1
- # React + TypeScript + Vite
1
+ # FE-React Template
2
2
 
3
- This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
3
+ 一个现代化的 React 前端项目模板,集成了多项实用功能和最佳实践。
4
4
 
5
- Currently, two official plugins are available:
5
+ ## 特性亮点
6
6
 
7
- - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8
- - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
7
+ - 🚀 基于 Vite 的快速开发体验
8
+ - 🎨 集成 Tailwind CSS 的主题系统
9
+ - 🌍 完善的国际化支持
10
+ - 🔄 IOC 容器的依赖注入
11
+ - 📡 统一的 API 请求处理
12
+ - 🎮 控制器模式的状态管理
9
13
 
10
- ## Expanding the ESLint configuration
14
+ ## 环境要求
11
15
 
12
- If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
16
+ - Node.js >= 16
17
+ - pnpm >= 8.0
13
18
 
14
- - Configure the top-level `parserOptions` property like this:
19
+ ## 配置说明
15
20
 
16
- ```js
17
- export default tseslint.config({
18
- languageOptions: {
19
- // other options...
20
- parserOptions: {
21
- project: ['./tsconfig.node.json', './tsconfig.app.json'],
22
- tsconfigRootDir: import.meta.dirname,
23
- },
24
- },
25
- })
21
+ 项目配置文件位于 `config/` 目录:
22
+
23
+ - `app.common.ts`: 应用通用配置,包含 API 配置、默认登录信息等
24
+ - `app.router.json`: 路由配置,定义应用的路由结构
25
+ - `i18n.ts`: 国际化配置,支持中英文切换
26
+ - `theme.json`: 主题配置,定义应用的主题系统
27
+
28
+ ## 项目结构
29
+
30
+ ├── config/ # 配置文件目录
31
+ │ ├── app.common.ts # 应用通用配置
32
+ │ ├── app.router.json # 路由配置
33
+ │ ├── i18n.ts # 国际化配置
34
+ │ └── theme.json # 主题配置
35
+ ├── lib/ # 公共库目录
36
+ │ ├── fe-react-controller/ # React 控制器库
37
+ │ ├── fe-react-theme/ # React 主题库
38
+ │ ├── openAiApi/ # OpenAI API 封装
39
+ │ ├── request-common-plugin/ # 请求公共插件
40
+ │ └── tw-root10px/ # Tailwind 10px 根字体配置
41
+ ├── public/ # 静态资源目录
42
+ │ └── locales/ # 国际化资源文件
43
+ ├── src/ # 源代码目录
44
+ │ ├── base/ # 基础代码
45
+ │ │ ├── apis/ # API 接口定义
46
+ │ │ ├── cases/ # 业务用例
47
+ │ │ ├── port/ # 接口定义
48
+ │ │ └── types/ # 类型定义
49
+ │ ├── core/ # 核心代码
50
+ │ │ └── feIOC/ # IOC 容器实现
51
+ │ │ └── globals.ts # 全局变量
52
+ │ │ └── bootstrap.ts # 启动器
53
+ │ ├── pages/ # 页面组件
54
+ │ ├── services/ # 服务层
55
+ │ └── uikit/ # UI 组件库
56
+ └── vite.config.ts # Vite 配置文件
57
+
58
+ ## 目录结构说明
59
+
60
+ 1. `config/`: 集中管理配置文件,便于统一维护和修改
61
+ 2. `lib/`: 可复用的独立功能库,方便跨项目使用
62
+ 3. `src/base/`: 基础代码层,定义接口和类型
63
+ 4. `src/core/`: 核心功能实现,包含 IOC 容器等基础设施
64
+ 5. `src/pages/`: 页面组件,按功能模块组织
65
+ 6. `src/services/`: 服务层,处理业务逻辑
66
+ 7. `src/uikit/`: UI 组件库,提供可复用的界面组件
67
+
68
+ ## 核心特性
69
+
70
+ ### 1. IOC 容器
71
+
72
+ 项目使用依赖注入容器管理依赖,主要包含:
73
+
74
+ - `FeIOC`: IOC 容器的核心实现
75
+ - `RegisterApi`: API 服务注册
76
+ - `RegisterCommon`: 通用服务注册
77
+ - `RegisterControllers`: 控制器注册
78
+
79
+ ### 2. 国际化支持
80
+
81
+ - 支持中文和英文
82
+ - 使用 i18next 实现
83
+ - 按模块划分语言文件
84
+
85
+ ### 3. 主题系统
86
+
87
+ - 支持主题切换
88
+ - 基于 Tailwind CSS
89
+ - 自定义 10px 根字体配置
90
+
91
+ ### 4. API 请求处理
92
+
93
+ - 统一的请求处理机制
94
+ - 支持请求拦截和响应处理
95
+ - Mock 数据支持
96
+ - OpenAI API 集成
97
+
98
+ ### 5. 控制器模式
99
+
100
+ 采用控制器模式管理业务逻辑:
101
+
102
+ - `JSONStorageController`: JSON 存储控制
103
+ - `RequestController`: 请求控制
104
+ - `RouterController`: 路由控制
105
+ - `UserController`: 用户控制
106
+ - `ThemeController`: 主题控制
107
+
108
+ ## 技术栈
109
+
110
+ - React
111
+ - TypeScript
112
+ - Vite
113
+ - Tailwind CSS
114
+ - i18next
115
+ - @qlover/fe-utils
116
+
117
+ ## 开发
118
+
119
+ 项目使用 pnpm 管理依赖,请先安装 pnpm
120
+
121
+ ```bash
122
+ npm install -g pnpm
123
+ ```
124
+
125
+ ## 开发指南
126
+
127
+ ### API 开发
128
+
129
+ 项目使用统一的 API 请求处理机制:
130
+
131
+ - 支持请求拦截和响应处理
132
+ - 内置 Mock 数据支持
133
+ - 集成 OpenAI API
134
+
135
+ ### 控制器开发
136
+
137
+ 项目采用控制器模式管理业务逻辑:
138
+
139
+ - `JSONStorageController`: 处理 JSON 数据存储
140
+ - `RequestController`: 处理 API 请求
141
+ - `UserController`: 处理用户认证
142
+ - `ThemeController`: 处理主题切换
143
+
144
+ ### 国际化开发
145
+
146
+ 语言文件位于 `public/locales/` 目录:
147
+
148
+ - `zh/`: 中文语言包
149
+ - `en/`: 英文语言包
150
+
151
+ ### 安装依赖
152
+
153
+ ```bash
154
+ pnpm install
26
155
  ```
27
156
 
28
- - Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
29
- - Optionally add `...tseslint.configs.stylisticTypeChecked`
30
- - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
31
-
32
- ```js
33
- // eslint.config.js
34
- import react from 'eslint-plugin-react'
35
-
36
- export default tseslint.config({
37
- // Set the react version
38
- settings: { react: { version: '18.3' } },
39
- plugins: {
40
- // Add the react plugin
41
- react,
42
- },
43
- rules: {
44
- // other rules...
45
- // Enable its recommended rules
46
- ...react.configs.recommended.rules,
47
- ...react.configs['jsx-runtime'].rules,
48
- },
49
- })
157
+ ### 开发模式
158
+
159
+ ```bash
160
+ pnpm run dev
50
161
  ```
162
+
163
+ ### 构建
164
+
165
+ ```bash
166
+ pnpm run build
167
+ ```
168
+
169
+ ### 测试
170
+
171
+ ```bash
172
+ pnpm run test
173
+ ```
174
+
175
+ ## 常见问题
176
+
177
+ ### Q: 如何切换主题?
178
+
179
+ A: 项目支持主题切换功能,通过 ThemeController 进行控制。
180
+
181
+ ### Q: 如何添加新的语言支持?
182
+
183
+ A: 在 `public/locales/` 目录下添加新的语言文件,并在 `i18n.ts` 中配置。
184
+
185
+ ## 许可证
186
+
187
+ ISC
@@ -1,4 +1,4 @@
1
- import { isProduction } from '@/containers/globals';
1
+ import { isProduction } from '@/core/globals';
2
2
 
3
3
  /** @type {import('i18next').InitOptions} */
4
4
  export const i18nConfig = {
@@ -1,8 +1,8 @@
1
- import { SliceStore } from '@qlover/slice-store';
1
+ import { SliceStore } from '@qlover/slice-store-react';
2
2
 
3
3
  export class FeController<T> extends SliceStore<T> {
4
- constructor(initialState: T) {
5
- super(() => initialState);
4
+ constructor(private stateFactory: () => T) {
5
+ super(stateFactory);
6
6
  }
7
7
 
8
8
  getState(): T {
@@ -12,4 +12,8 @@ export class FeController<T> extends SliceStore<T> {
12
12
  setState(state: Partial<T>): void {
13
13
  this.emit({ ...this.state, ...state });
14
14
  }
15
+
16
+ reset(): void {
17
+ this.emit(this.stateFactory());
18
+ }
15
19
  }
@@ -4,7 +4,7 @@ import { ThemeStateGetter } from './ThemeStateGetter';
4
4
 
5
5
  export class ThemeController extends FeController<ThemeControllerState> {
6
6
  constructor(private props: ThemeControllerProps) {
7
- super(ThemeStateGetter.create(props));
7
+ super(() => ThemeStateGetter.create(props));
8
8
 
9
9
  this.bindToTheme();
10
10
  }
@@ -1,13 +1,54 @@
1
1
  {
2
- "name": "fe-react",
3
- "private": true,
2
+ "name": "react-app",
3
+ "description": "A react app template",
4
4
  "version": "0.0.0",
5
5
  "type": "module",
6
+ "private": true,
7
+ "homepage": "",
8
+ "author": "qlover",
9
+ "license": "ISC",
10
+ "main": "./dist/es/index.js",
11
+ "module": "./dist/es/index.js",
12
+ "types": "./dist/es/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/es/index.d.ts",
16
+ "import": "./dist/es/index.js",
17
+ "require": "./dist/cjs/index.js"
18
+ },
19
+ "./cjs/*": "./dist/cjs/*",
20
+ "./es/*": "./dist/es/*",
21
+ "./package.json": "./package.json"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/qlover/fe-base.git",
26
+ "directory": ""
27
+ },
28
+ "files": [
29
+ "bin",
30
+ "dist",
31
+ "package.json",
32
+ "README.md"
33
+ ],
34
+ "keywords": [
35
+ "scripts",
36
+ "release",
37
+ "fe-release"
38
+ ],
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "bin": {
43
+ "fe-release": "./bin/release.js"
44
+ },
6
45
  "scripts": {
7
46
  "dev": "vite",
8
- "build": "tsc -b && vite build",
9
- "lint": "eslint .",
10
- "preview": "vite preview"
47
+ "build": "vite build",
48
+ "lint": "eslint ./src --fix",
49
+ "prettier": "prettier --write ./src",
50
+ "preview": "vite preview",
51
+ "test": "vitest run"
11
52
  },
12
53
  "dependencies": {
13
54
  "@qlover/fe-utils": "latest",
@@ -19,12 +60,12 @@
19
60
  "react": "^18.3.1",
20
61
  "react-dom": "^18.3.1",
21
62
  "react-i18next": "^15.2.0",
22
- "react-router-dom": "6"
63
+ "react-router-dom": "^7.1.5"
23
64
  },
24
65
  "devDependencies": {
25
66
  "@eslint/js": "^9.11.1",
26
- "@qlover/eslint-plugin-fe-dev": "^0.2.0",
27
67
  "@qlover/env-loader": "latest",
68
+ "@qlover/eslint-plugin-fe-dev": "^0.2.0",
28
69
  "@qlover/fe-scripts": "latest",
29
70
  "@rollup/plugin-alias": "^5.1.1",
30
71
  "@types/lodash": "^4.17.13",
@@ -32,10 +73,12 @@
32
73
  "@types/react-dom": "^18.3.0",
33
74
  "@types/react-syntax-highlighter": "^15.5.13",
34
75
  "@types/typo-js": "^1.2.2",
35
- "@vitejs/plugin-react": "^4.3.2",
76
+ "@vitejs/plugin-react": "^4.3.4",
36
77
  "@vitejs/plugin-react-swc": "^3.5.0",
37
78
  "autoprefixer": "^10.4.20",
38
79
  "eslint": "^9.15.0",
80
+ "eslint-plugin-prettier": "^5.2.3",
81
+ "eslint-plugin-react": "^7.37.4",
39
82
  "eslint-plugin-react-hooks": "^5.0.0",
40
83
  "eslint-plugin-react-refresh": "^0.4.14",
41
84
  "globals": "^15.12.0",
@@ -45,6 +88,7 @@
45
88
  "typescript": "^5.6.3",
46
89
  "typescript-eslint": "^8.15.0",
47
90
  "vite": "^5.4.8",
48
- "vite-plugin-cross-origin-isolation": "^0.1.6"
91
+ "vite-plugin-cross-origin-isolation": "^0.1.6",
92
+ "vitest": "^3.0.5"
49
93
  }
50
94
  }
@@ -1,14 +1,13 @@
1
- import './styles/css/index.css';
1
+ import '@/uikit/styles/css/index.css';
2
2
  import { createBrowserRouter, RouterProvider } from 'react-router-dom';
3
3
  import { createFeReactRoutes } from './pages';
4
- import { I18nService } from '@/services/i18n';
5
4
  import { useMemo } from 'react';
6
- import { routerController } from './containers';
7
-
8
- I18nService.init();
5
+ import { IOC } from './core';
6
+ import { RouterController } from './uikit/controllers/RouterController';
9
7
 
10
8
  function App() {
11
9
  const routerBase = useMemo(() => {
10
+ const routerController = IOC(RouterController);
12
11
  const routes = createFeReactRoutes(routerController.getRoutes());
13
12
  const router = createBrowserRouter(routes);
14
13
  return router;
@@ -4,7 +4,7 @@ import {
4
4
  RequestAdapterFetchConfig,
5
5
  RequestAdapterResponse
6
6
  } from '@qlover/fe-utils';
7
- import { sleep } from '@/utils/thread';
7
+ import { sleep } from '@/uikit/utils/thread';
8
8
 
9
9
  export class FeApiMockPlugin implements ExecutorPlugin {
10
10
  readonly pluginName = 'FeApiMockPlugin';
@@ -0,0 +1,47 @@
1
+ import { StorageTokenInterface } from '@/base/port/StorageTokenInterface';
2
+ import { adjustExpirationTime } from '@/uikit/utils/datetime';
3
+ import { JSONStorage } from '@qlover/fe-utils';
4
+
5
+ export interface UserTokenOptions {
6
+ /**
7
+ * @default `month`
8
+ */
9
+ expiresIn?: number | 'day' | 'week' | 'month' | 'year';
10
+ storageKey: string;
11
+ storage: JSONStorage;
12
+ }
13
+
14
+ export class UserToken implements StorageTokenInterface {
15
+ private token = '';
16
+
17
+ constructor(private options: UserTokenOptions) {}
18
+
19
+ getToken(): string {
20
+ if (!this.token) {
21
+ const { storageKey, storage } = this.options;
22
+ const token = storage.getItem(storageKey, '');
23
+
24
+ if (token) {
25
+ this.setToken(token);
26
+ }
27
+ }
28
+
29
+ return this.token;
30
+ }
31
+
32
+ setToken(token: string, expireTime?: number): void {
33
+ this.token = token;
34
+
35
+ expireTime =
36
+ expireTime !== undefined
37
+ ? expireTime
38
+ : adjustExpirationTime(Date.now(), this.options.expiresIn ?? 'month');
39
+
40
+ this.options.storage.setItem(this.options.storageKey, token, expireTime);
41
+ }
42
+
43
+ removeToken(): void {
44
+ this.token = '';
45
+ this.options.storage.removeItem(this.options.storageKey);
46
+ }
47
+ }
@@ -0,0 +1,53 @@
1
+ export interface Abstract<T> {
2
+ prototype: T;
3
+ }
4
+ export type Newable<T, Args extends unknown[] = unknown[]> = new (
5
+ ...args: Args
6
+ ) => T;
7
+
8
+ export type ServiceIdentifier<T = unknown> =
9
+ | string
10
+ | symbol
11
+ | Newable<T>
12
+ | Abstract<T>;
13
+
14
+ /**
15
+ * IOC container
16
+ *
17
+ */
18
+ export interface IOCInterface {
19
+ /**
20
+ * configure IOC container
21
+ */
22
+ configure(): void;
23
+
24
+ /**
25
+ * bind instance
26
+ *
27
+ * @param serviceIdentifier
28
+ * @param value
29
+ */
30
+ bind<T>(serviceIdentifier: ServiceIdentifier<T>, value: T): void;
31
+
32
+ /**
33
+ * get instance
34
+ *
35
+ * @param serviceIdentifier
36
+ * @returns
37
+ */
38
+ get<T>(serviceIdentifier: ServiceIdentifier<T>): T;
39
+
40
+ /**
41
+ * You can also use the override method to specify a replacement at runtime
42
+ *
43
+ * However, it may have performance issues because it creates an additional instance
44
+ *
45
+ * @param serviceIdentifier
46
+ * @param value
47
+ */
48
+ override<T>(serviceIdentifier: ServiceIdentifier<T>, value: T): void;
49
+ }
50
+
51
+ export interface IOCRegisterInterface {
52
+ register(container: IOCInterface): void;
53
+ }
@@ -0,0 +1,5 @@
1
+ export interface StorageTokenInterface {
2
+ getToken(): string;
3
+ setToken(token: string, expireTime?: number): void;
4
+ removeToken(): void;
5
+ }
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Need to be used in the UI component
3
+ *
4
+ * eg. A service use window.localStorage, it should be like this:
5
+ *
6
+ */
1
7
  export interface UIDependenciesInterface<Dep = unknown> {
2
8
  /**
3
9
  * Represents the dependencies required by the UI component.
@@ -1,4 +1,4 @@
1
- import * as feGlobals from '@/containers/globals';
1
+ import * as feGlobals from '@/core/globals';
2
2
 
3
3
  declare global {
4
4
  interface Window {
@@ -1,9 +1,10 @@
1
- import { themeController } from '@/containers';
1
+ import { IOC } from '@/core';
2
2
  import { useController } from '@lib/fe-react-controller';
3
+ import { ThemeController } from '@lib/fe-react-theme/ThemeController';
3
4
  import { useTranslation } from 'react-i18next';
4
5
 
5
6
  export default function ThemeSwitcher() {
6
- const controller = useController(themeController);
7
+ const controller = useController(IOC(ThemeController));
7
8
  const { theme } = controller.getState();
8
9
  const themes = controller.getSupportedThemes();
9
10
  const { t } = useTranslation('common');
@@ -0,0 +1,21 @@
1
+ import * as feGlobals from '@/core/globals';
2
+ import { IOC } from '.';
3
+ import { IOCInterface } from '@/base/port/IOCInterface';
4
+ import { I18nService } from '@/services/i18n';
5
+
6
+ export class Bootstrap {
7
+ constructor(private IOCContainer: IOCInterface) {}
8
+
9
+ start(): void {
10
+ // set global feGlobals
11
+ if (typeof window !== 'undefined') {
12
+ window.feGlobals = Object.freeze(Object.assign({}, feGlobals));
13
+ }
14
+
15
+ // startup IOC
16
+ IOC.implement(this.IOCContainer);
17
+
18
+ // startup i18n
19
+ I18nService.init();
20
+ }
21
+ }