遵循最佳实践是构建高质量、可维护、高性能Angular应用的关键。本章总结了从项目结构到部署维护的全方位最佳实践。
按功能而非技术角色组织代码,提高可维护性和可测试性。
# 推荐的项目结构
src/
├── app/
│ ├── core/ # 核心模块(单例服务)
│ │ ├── services/
│ │ ├── guards/
│ │ ├── interceptors/
│ │ └── core.module.ts
│ ├── shared/ # 共享模块
│ │ ├── components/
│ │ ├── directives/
│ │ ├── pipes/
│ │ └── shared.module.ts
│ ├── features/ # 功能模块
│ │ ├── auth/
│ │ ├── dashboard/
│ │ ├── products/
│ │ └── orders/
│ ├── app-routing.module.ts
│ └── app.module.ts
├── assets/
├── environments/
└── styles/
// 过于庞大、承担过多责任的组件
@Component({
selector: 'app-megacomponent',
template: `
<!-- 500+行模板代码 -->
<div>用户管理</div>
<div>订单处理</div>
<div>报表展示</div>
<!-- 更多业务逻辑... -->
`
})
export class Megacomponent {
// 1000+行业务逻辑
// 混合了UI逻辑、业务逻辑、数据获取
// 难以测试和维护
}
// 单一职责的组件
@Component({
selector: 'app-user-profile',
template: `
<div class="user-profile">
<app-user-avatar [user]="user"></app-user-avatar>
<app-user-info [user]="user"></app-user-info>
<app-user-actions
[user]="user"
(save)="onSave($event)"
(delete)="onDelete($event)">
</app-user-actions>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserProfileComponent {
@Input() user!: User;
@Output() updated = new EventEmitter<User>();
// 组件只处理UI逻辑
onSave(user: User) {
this.updated.emit(user);
}
onDelete(userId: string) {
// 委托给服务处理
this.userService.delete(userId);
}
}
每个服务应专注于单一业务领域或技术功能。
// 推荐的服务设计
@Injectable({
providedIn: 'root' // 根注入器,单例
})
export class UserService {
constructor(
private http: HttpClient,
private logger: LoggerService,
private cache: CacheService
) {}
// 专注于用户相关的业务逻辑
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users').pipe(
tap(users => this.logger.log(`获取${users.length}个用户`)),
catchError(this.handleError)
);
}
// 错误处理集中化
private handleError(error: HttpErrorResponse) {
this.logger.error('用户服务错误:', error);
return throwError(() => new Error('获取用户失败'));
}
}
// 另一个专注授权的服务
@Injectable({ providedIn: 'root' })
export class AuthService {
// 专注于认证授权逻辑
}
providedIn: 'root'创建单例服务@Optional()标记可选依赖@Inject()注入非类依赖小型应用:使用服务 + RxJS BehaviorSubject
中型应用:使用NgRx Component Store
大型应用:使用NgRx Store + Effects
// 使用BehaviorSubject实现简单状态管理
@Injectable({ providedIn: 'root' })
export class UserStateService {
private usersSubject = new BehaviorSubject<User[]>([]);
private loadingSubject = new BehaviorSubject<boolean>(false);
// 只读状态流
users$ = this.usersSubject.asObservable();
loading$ = this.loadingSubject.asObservable();
// 派生状态
activeUsers$ = this.users$.pipe(
map(users => users.filter(user => user.active))
);
// 动作方法
loadUsers() {
this.loadingSubject.next(true);
this.userService.getUsers().subscribe({
next: users => {
this.usersSubject.next(users);
this.loadingSubject.next(false);
},
error: error => {
this.loadingSubject.next(false);
this.errorHandler.handle(error);
}
});
}
// 不可变更新
addUser(user: User) {
const currentUsers = this.usersSubject.value;
this.usersSubject.next([...currentUsers, user]);
}
}
使用DevTools分析性能
应用优化策略
验证优化成果
建立性能基线
any类型// 类型松散
function processData(data: any) {
// 大量类型断言
const result = (data as any).items.map((item: any) => {
// 业务逻辑...
});
return result;
}
// 魔法字符串和数字
if (status === 'ACTIVE') {
// 业务逻辑...
}
// 过于复杂的函数
function doEverything() {
// 100+行混合逻辑
}
// 严格类型定义
export interface User {
id: string;
name: string;
email: string;
status: UserStatus;
}
export enum UserStatus {
Active = 'ACTIVE',
Inactive = 'INACTIVE',
Pending = 'PENDING'
}
// 函数单一职责
function processUserData(users: User[]): ProcessedUser[] {
return users.map(processSingleUser);
}
function processSingleUser(user: User): ProcessedUser {
// 明确的业务逻辑
return {
...user,
isActive: user.status === UserStatus.Active
};
}
// 使用类型守卫
function isActiveUser(user: User): user is ActiveUser {
return user.status === UserStatus.Active;
}
大量、快速、独立
70%验证组件协作
20%完整用户流程
10%// 直接插入HTML,可能导致XSS
@Component({
template: `<div [innerHTML]="userContent"></div>`
})
export class UnsafeComponent {
userContent = '<script>恶意代码</script>';
}
// 未经验证的输入
updateUser(data: any) {
// 直接使用用户输入
this.http.post('/api/users', data);
}
// 使用DomSanitizer
@Component({
template: `<div [innerHTML]="safeContent"></div>`
})
export class SafeComponent {
constructor(private sanitizer: DomSanitizer) {}
get safeContent() {
return this.sanitizer.bypassSecurityTrustHtml(this.userContent);
}
}
// 输入验证和类型安全
interface UserData {
id: string;
name: string;
email: string;
}
updateUser(data: UserData) {
// 类型安全,编译器会检查
this.http.post<UserData>('/api/users', data);
}
// 使用HTTP拦截器添加安全头
@Injectable()
export class SecurityInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler) {
const secureReq = req.clone({
headers: req.headers.set('X-Requested-With', 'XMLHttpRequest')
});
return next.handle(secureReq);
}
}
# 推荐的分支策略
feature/ # 新功能开发
bugfix/ # 缺陷修复
hotfix/ # 紧急修复
release/ # 发布准备
main # 生产代码(受保护)
遵循最佳实践不是一蹴而就的,而是一个持续改进的过程。从简单的规范开始,逐步建立完整的开发流程和标准。
记住:最好的实践是那些适合你团队和项目的实践。保持灵活,持续学习,不断改进。