@qlover/create-app 0.6.3 → 0.7.1

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 (55) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/configs/node-lib/eslint.config.js +3 -3
  3. package/dist/configs/react-app/eslint.config.js +3 -3
  4. package/dist/index.cjs +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/templates/pack-app/eslint.config.js +3 -3
  7. package/dist/templates/pack-app/package.json +1 -1
  8. package/dist/templates/react-app/__tests__/__mocks__/I18nService.ts +13 -0
  9. package/dist/templates/react-app/__tests__/__mocks__/MockAppConfit.ts +48 -0
  10. package/dist/templates/react-app/__tests__/__mocks__/MockDialogHandler.ts +16 -0
  11. package/dist/templates/react-app/__tests__/__mocks__/MockLogger.ts +14 -0
  12. package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +92 -0
  13. package/dist/templates/react-app/__tests__/setup/index.ts +51 -0
  14. package/dist/templates/react-app/__tests__/src/App.test.tsx +139 -0
  15. package/dist/templates/react-app/__tests__/src/base/cases/AppConfig.test.ts +288 -0
  16. package/dist/templates/react-app/__tests__/src/base/cases/AppError.test.ts +102 -0
  17. package/dist/templates/react-app/__tests__/src/base/cases/DialogHandler.test.ts +228 -0
  18. package/dist/templates/react-app/__tests__/src/base/cases/I18nKeyErrorPlugin.test.ts +207 -0
  19. package/dist/templates/react-app/__tests__/src/base/cases/InversifyContainer.test.ts +181 -0
  20. package/dist/templates/react-app/__tests__/src/base/cases/PublicAssetsPath.test.ts +61 -0
  21. package/dist/templates/react-app/__tests__/src/base/cases/RequestLogger.test.ts +199 -0
  22. package/dist/templates/react-app/__tests__/src/base/cases/RequestStatusCatcher.test.ts +192 -0
  23. package/dist/templates/react-app/__tests__/src/base/cases/RouterLoader.test.ts +235 -0
  24. package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +224 -0
  25. package/dist/templates/react-app/__tests__/src/core/IOC.test.ts +257 -0
  26. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapsApp.test.ts +72 -0
  27. package/dist/templates/react-app/__tests__/src/main.integration.test.tsx +62 -0
  28. package/dist/templates/react-app/__tests__/src/main.test.tsx +46 -0
  29. package/dist/templates/react-app/__tests__/src/uikit/components/BaseHeader.test.tsx +88 -0
  30. package/dist/templates/react-app/config/app.router.ts +155 -0
  31. package/dist/templates/react-app/config/common.ts +9 -1
  32. package/dist/templates/react-app/docs/en/test-guide.md +782 -0
  33. package/dist/templates/react-app/docs/zh/test-guide.md +782 -0
  34. package/dist/templates/react-app/package.json +9 -20
  35. package/dist/templates/react-app/public/locales/en/common.json +1 -1
  36. package/dist/templates/react-app/public/locales/zh/common.json +1 -1
  37. package/dist/templates/react-app/src/base/cases/AppConfig.ts +16 -9
  38. package/dist/templates/react-app/src/base/cases/PublicAssetsPath.ts +7 -1
  39. package/dist/templates/react-app/src/base/services/I18nService.ts +15 -4
  40. package/dist/templates/react-app/src/base/services/RouteService.ts +43 -7
  41. package/dist/templates/react-app/src/core/bootstraps/BootstrapApp.ts +31 -10
  42. package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +1 -1
  43. package/dist/templates/react-app/src/core/globals.ts +1 -3
  44. package/dist/templates/react-app/src/core/registers/RegisterCommon.ts +5 -3
  45. package/dist/templates/react-app/src/main.tsx +6 -1
  46. package/dist/templates/react-app/src/pages/404.tsx +0 -1
  47. package/dist/templates/react-app/src/pages/500.tsx +1 -1
  48. package/dist/templates/react-app/src/pages/base/RedirectPathname.tsx +3 -1
  49. package/dist/templates/react-app/src/uikit/components/BaseHeader.tsx +9 -2
  50. package/dist/templates/react-app/src/uikit/components/LocaleLink.tsx +5 -3
  51. package/dist/templates/react-app/src/uikit/hooks/useI18nGuard.ts +4 -6
  52. package/dist/templates/react-app/tsconfig.json +2 -1
  53. package/dist/templates/react-app/tsconfig.test.json +13 -0
  54. package/dist/templates/react-app/vite.config.ts +3 -2
  55. package/package.json +3 -3
