@qlover/create-app 0.6.2 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/react-app/README.en.md +257 -0
- package/dist/templates/react-app/README.md +29 -231
- package/dist/templates/react-app/docs/en/bootstrap.md +562 -0
- package/dist/templates/react-app/docs/en/development-guide.md +523 -0
- package/dist/templates/react-app/docs/en/env.md +482 -0
- package/dist/templates/react-app/docs/en/global.md +509 -0
- package/dist/templates/react-app/docs/en/i18n.md +268 -0
- package/dist/templates/react-app/docs/en/index.md +173 -0
- package/dist/templates/react-app/docs/en/ioc.md +424 -0
- package/dist/templates/react-app/docs/en/project-structure.md +434 -0
- package/dist/templates/react-app/docs/en/request.md +425 -0
- package/dist/templates/react-app/docs/en/router.md +404 -0
- package/dist/templates/react-app/docs/en/store.md +321 -0
- package/dist/templates/react-app/docs/en/theme.md +424 -0
- package/dist/templates/react-app/docs/en/typescript-guide.md +473 -0
- package/dist/templates/react-app/docs/zh/bootstrap.md +7 -0
- package/dist/templates/react-app/docs/zh/development-guide.md +523 -0
- package/dist/templates/react-app/docs/zh/env.md +24 -25
- package/dist/templates/react-app/docs/zh/global.md +28 -27
- package/dist/templates/react-app/docs/zh/i18n.md +268 -0
- package/dist/templates/react-app/docs/zh/index.md +173 -0
- package/dist/templates/react-app/docs/zh/ioc.md +44 -32
- package/dist/templates/react-app/docs/zh/project-structure.md +434 -0
- package/dist/templates/react-app/docs/zh/request.md +429 -0
- package/dist/templates/react-app/docs/zh/router.md +408 -0
- package/dist/templates/react-app/docs/zh/store.md +321 -0
- package/dist/templates/react-app/docs/zh/theme.md +424 -0
- package/dist/templates/react-app/docs/zh/typescript-guide.md +473 -0
- package/dist/templates/react-app/package.json +1 -1
- package/dist/templates/react-app/src/styles/css/antd-themes/dark.css +3 -1
- package/dist/templates/react-app/src/styles/css/antd-themes/index.css +1 -1
- package/dist/templates/react-app/src/styles/css/antd-themes/pink.css +6 -1
- package/dist/templates/react-app/src/styles/css/page.css +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
# TypeScript Development Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This guide introduces TypeScript usage standards in the project, emphasizing three programming paradigms:
|
|
6
|
+
|
|
7
|
+
- Object-Oriented Programming (OOP)
|
|
8
|
+
- Interface-based Programming
|
|
9
|
+
- Configuration-based Programming
|
|
10
|
+
|
|
11
|
+
## Programming Paradigms
|
|
12
|
+
|
|
13
|
+
### 1. Object-Oriented Programming (OOP)
|
|
14
|
+
|
|
15
|
+
In the project, we extensively use object-oriented concepts to organize code, primarily manifested in:
|
|
16
|
+
|
|
17
|
+
#### Class Design
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// Base class design
|
|
21
|
+
abstract class StoreInterface<T extends StoreStateInterface> {
|
|
22
|
+
protected state: T;
|
|
23
|
+
|
|
24
|
+
constructor(initialState: T) {
|
|
25
|
+
this.state = initialState;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
abstract setState(state: Partial<T>): void;
|
|
29
|
+
|
|
30
|
+
getState(): T {
|
|
31
|
+
return this.state;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Concrete implementation
|
|
36
|
+
@injectable()
|
|
37
|
+
class UserStore extends StoreInterface<UserState> {
|
|
38
|
+
constructor() {
|
|
39
|
+
super({
|
|
40
|
+
user: null,
|
|
41
|
+
loading: false
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
setState(state: Partial<UserState>): void {
|
|
46
|
+
this.state = { ...this.state, ...state };
|
|
47
|
+
this.notify();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private notify(): void {
|
|
51
|
+
// Notify observers
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### Inheritance and Polymorphism
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// Base service interface
|
|
60
|
+
interface ServiceInterface {
|
|
61
|
+
initialize(): Promise<void>;
|
|
62
|
+
destroy(): void;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Abstract base class
|
|
66
|
+
abstract class BaseService implements ServiceInterface {
|
|
67
|
+
abstract initialize(): Promise<void>;
|
|
68
|
+
|
|
69
|
+
destroy(): void {
|
|
70
|
+
// Common cleanup logic
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Concrete service implementation
|
|
75
|
+
class UserService extends BaseService {
|
|
76
|
+
async initialize(): Promise<void> {
|
|
77
|
+
// User service initialization logic
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Extended specific methods
|
|
81
|
+
async login(): Promise<void> {
|
|
82
|
+
// Login logic
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 2. Interface-based Programming
|
|
88
|
+
|
|
89
|
+
The project emphasizes using interfaces to define contracts, achieving loose coupling:
|
|
90
|
+
|
|
91
|
+
#### Interface Definition
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// Define interface contract
|
|
95
|
+
interface StorageInterface<T> {
|
|
96
|
+
get(key: string): T | null;
|
|
97
|
+
set(key: string, value: T): void;
|
|
98
|
+
remove(key: string): void;
|
|
99
|
+
clear(): void;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Interface implementation
|
|
103
|
+
class LocalStorage<T> implements StorageInterface<T> {
|
|
104
|
+
get(key: string): T | null {
|
|
105
|
+
const value = localStorage.getItem(key);
|
|
106
|
+
return value ? JSON.parse(value) : null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
set(key: string, value: T): void {
|
|
110
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
remove(key: string): void {
|
|
114
|
+
localStorage.removeItem(key);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
clear(): void {
|
|
118
|
+
localStorage.clear();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### Dependency Injection
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
// Service interface
|
|
127
|
+
interface UserServiceInterface {
|
|
128
|
+
getCurrentUser(): User | null;
|
|
129
|
+
updateProfile(data: UserProfile): Promise<void>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Service implementation
|
|
133
|
+
@injectable()
|
|
134
|
+
class UserService implements UserServiceInterface {
|
|
135
|
+
constructor(
|
|
136
|
+
@inject('StorageService') private storage: StorageInterface<User>,
|
|
137
|
+
@inject('ApiService') private api: ApiInterface
|
|
138
|
+
) {}
|
|
139
|
+
|
|
140
|
+
getCurrentUser(): User | null {
|
|
141
|
+
return this.storage.get('currentUser');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async updateProfile(data: UserProfile): Promise<void> {
|
|
145
|
+
await this.api.put('/user/profile', data);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 3. Configuration-based Programming
|
|
151
|
+
|
|
152
|
+
The project adopts a configuration-driven approach to manage features:
|
|
153
|
+
|
|
154
|
+
#### Configuration Definition
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// Configuration interface
|
|
158
|
+
interface AppConfig {
|
|
159
|
+
api: {
|
|
160
|
+
baseUrl: string;
|
|
161
|
+
timeout: number;
|
|
162
|
+
retries: number;
|
|
163
|
+
};
|
|
164
|
+
auth: {
|
|
165
|
+
tokenKey: string;
|
|
166
|
+
tokenPrefix: string;
|
|
167
|
+
expiresIn: number;
|
|
168
|
+
};
|
|
169
|
+
theme: {
|
|
170
|
+
defaultTheme: 'light' | 'dark';
|
|
171
|
+
enableUserTheme: boolean;
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Configuration implementation
|
|
176
|
+
const appConfig: AppConfig = {
|
|
177
|
+
api: {
|
|
178
|
+
baseUrl: process.env.API_BASE_URL || '/api',
|
|
179
|
+
timeout: 5000,
|
|
180
|
+
retries: 3
|
|
181
|
+
},
|
|
182
|
+
auth: {
|
|
183
|
+
tokenKey: 'auth_token',
|
|
184
|
+
tokenPrefix: 'Bearer',
|
|
185
|
+
expiresIn: 7200
|
|
186
|
+
},
|
|
187
|
+
theme: {
|
|
188
|
+
defaultTheme: 'light',
|
|
189
|
+
enableUserTheme: true
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### Configuration-driven
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
// Configuration-driven feature implementation
|
|
198
|
+
@injectable()
|
|
199
|
+
class ApiService {
|
|
200
|
+
constructor(
|
|
201
|
+
@inject('AppConfig') private config: AppConfig,
|
|
202
|
+
@inject('HttpClient') private http: HttpClient
|
|
203
|
+
) {
|
|
204
|
+
// Initialize service using configuration
|
|
205
|
+
this.http.setBaseUrl(config.api.baseUrl);
|
|
206
|
+
this.http.setTimeout(config.api.timeout);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async request<T>(options: RequestOptions): Promise<T> {
|
|
210
|
+
let retries = this.config.api.retries;
|
|
211
|
+
|
|
212
|
+
while (retries > 0) {
|
|
213
|
+
try {
|
|
214
|
+
return await this.http.request(options);
|
|
215
|
+
} catch (error) {
|
|
216
|
+
retries--;
|
|
217
|
+
if (retries === 0) throw error;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Type System Usage
|
|
225
|
+
|
|
226
|
+
### 1. Generics
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
// Generic interface
|
|
230
|
+
interface Repository<T> {
|
|
231
|
+
findById(id: string): Promise<T>;
|
|
232
|
+
findAll(): Promise<T[]>;
|
|
233
|
+
create(data: Omit<T, 'id'>): Promise<T>;
|
|
234
|
+
update(id: string, data: Partial<T>): Promise<T>;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Generic class
|
|
238
|
+
class ApiRepository<T> implements Repository<T> {
|
|
239
|
+
constructor(private endpoint: string) {}
|
|
240
|
+
|
|
241
|
+
async findById(id: string): Promise<T> {
|
|
242
|
+
return api.get(`${this.endpoint}/${id}`);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ... other method implementations
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### 2. Type Utilities
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
// Type mapping
|
|
253
|
+
type Nullable<T> = { [P in keyof T]: T[P] | null };
|
|
254
|
+
|
|
255
|
+
// Conditional types
|
|
256
|
+
type ArrayType<T> = T extends Array<infer U> ? U : never;
|
|
257
|
+
|
|
258
|
+
// Utility types
|
|
259
|
+
type PartialDeep<T> = {
|
|
260
|
+
[P in keyof T]?: T[P] extends object ? PartialDeep<T[P]> : T[P];
|
|
261
|
+
};
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### 3. Decorators
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
// Method decorator
|
|
268
|
+
function Cached(ttl: number = 3600) {
|
|
269
|
+
return function (
|
|
270
|
+
target: any,
|
|
271
|
+
propertyKey: string,
|
|
272
|
+
descriptor: PropertyDescriptor
|
|
273
|
+
) {
|
|
274
|
+
const original = descriptor.value;
|
|
275
|
+
const cache = new Map();
|
|
276
|
+
|
|
277
|
+
descriptor.value = async function (...args: any[]) {
|
|
278
|
+
const key = JSON.stringify(args);
|
|
279
|
+
if (cache.has(key)) {
|
|
280
|
+
const { value, timestamp } = cache.get(key);
|
|
281
|
+
if (Date.now() - timestamp < ttl * 1000) {
|
|
282
|
+
return value;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const result = await original.apply(this, args);
|
|
287
|
+
cache.set(key, { value: result, timestamp: Date.now() });
|
|
288
|
+
return result;
|
|
289
|
+
};
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Using decorator
|
|
294
|
+
class UserService {
|
|
295
|
+
@Cached(1800)
|
|
296
|
+
async getUserProfile(id: string): Promise<UserProfile> {
|
|
297
|
+
return this.api.get(`/users/${id}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Best Practices
|
|
303
|
+
|
|
304
|
+
### 1. Type Definitions
|
|
305
|
+
|
|
306
|
+
- Use interface for object structures
|
|
307
|
+
- Use type for union types and utility types
|
|
308
|
+
- Prefer readonly to ensure immutability
|
|
309
|
+
- Use optional properties judiciously
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
// Good practices
|
|
313
|
+
interface UserProfile {
|
|
314
|
+
readonly id: string;
|
|
315
|
+
name: string;
|
|
316
|
+
email: string;
|
|
317
|
+
avatar?: string;
|
|
318
|
+
preferences: Readonly<UserPreferences>;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Practices to avoid
|
|
322
|
+
interface BadUserProfile {
|
|
323
|
+
[key: string]: any; // Avoid using index signatures
|
|
324
|
+
data: any; // Avoid using any
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### 2. Error Handling
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
// Custom error class
|
|
332
|
+
class ApiError extends Error {
|
|
333
|
+
constructor(
|
|
334
|
+
public code: string,
|
|
335
|
+
message: string,
|
|
336
|
+
public data?: any
|
|
337
|
+
) {
|
|
338
|
+
super(message);
|
|
339
|
+
this.name = 'ApiError';
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Type guard
|
|
344
|
+
function isApiError(error: unknown): error is ApiError {
|
|
345
|
+
return error instanceof ApiError;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Error handling
|
|
349
|
+
try {
|
|
350
|
+
await api.request();
|
|
351
|
+
} catch (error) {
|
|
352
|
+
if (isApiError(error)) {
|
|
353
|
+
handleApiError(error);
|
|
354
|
+
} else {
|
|
355
|
+
handleUnknownError(error);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### 3. Asynchronous Handling
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
// Async result type
|
|
364
|
+
interface AsyncResult<T, E = Error> {
|
|
365
|
+
data: T | null;
|
|
366
|
+
error: E | null;
|
|
367
|
+
loading: boolean;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Async operation wrapper
|
|
371
|
+
async function asyncWrapper<T, E = Error>(
|
|
372
|
+
promise: Promise<T>
|
|
373
|
+
): Promise<AsyncResult<T, E>> {
|
|
374
|
+
try {
|
|
375
|
+
const data = await promise;
|
|
376
|
+
return { data, error: null, loading: false };
|
|
377
|
+
} catch (error) {
|
|
378
|
+
return { data: null, error: error as E, loading: false };
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Development Tools Configuration
|
|
384
|
+
|
|
385
|
+
### 1. TSConfig Configuration
|
|
386
|
+
|
|
387
|
+
```json
|
|
388
|
+
{
|
|
389
|
+
"compilerOptions": {
|
|
390
|
+
"target": "ES2020",
|
|
391
|
+
"module": "ESNext",
|
|
392
|
+
"strict": true,
|
|
393
|
+
"esModuleInterop": true,
|
|
394
|
+
"skipLibCheck": true,
|
|
395
|
+
"forceConsistentCasingInFileNames": true,
|
|
396
|
+
"experimentalDecorators": true,
|
|
397
|
+
"emitDecoratorMetadata": true
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### 2. ESLint Configuration
|
|
403
|
+
|
|
404
|
+
```json
|
|
405
|
+
{
|
|
406
|
+
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
|
407
|
+
"rules": {
|
|
408
|
+
"@typescript-eslint/explicit-function-return-type": "error",
|
|
409
|
+
"@typescript-eslint/no-explicit-any": "error",
|
|
410
|
+
"@typescript-eslint/no-unused-vars": "error"
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Debugging Techniques
|
|
416
|
+
|
|
417
|
+
### 1. Type Assertions
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
// Type assertion
|
|
421
|
+
function processValue(value: unknown) {
|
|
422
|
+
if (typeof value === 'string') {
|
|
423
|
+
return value.toUpperCase();
|
|
424
|
+
}
|
|
425
|
+
return String(value);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Type narrowing
|
|
429
|
+
function isString(value: unknown): value is string {
|
|
430
|
+
return typeof value === 'string';
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### 2. Debugging Tools
|
|
435
|
+
|
|
436
|
+
```typescript
|
|
437
|
+
// Type checking
|
|
438
|
+
type Debug<T> = {
|
|
439
|
+
[P in keyof T]: T[P];
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
// Runtime type checking
|
|
443
|
+
function assertType<T>(value: unknown, message?: string): asserts value is T {
|
|
444
|
+
if (!isValidType<T>(value)) {
|
|
445
|
+
throw new TypeError(message || 'Type assertion failed');
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
## Performance Optimization
|
|
451
|
+
|
|
452
|
+
### 1. Type Optimization
|
|
453
|
+
|
|
454
|
+
```typescript
|
|
455
|
+
// Use type caching
|
|
456
|
+
type CachedType<T> = T extends Function ? T : Readonly<T>;
|
|
457
|
+
|
|
458
|
+
// Avoid excessive use of generics
|
|
459
|
+
type SimpleType = string | number;
|
|
460
|
+
type ComplexType<T> = T extends SimpleType ? T : never;
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### 2. Compilation Optimization
|
|
464
|
+
|
|
465
|
+
- Use project references
|
|
466
|
+
- Enable incremental compilation
|
|
467
|
+
- Optimize type imports
|
|
468
|
+
|
|
469
|
+
## Reference Resources
|
|
470
|
+
|
|
471
|
+
- [TypeScript Official Documentation](https://www.typescriptlang.org/docs/)
|
|
472
|
+
- [TypeScript Design Patterns](https://refactoring.guru/design-patterns/typescript)
|
|
473
|
+
- [Clean Code TypeScript](https://github.com/labs42io/clean-code-typescript)
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
Bootstrap 是一个应用启动器,它帮助我们在应用启动时统一管理各种初始化逻辑。
|
|
6
6
|
|
|
7
7
|
**简单来说**:就像电脑开机时需要启动各种服务一样,我们的应用也需要在启动时做一些准备工作,比如:
|
|
8
|
+
|
|
8
9
|
- 检查用户是否登录
|
|
9
10
|
- 加载用户信息
|
|
10
11
|
- 初始化 API 配置
|
|
@@ -19,6 +20,7 @@ Bootstrap 是一个应用启动器,它帮助我们在应用启动时统一管
|
|
|
19
20
|
**文件入口**:`src/core/bootstraps/BootstrapApp.ts`
|
|
20
21
|
|
|
21
22
|
**主要组成部分**:
|
|
23
|
+
|
|
22
24
|
1. [IOC 容器](./ioc.md) - 依赖注入管理
|
|
23
25
|
2. [环境变量的注入](./env.md) - 配置管理
|
|
24
26
|
3. [浏览器全局变量的注入](./global.md) - 浏览器全局属性
|
|
@@ -209,6 +211,7 @@ await bootstrap.start();
|
|
|
209
211
|
```
|
|
210
212
|
|
|
211
213
|
**对比结果**:
|
|
214
|
+
|
|
212
215
|
- ✅ 组件变得简洁,只负责渲染
|
|
213
216
|
- ✅ 业务逻辑被分离到启动器中
|
|
214
217
|
- ✅ 可以独立测试业务逻辑
|
|
@@ -293,6 +296,7 @@ await bootstrap.start();
|
|
|
293
296
|
```
|
|
294
297
|
|
|
295
298
|
**关键点**:
|
|
299
|
+
|
|
296
300
|
- `UserApiBootstarp`:负责配置 API 请求
|
|
297
301
|
- `UserService`:负责处理用户认证逻辑
|
|
298
302
|
- `Bootstrap`:统一管理所有插件
|
|
@@ -358,6 +362,7 @@ bootstrap.use([
|
|
|
358
362
|
如果你想要快速体验 Bootstrap,可以按照以下步骤:
|
|
359
363
|
|
|
360
364
|
#### 步骤 1:创建简单的插件
|
|
365
|
+
|
|
361
366
|
```tsx
|
|
362
367
|
// 创建一个简单的插件
|
|
363
368
|
export class SimplePlugin implements BootstrapExecutorPlugin {
|
|
@@ -370,6 +375,7 @@ export class SimplePlugin implements BootstrapExecutorPlugin {
|
|
|
370
375
|
```
|
|
371
376
|
|
|
372
377
|
#### 步骤 2:在启动器中注册
|
|
378
|
+
|
|
373
379
|
```tsx
|
|
374
380
|
const bootstrap = new Bootstrap({
|
|
375
381
|
root: window,
|
|
@@ -386,6 +392,7 @@ await bootstrap.start();
|
|
|
386
392
|
```
|
|
387
393
|
|
|
388
394
|
#### 步骤 3:查看效果
|
|
395
|
+
|
|
389
396
|
打开浏览器控制台,你会看到 "SimplePlugin 启动成功!" 的日志。
|
|
390
397
|
|
|
391
398
|
**提示**:这个简单的例子展示了 Bootstrap 的基本用法。随着你对项目的了解,可以逐步添加更复杂的业务逻辑。
|