@@ -0,0 +1,257 @@
1
+ import { IOC, type IOCContainer, type IOCIdentifierMap } from '@/core/IOC';
2
+ import { InversifyContainer } from '@/base/cases/InversifyContainer';
3
+ import { IocRegisterImpl } from '@/core/registers/IocRegisterImpl';
4
+ import { IOCIdentifier } from '@config/IOCIdentifier';
5
+ import type { AppConfig } from '@/base/cases/AppConfig';
6
+
7
+ describe('IOC Container Tests', () => {
8
+ let container: IOCContainer;
9
+ let mockAppConfig: AppConfig;
10
+
11
+ beforeEach(() => {
12
+ container = new InversifyContainer();
13
+ mockAppConfig = {
14
+ appName: '',
15
+ appVersion: '',
16
+ env: 'test',
17
+ userInfoStorageKey: '__fe_user_info__',
18
+ userTokenStorageKey: '__fe_user_token__',
19
+ openAiModels: [
20
+ 'gpt-4o-mini',
21
+ 'gpt-3.5-turbo',
22
+ 'gpt-3.5-turbo-2',
23
+ 'gpt-4',
24
+ 'gpt-4-32k'
25
+ ],
26
+ openAiBaseUrl: '',
27
+ openAiToken: '',
28
+ openAiTokenPrefix: '',
29
+ openAiRequireToken: true,
30
+ loginUser: '',
31
+ loginPassword: '',
32
+ feApiBaseUrl: '',
33
+ userApiBaseUrl: '',
34
+ aiApiBaseUrl: 'https://api.openai.com/v1',
35
+ aiApiToken: '',
36
+ aiApiTokenPrefix: 'Bearer',
37
+ aiApiRequireToken: true,
38
+ bootHref: ''
39
+ };
40
+ });
41
+
42
+ describe('InversifyContainer', () => {
43
+ it('should create container with correct configuration', () => {
44
+ expect(container).toBeInstanceOf(InversifyContainer);
45
+ });
46
+
47
+ it('should bind and get services correctly', () => {
48
+ const mockService = { test: 'service' };
49
+ const mockKey = 'testKey';
50
+
51
+ container.bind(mockKey, mockService);
52
+ const result = container.get(mockKey);
53
+
54
+ expect(result).toBe(mockService);
55
+ });
56
+
57
+ it('should handle string identifiers correctly', () => {
58
+ const mockLogger = { info: vi.fn() };
59
+ container.bind(IOCIdentifier.Logger, mockLogger);
60
+
61
+ const result = container.get(IOCIdentifier.Logger);
62
+ expect(result).toBe(mockLogger);
63
+ });
64
+ });
65
+
66
+ describe('IOC Function', () => {
67
+ it('should be a function', () => {
68
+ expect(typeof IOC).toBe('function');
69
+ });
70
+
71
+ it('should accept string identifiers', () => {
72
+ // This test verifies that IOC function can be called with string identifiers
73
+ // The function should accept the identifier, but will throw if service is not bound
74
+ expect(() => {
75
+ IOC(IOCIdentifier.Logger);
76
+ }).toThrow();
77
+ });
78
+
79
+ it('should accept class constructors', () => {
80
+ // Mock class for testing
81
+ class TestService {
82
+ constructor() {}
83
+ }
84
+
85
+ // if service is not bound, it will return the class itself
86
+ const result = IOC(TestService);
87
+ expect(result).toBeInstanceOf(TestService);
88
+ });
89
+ });
90
+
91
+ describe('IocRegisterImpl', () => {
92
+ let registerImpl: IocRegisterImpl;
93
+
94
+ beforeEach(() => {
95
+ registerImpl = new IocRegisterImpl({
96
+ pathname: '/test',
97
+ appConfig: mockAppConfig
98
+ });
99
+ });
100
+
101
+ it('should create register implementation correctly', () => {
102
+ expect(registerImpl).toBeInstanceOf(IocRegisterImpl);
103
+ });
104
+
105
+ it('should return register list', () => {
106
+ const registerList = registerImpl.getRegisterList();
107
+ expect(Array.isArray(registerList)).toBe(true);
108
+ expect(registerList.length).toBeGreaterThan(0);
109
+ });
110
+
111
+ it('should register services without throwing', () => {
112
+ const mockManager = {
113
+ get: vi.fn(),
114
+ bind: vi.fn(),
115
+ implement: vi.fn(),
116
+ implemention: container
117
+ };
118
+
119
+ expect(() => {
120
+ registerImpl.register(container, mockManager);
121
+ }).not.toThrow();
122
+ });
123
+ });
124
+
125
+ describe('IOCIdentifierMap Type Safety', () => {
126
+ it('should have correct type mapping for JSON', () => {
127
+ // This test verifies that the type mapping is correct
128
+ const identifierMap: IOCIdentifierMap = {} as IOCIdentifierMap;
129
+
130
+ // TypeScript should enforce that these keys exist
131
+ expect(IOCIdentifier.JSON in identifierMap).toBeDefined();
132
+ expect(IOCIdentifier.LocalStorage in identifierMap).toBeDefined();
133
+ expect(IOCIdentifier.Logger in identifierMap).toBeDefined();
134
+ expect(IOCIdentifier.AppConfig in identifierMap).toBeDefined();
135
+ });
136
+
137
+ it('should have all required identifiers', () => {
138
+ const requiredIdentifiers = [
139
+ 'JSON',
140
+ 'LocalStorage',
141
+ 'LocalStorageEncrypt',
142
+ 'CookieStorage',
143
+ 'Logger',
144
+ 'FeApiToken',
145
+ 'FeApiCommonPlugin',
146
+ 'AppConfig',
147
+ 'ApiMockPlugin',
148
+ 'ApiCatchPlugin',
149
+ 'DialogHandler'
150
+ ];
151
+
152
+ requiredIdentifiers.forEach((identifier) => {
153
+ expect(IOCIdentifier).toHaveProperty(identifier);
154
+ });
155
+ });
156
+ });
157
+
158
+ describe('Service Registration Integration', () => {
159
+ it('should register global services correctly', async () => {
160
+ const registerImpl = new IocRegisterImpl({
161
+ pathname: '/test',
162
+ appConfig: mockAppConfig
163
+ });
164
+
165
+ const mockManager = {
166
+ get: vi.fn(),
167
+ bind: vi.fn(),
168
+ implement: vi.fn(),
169
+ implemention: container
170
+ };
171
+
172
+ // This should not throw and should register services
173
+ expect(() => {
174
+ registerImpl.register(container, mockManager);
175
+ }).not.toThrow();
176
+ });
177
+
178
+ it('should handle app config registration', () => {
179
+ container.bind(IOCIdentifier.AppConfig, mockAppConfig);
180
+ const result = container.get(IOCIdentifier.AppConfig);
181
+
182
+ expect(result).toBe(mockAppConfig);
183
+ expect(result.appName).toBe('');
184
+ expect(result.env).toBe('test');
185
+ });
186
+
187
+ it('should handle logger registration', () => {
188
+ const mockLogger = {
189
+ info: vi.fn(),
190
+ warn: vi.fn(),
191
+ error: vi.fn(),
192
+ debug: vi.fn()
193
+ };
194
+
195
+ container.bind(IOCIdentifier.Logger, mockLogger);
196
+ const result = container.get(IOCIdentifier.Logger);
197
+
198
+ expect(result).toBe(mockLogger);
199
+ expect(typeof result.info).toBe('function');
200
+ });
201
+ });
202
+
203
+ describe('Error Handling', () => {
204
+ it('should handle missing service gracefully', () => {
205
+ expect(() => {
206
+ container.get('NonExistentService');
207
+ }).toThrow();
208
+ });
209
+
210
+ it('should handle invalid identifier types', () => {
211
+ expect(() => {
212
+ container.get(null as never);
213
+ }).toThrow();
214
+ });
215
+ });
216
+
217
+ describe('Dependency Injection', () => {
218
+ it('should support injectable decorators', () => {
219
+ // This test verifies that the container supports @injectable decorators
220
+ // The autobind configuration should allow this
221
+ expect(container).toBeDefined();
222
+ });
223
+
224
+ it('should support singleton scope', () => {
225
+ // This test verifies that the container uses singleton scope by default
226
+ const service1 = { id: 'test' };
227
+ const service2 = { id: 'test' };
228
+
229
+ container.bind('TestService1', service1);
230
+ container.bind('TestService2', service2);
231
+
232
+ const result1 = container.get('TestService1');
233
+ const result2 = container.get('TestService2');
234
+
235
+ expect(result1).toBe(service1);
236
+ expect(result2).toBe(service2);
237
+ });
238
+ });
239
+
240
+ describe('IOCIdentifier Constants', () => {
241
+ it('should be frozen object', () => {
242
+ expect(Object.isFrozen(IOCIdentifier)).toBe(true);
243
+ });
244
+
245
+ it('should have string values', () => {
246
+ Object.values(IOCIdentifier).forEach((value) => {
247
+ expect(typeof value).toBe('string');
248
+ });
249
+ });
250
+
251
+ it('should have unique values', () => {
252
+ const values = Object.values(IOCIdentifier);
253
+ const uniqueValues = new Set(values);
254
+ expect(uniqueValues.size).toBe(values.length);
255
+ });
256
+ });
257
+ });
@@ -0,0 +1,72 @@
1
+ import { InversifyContainer } from '@/base/cases/InversifyContainer';
2
+ import { BootstrapApp } from '@/core/bootstraps/BootstrapApp';
3
+ import type { BootstrapAppArgs } from '@/core/bootstraps/BootstrapApp';
4
+ import { createIOCFunction } from '@qlover/corekit-bridge';
5
+ import type { IOCIdentifierMap } from '@/core/IOC';
6
+ import { name, version } from '../../../../package.json';
7
+ import { browserGlobalsName } from '@config/common';
8
+
9
+ // Mock IocRegisterImpl to properly handle registration
10
+ vi.mock('@/core/registers/IocRegisterImpl', () => ({
11
+ IocRegisterImpl: vi.fn().mockImplementation((_options) => ({
12
+ getRegisterList: vi.fn().mockReturnValue([]),
13
+ register: vi.fn().mockImplementation((_container, _manager) => {
14
+ // Mock the actual registration process to avoid I18nService constructor issues
15
+ // This prevents the real registration from happening which causes the error
16
+ })
17
+ }))
18
+ }));
19
+
20
+ // Mock BootstrapsRegistry to avoid I18nService instantiation
21
+ vi.mock('@/core/bootstraps/BootstrapsRegistry', () => ({
22
+ BootstrapsRegistry: vi.fn().mockImplementation(() => ({
23
+ register: vi.fn().mockReturnValue([])
24
+ }))
25
+ }));
26
+
27
+ describe('BootstrapApp', () => {
28
+ let mockArgs: BootstrapAppArgs;
29
+ let mockIOC: ReturnType<typeof createIOCFunction<IOCIdentifierMap>>;
30
+
31
+ beforeEach(() => {
32
+ // Reset all mocks
33
+ vi.clearAllMocks();
34
+
35
+ // Setup mock IOC with proper typing
36
+ const container = new InversifyContainer();
37
+ mockIOC = createIOCFunction<IOCIdentifierMap>(container);
38
+
39
+ // Setup test arguments
40
+ mockArgs = {
41
+ root: {},
42
+ bootHref: 'http://localhost:3000',
43
+ IOC: mockIOC
44
+ };
45
+ });
46
+
47
+ describe('main', () => {
48
+ it('should initialize bootstrap successfully', async () => {
49
+ const result = await BootstrapApp.main(mockArgs);
50
+
51
+ expect(result.bootHref).toBe('http://localhost:3000');
52
+ // default inject env,globals var, ioc
53
+
54
+ expect(
55
+ (mockArgs.root as Record<string, unknown>)[browserGlobalsName]
56
+ ).toBeDefined();
57
+
58
+ // Verify that the globals object is injected into root
59
+ const injectedGlobals = (mockArgs.root as Record<string, unknown>)[
60
+ browserGlobalsName
61
+ ] as Record<string, unknown>;
62
+ expect(injectedGlobals).toHaveProperty('logger');
63
+ expect(injectedGlobals).toHaveProperty('appConfig');
64
+ expect(
65
+ (injectedGlobals.appConfig as Record<string, unknown>).appName
66
+ ).toBe(name);
67
+ expect(
68
+ (injectedGlobals.appConfig as Record<string, unknown>).appVersion
69
+ ).toBe(version);
70
+ });
71
+ });
72
+ });
@@ -0,0 +1,62 @@
1
+ import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
2
+ import { readFileSync, existsSync } from 'fs';
3
+ import { join } from 'path';
4
+
5
+ describe('main.tsx Integration Tests', () => {
6
+ beforeAll(() => {
7
+ // Setup test environment
8
+ if (!document.getElementById('root')) {
9
+ const rootElement = document.createElement('div');
10
+ rootElement.id = 'root';
11
+ document.body.appendChild(rootElement);
12
+ }
13
+ });
14
+
15
+ afterAll(() => {
16
+ // Clean up DOM
17
+ const rootElement = document.getElementById('root');
18
+ if (rootElement) {
19
+ rootElement.remove();
20
+ }
21
+ });
22
+
23
+ beforeEach(() => {
24
+ // Clean up root element content
25
+ const rootElement = document.getElementById('root');
26
+ if (rootElement) {
27
+ rootElement.innerHTML = '';
28
+ }
29
+ });
30
+
31
+ it('should have main.tsx file', () => {
32
+ // Test if file exists
33
+ const mainPath = join(process.cwd(), 'src/main.tsx');
34
+ expect(existsSync(mainPath)).toBe(true);
35
+ });
36
+
37
+ it('should have main.tsx with correct structure', () => {
38
+ // Test file content structure
39
+ const mainPath = join(process.cwd(), 'src/main.tsx');
40
+ const content = readFileSync(mainPath, 'utf-8');
41
+
42
+ // Check if it contains necessary imports
43
+ expect(content).toContain('import');
44
+ expect(content).toContain('BootstrapApp');
45
+ expect(content).toContain('createRoot');
46
+ });
47
+
48
+ it('should have App.tsx file', () => {
49
+ // Test if App.tsx file exists
50
+ const appPath = join(process.cwd(), 'src/App.tsx');
51
+ expect(existsSync(appPath)).toBe(true);
52
+ });
53
+
54
+ it('should have BootstrapApp.ts file', () => {
55
+ // Test if BootstrapApp.ts file exists
56
+ const bootstrapPath = join(
57
+ process.cwd(),
58
+ 'src/core/bootstraps/BootstrapApp.ts'
59
+ );
60
+ expect(existsSync(bootstrapPath)).toBe(true);
61
+ });
62
+ });
@@ -0,0 +1,46 @@
1
+ import { BootstrapApp } from '@/core/bootstraps/BootstrapApp';
2
+
3
+ // Mock BootstrapApp
4
+ vi.mock('@/core/bootstraps/BootstrapApp', () => ({
5
+ BootstrapApp: {
6
+ main: vi.fn()
7
+ }
8
+ }));
9
+
10
+ // Mock react-dom
11
+ vi.mock('react-dom/client', () => ({
12
+ createRoot: vi.fn(() => ({
13
+ render: vi.fn(),
14
+ unmount: vi.fn()
15
+ }))
16
+ }));
17
+
18
+ // Mock App component
19
+ vi.mock('@/App', () => ({
20
+ default: vi.fn(() => 'MockedApp')
21
+ }));
22
+
23
+ describe('main.tsx', () => {
24
+ beforeEach(() => {
25
+ vi.clearAllMocks();
26
+ vi.resetModules();
27
+ });
28
+
29
+ afterEach(() => {
30
+ vi.restoreAllMocks();
31
+ });
32
+
33
+ describe('BootstrapApp initialization', () => {
34
+ it('should call BootstrapApp.main()', async () => {
35
+ await import('@/main');
36
+ expect(BootstrapApp.main).toHaveBeenCalledTimes(1);
37
+ });
38
+ });
39
+
40
+ describe('Module loading', () => {
41
+ it('should load main module without errors', async () => {
42
+ const mainModule = await import('@/main');
43
+ expect(mainModule).toBeDefined();
44
+ });
45
+ });
46
+ });
@@ -0,0 +1,88 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { vi, expect } from 'vitest';
3
+ import BaseHeader from '@/uikit/components/BaseHeader';
4
+ import { PublicAssetsPath } from '@/base/cases/PublicAssetsPath';
5
+
6
+ // Mock dependencies
7
+ const mockPublicAssetsPath = new PublicAssetsPath('');
8
+
9
+ vi.mock('@/core/IOC', () => ({
10
+ IOC: vi.fn((key) => {
11
+ if (key === 'AppConfig') {
12
+ return { appName: 'Test App' };
13
+ }
14
+ if (key === PublicAssetsPath) {
15
+ return mockPublicAssetsPath;
16
+ }
17
+ return {};
18
+ })
19
+ }));
20
+
21
+ // Mock child components
22
+ vi.mock('@/uikit/components/ThemeSwitcher', () => ({
23
+ default: () => <div data-testid="theme-switcher">Theme Switcher</div>
24
+ }));
25
+
26
+ interface LocaleLinkProps {
27
+ children: React.ReactNode;
28
+ href: string;
29
+ className?: string;
30
+ }
31
+
32
+ vi.mock('@/uikit/components/LocaleLink', () => ({
33
+ default: ({ children, href, className }: LocaleLinkProps) => (
34
+ <a href={href} className={className} data-testid="locale-link">
35
+ {children}
36
+ </a>
37
+ )
38
+ }));
39
+
40
+ vi.mock('@/uikit/components/LanguageSwitcher', () => ({
41
+ default: () => <div data-testid="language-switcher">Language Switcher</div>
42
+ }));
43
+
44
+ vi.mock('@/uikit/components/LogoutButton', () => ({
45
+ default: () => <div data-testid="logout-button">Logout</div>
46
+ }));
47
+
48
+ describe('BaseHeader', () => {
49
+ it('renders header with correct structure', () => {
50
+ render(<BaseHeader />);
51
+ expect(screen.getByTestId('base-header')).toBeDefined();
52
+ });
53
+
54
+ it('renders logo and app name correctly', () => {
55
+ render(<BaseHeader />);
56
+ const logo = screen.getByTestId('base-header-logo');
57
+ const appName = screen.getByTestId('base-header-app-name');
58
+
59
+ expect(logo).toBeDefined();
60
+ expect(logo.getAttribute('src')).toBe('/logo.svg');
61
+ expect(logo.getAttribute('alt')).toBe('logo');
62
+ expect(appName).toBeDefined();
63
+ expect(appName.textContent).toBe('Test App');
64
+ });
65
+
66
+ it('renders theme and language switchers', () => {
67
+ render(<BaseHeader />);
68
+ expect(screen.getByTestId('theme-switcher')).toBeDefined();
69
+ expect(screen.getByTestId('language-switcher')).toBeDefined();
70
+ });
71
+
72
+ it('renders logout button when showLogoutButton is true', () => {
73
+ render(<BaseHeader showLogoutButton />);
74
+ expect(screen.getByTestId('logout-button')).toBeDefined();
75
+ });
76
+
77
+ it('does not render logout button when showLogoutButton is false', () => {
78
+ render(<BaseHeader showLogoutButton={false} />);
79
+ expect(screen.queryByTestId('logout-button')).toBeNull();
80
+ });
81
+
82
+ it('renders home link correctly', () => {
83
+ render(<BaseHeader />);
84
+ const link = screen.getByTestId('locale-link');
85
+ expect(link).toBeDefined();
86
+ expect(link.getAttribute('href')).toBe('/');
87
+ });
88
+ });
@@ -161,3 +161,158 @@ export const baseRoutes: RouteConfigValue[] = [
161
161
  }
162
162
  }
163
163
  ];
164
+
165
+ export const baseNoLocaleRoutes: RouteConfigValue[] = [
166
+ {
167
+ path: '/',
168
+ element: 'base/Layout',
169
+ meta: {
170
+ category: 'main'
171
+ },
172
+ children: [
173
+ {
174
+ index: true,
175
+ element: 'base/HomePage',
176
+ meta: {
177
+ title: identifier.PAGE_HOME_TITLE,
178
+ description: identifier.PAGE_HOME_DESCRIPTION,
179
+ icon: 'home',
180
+ localNamespace: 'common'
181
+ }
182
+ },
183
+ {
184
+ path: 'about',
185
+ element: 'base/AboutPage',
186
+ meta: {
187
+ title: identifier.PAGE_ABOUT_TITLE,
188
+ description: identifier.PAGE_ABOUT_DESCRIPTION,
189
+ icon: 'info',
190
+ localNamespace: 'common'
191
+ }
192
+ },
193
+ {
194
+ path: 'jsonStorage',
195
+ element: 'base/JSONStoragePage',
196
+ meta: {
197
+ title: identifier.PAGE_JSONSTORAGE_TITLE,
198
+ description: identifier.PAGE_JSONSTORAGE_DESCRIPTION,
199
+ icon: 'info',
200
+ localNamespace: 'common'
201
+ }
202
+ },
203
+ {
204
+ path: 'request',
205
+ element: 'base/RequestPage',
206
+ meta: {
207
+ title: identifier.PAGE_REQUEST_TITLE,
208
+ description: identifier.PAGE_REQUEST_DESCRIPTION,
209
+ icon: 'info',
210
+ localNamespace: 'common'
211
+ }
212
+ },
213
+ {
214
+ path: 'executor',
215
+ element: 'base/ExecutorPage',
216
+ meta: {
217
+ title: identifier.PAGE_EXECUTOR_TITLE,
218
+ description: identifier.PAGE_EXECUTOR_DESCRIPTION,
219
+ icon: 'info',
220
+ localNamespace: 'common'
221
+ }
222
+ },
223
+ {
224
+ path: 'errorIdentifier',
225
+ element: 'base/ErrorIdentifierPage',
226
+ meta: {
227
+ title: identifier.PAGE_ERROR_IDENTIFIER_TITLE,
228
+ description: identifier.PAGE_ERROR_IDENTIFIER_DESCRIPTION,
229
+ icon: 'info',
230
+ localNamespace: 'common'
231
+ }
232
+ },
233
+ {
234
+ path: '404',
235
+ element: '404',
236
+ meta: {
237
+ category: 'common',
238
+ title: identifier.PAGE_404_TITLE,
239
+ description: identifier.PAGE_404_DESCRIPTION,
240
+ localNamespace: 'common'
241
+ }
242
+ },
243
+ {
244
+ path: '500',
245
+ element: '500',
246
+ meta: {
247
+ category: 'common',
248
+ title: identifier.PAGE_500_TITLE,
249
+ description: identifier.PAGE_500_DESCRIPTION,
250
+ localNamespace: 'common'
251
+ }
252
+ }
253
+ ]
254
+ },
255
+ {
256
+ path: '/',
257
+ element: 'auth/Layout',
258
+ meta: {
259
+ category: 'auth'
260
+ },
261
+ children: [
262
+ {
263
+ index: true,
264
+ element: 'auth/LoginPage'
265
+ },
266
+ {
267
+ path: 'login',
268
+ element: 'auth/LoginPage',
269
+ meta: {
270
+ title: identifier.PAGE_LOGIN_TITLE,
271
+ description: identifier.PAGE_LOGIN_DESCRIPTION,
272
+ icon: 'info',
273
+ localNamespace: 'common'
274
+ }
275
+ },
276
+ {
277
+ path: 'register',
278
+ element: 'auth/RegisterPage',
279
+ meta: {
280
+ title: identifier.PAGE_REGISTER_TITLE,
281
+ description: identifier.PAGE_REGISTER_DESCRIPTION,
282
+ icon: 'info',
283
+ localNamespace: 'common'
284
+ }
285
+ }
286
+ ]
287
+ },
288
+ {
289
+ path: '404',
290
+ element: '404',
291
+ meta: {
292
+ category: 'common',
293
+ title: identifier.PAGE_404_TITLE,
294
+ description: identifier.PAGE_404_DESCRIPTION,
295
+ localNamespace: 'common'
296
+ }
297
+ },
298
+ {
299
+ path: '500',
300
+ element: '500',
301
+ meta: {
302
+ category: 'common',
303
+ title: identifier.PAGE_500_TITLE,
304
+ description: identifier.PAGE_500_DESCRIPTION,
305
+ localNamespace: 'common'
306
+ }
307
+ },
308
+ {
309
+ path: '*',
310
+ element: '404',
311
+ meta: {
312
+ category: 'common',
313
+ title: identifier.PAGE_404_TITLE,
314
+ description: identifier.PAGE_404_DESCRIPTION,
315
+ localNamespace: 'common'
316
+ }
317
+ }
318
+ ];
@@ -16,7 +16,7 @@ export const overrideAntdThemeMode: ViteDeprecatedAntdOptions['mode'] =
16
16
  'noGlobals';
17
17
 
18
18
  /**
19
- * bootstrap ,not inject env
19
+ * 启动器环境变量注入黑名单
20
20
  */
21
21
  export const envBlackList = ['env', 'userNodeEnv'];
22
22
 
@@ -37,3 +37,11 @@ export const loggerStyles = {
37
37
  * - 但是不能只有 /
38
38
  */
39
39
  export const routerPrefix = '/router-root';
40
+
41
+ /**
42
+ * 是否使用本地化路由
43
+ *
44
+ * - true: 使用本地化路由,路由会带有语言前缀 (例如: /en/home)
45
+ * - false: 不使用本地化路由,直接使用路径 (例如: /home)
46
+ */
47
+ export const useLocaleRoutes = true;