프런트엔드 Angular 19: 복잡한 앱을 위한 현대 아키텍처
프런트엔드 이벤트를 플레이하세요 27개의 기능 모듈을 처리하는 Angular 19 애플리케이션을 지원합니다. 21개 언어로 구성되어 있으며 Univerjs, Konva, D3.js 및 MapLibre. 이 기사에서는 아키텍처 선택에 대해 살펴봅니다. 성능과 유지 관리성을 희생하지 않고도 이 모든 것이 가능해집니다.
이 기사에서 찾을 수 있는 내용
- NgModules가 없는 독립형 아키텍처
- Signals 및 BaseStore를 사용한 상태 관리
- Express를 사용한 서버 측 렌더링
- 27개의 지연 로드 모듈 및 반응형 디자인
- 고급 UI 라이브러리: Univerjs, Konva, D3.js, MapLibre, Chart.js
- HTTP 인터셉터, 프리미엄 가드 및 접근성
독립형 구성요소: 안녕 NgModules
전체 응용 프로그램이 사용합니다 독립형 구성 요소, NgModule을 완전히 제거합니다. 각 구성요소는 자체적으로 선언합니다. 데코레이터에 직접 종속성을 부여하여 코드를 더욱 명확하게 만듭니다. 더욱 효과적인 트리 쉐이킹이 가능합니다.
@Component({
selector: 'app-event-dashboard',
standalone: true,
imports: [
CommonModule,
TranslateModule,
ChartComponent,
ExpenseSummaryComponent,
GuestListComponent
],
templateUrl: './event-dashboard.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EventDashboardComponent {
private readonly store = inject(EventStore);
event = this.store.currentEvent;
guests = this.store.guests;
expenses = this.store.expenses;
isLoading = this.store.isLoading;
}
주요 장점과 명확성: 구성 요소를 보면 알 수 있습니다. 정확히 무엇에 달려 있는지. 양식을 탐색할 필요가 없습니다. 템플릿에서 사용 가능한 내용을 이해하기 위해 중첩되었습니다.
신호를 사용한 상태 관리: BaseStore 패턴
상태 관리를 위해 Play The Event는 패턴을 사용합니다. 기반으로 맞춤형 각도 신호. 그만큼 베이스스토어 모두에게 공통적인 기능을 제공합니다. 응용 프로그램 저장소.
export abstract class BaseStore<T> {
// Stato interno con signals
protected readonly _data = signal<T | null>(null);
protected readonly _isLoading = signal(false);
protected readonly _error = signal<string | null>(null);
protected readonly _lastFetch = signal<number>(0);
// Cache TTL configurabile (default: 5 minuti)
protected readonly cacheTTL = 5 * 60 * 1000;
// Selettori pubblici (readonly)
readonly data = this._data.asReadonly();
readonly isLoading = this._isLoading.asReadonly();
readonly error = this._error.asReadonly();
// Computed signals
readonly hasData = computed(() => this._data() !== null);
readonly isStale = computed(() => {
const elapsed = Date.now() - this._lastFetch();
return elapsed > this.cacheTTL;
});
// Fetch con cache intelligente
async loadIfNeeded(): Promise<void> {
if (this.hasData() && !this.isStale()) {
return; // Dati freschi in cache, skip
}
await this.forceLoad();
}
protected abstract fetchData(): Observable<T>;
}
NgRx가 아닌 BaseStore가 필요한 이유는 무엇입니까?
- 간단: NgRx에는 작업, 감소기, 효과 및 선택기가 필요합니다. BaseStore는 단일 파일입니다.
- 성능: 신호는 Angular의 기본 신호이며 OnPush 변경 감지에 최적화되어 있습니다.
- 통합 캐시: TTL은 추가 라이브러리 없이 중복되는 API 호출을 방지합니다.
- 유형: TypeScript 제네릭 덕분에 각 상점은 강력한 형식으로 지정됩니다.
Express를 사용한 서버 측 렌더링
SSR은 인지된 성능과 SEO에 매우 중요합니다. 이벤트를 플레이하세요 렌더링을 처리하는 Express 서버와 함께 Angular Universal을 사용합니다. 서버 측.
Express 서버는 렌더링에만 국한되지 않고 압축도 처리합니다. 지원을 위한 정적 페이지 캐싱 및 URL 재작성 다국어. 공개 페이지(랜딩, 가격, 블로그)가 사전 렌더링됩니다. 캐시되고, 인증된 페이지는 요청 시 렌더링됩니다.
27 지연 로드 모듈
신청은 다음과 같이 나누어집니다. 27개의 기능 모듈, 각각 지연 로딩을 통해 요청 시 로드됩니다. 이는 사용자가 방문 중인 페이지에 필요한 코드만 다운로드합니다.
export const routes: Routes = [
{
path: 'events',
loadComponent: () =>
import('./features/events/event-list.component')
.then(m => m.EventListComponent),
canActivate: [authGuard]
},
{
path: 'events/:id/expenses',
loadComponent: () =>
import('./features/expenses/expense-dashboard.component')
.then(m => m.ExpenseDashboardComponent),
canActivate: [authGuard, premiumGuard('PRO')]
},
{
path: 'events/:id/seating',
loadComponent: () =>
import('./features/seating/seating-chart.component')
.then(m => m.SeatingChartComponent),
canActivate: [authGuard, premiumGuard('ENTERPRISE')]
},
// ... altri 24 moduli
];
반응형 디자인: 모바일 우선
인터페이스는 신중하게 설계되었습니다. 모바일 우선 세 가지 주요 중단점을 사용합니다.
/* Breakpoint */
--breakpoint-mobile: 320px; /* Smartphone */
--breakpoint-tablet: 768px; /* Tablet */
--breakpoint-desktop: 1024px; /* Desktop */
/* Typography: Montserrat + Lato */
--font-heading: 'Montserrat', sans-serif;
--font-body: 'Lato', sans-serif;
/* Layout responsive */
.event-grid {
display: grid;
grid-template-columns: 1fr; /* Mobile: 1 colonna */
}
@media (min-width: 768px) {
.event-grid {
grid-template-columns: repeat(2, 1fr); /* Tablet: 2 colonne */
}
}
@media (min-width: 1024px) {
.event-grid {
grid-template-columns: repeat(3, 1fr); /* Desktop: 3 colonne */
}
}
TranslateService를 통한 21개 언어
국제화는 다음을 통해 관리됩니다. 번역서비스 21개 언어를 지원하는 맞춤형. 번역 파일은 JSON입니다. 기능적 모듈로 구성되어 있으며 필요에 따라 로드됩니다. 해당 양식.
21개 언어로 진행되는 i18n 챌린지
21개 언어를 관리한다는 것은 단순히 문자열을 번역하는 것이 아닙니다. 그것은 고려되어야 한다 텍스트 방향(아랍어의 경우 LTR/RTL), 날짜 형식 및 현지 통화, 복수형(언어마다 크게 다름), 레이아웃에 영향을 미치는 텍스트의 가변 길이.
고급 UI 라이브러리
Play The Event는 5개의 특수 UI 라이브러리를 통합합니다. 특정 사용 사례.
통합 라이브러리
- 대학교: 공동 예산 및 스프레드시트를 위한 브라우저의 스프레드시트
- 콘바: 평면도 및 테이블 레이아웃 편집기를 위한 2D 캔버스
- D3.js: 참가자 관계 그래프 및 복잡한 데이터 시각화
- 맵리브레 GL: 여행 일정 및 장소 위치에 대한 대화형 지도
- 차트.js: 분석, 통계 대시보드 및 재무 보고서용 차트
HTTP 인터셉터
두 개의 HTTP 인터셉터가 전반적으로 API 호출을 처리합니다.
토큰 새로 고침이 포함된 인증 인터셉터
인증 인터셉터는 각 요청에 JWT 토큰을 자동으로 추가합니다. 토큰이 만료되면(401 응답) 인터셉터는 자동 새로고침 새로 고침 토큰을 사용하여 새 토큰을 사용한 원래 요청 및 새로 고침도 실패하는 경우 로그인 페이지로 리디렉션됩니다.
오류 인터셉터
오류 인터셉터는 HTTP 오류 처리를 중앙 집중화합니다. 클라이언트 오류(4xx)에 대한 토스트 알림, 오류에 대한 오류 페이지 서버(5xx) 및 디버깅을 위한 오류를 기록합니다.
프리미엄 기능 가드
일부 기능은 구독 사용자에게만 제공됩니다. 프로 또는 엔터프라이즈. 그만큼 바라보다 수준을 확인하다 경로에 대한 액세스를 허용하기 전에 구독하십시오.
export function premiumGuard(requiredLevel: 'PRO' | 'ENTERPRISE') {
return () => {
const auth = inject(AuthStore);
const router = inject(Router);
const userLevel = auth.subscriptionLevel();
const levels = { 'BASIC': 0, 'PRO': 1, 'ENTERPRISE': 2 };
if (levels[userLevel] >= levels[requiredLevel]) {
return true;
}
return router.createUrlTree(['/pricing'], {
queryParams: { upgrade: requiredLevel }
});
};
}
WCAG 2.1 AA 접근성
접근성은 늦게 추가되는 것이 아니라 프로세스에 통합되어 있습니다. 개발의. 각 구성 요소는 WCAG 2.1 AA 준수 여부를 테스트했습니다.
접근성 관행
- 최소 색상 대비 일반 텍스트의 경우 4.5:1, 큰 텍스트의 경우 3:1
- 초점이 보이는 전체 키보드 탐색
- 사용자 정의 대화형 구성요소에 대한 ARIA 속성
- 동적 주식에 대한 스크린 리더 광고
- 지원하다
prefers-reduced-motion애니메이션을 줄이기 위해 - 자동화된 테스트 도끼 코어 CI 파이프라인에서
테스트: Jest, Playwright 및 axe-core
테스트 전략은 세 가지 수준으로 구분됩니다.
단위 및 구성 요소 테스트
- 농담: 서비스, 파이프 및 비즈니스 로직에 대한 단위 테스트
- Angular 구성 요소용 TestBed를 사용한 구성 요소 테스트
- 격리된 테스트를 위한 모의 HTTP 서비스
E2E 및 접근성
- 극작가: 엔드 투 엔드 크로스 브라우저 테스트(Chrome, Firefox, Safari)
- 도끼 코어: E2E 테스트에 통합된 자동 접근성 테스트
- 중요 구성 요소에 대한 시각적 회귀 테스트
핵심 사항
- 최대의 명확성과 효과적인 트리 쉐이킹을 위한 독립형 구성 요소
- 응답성 및 성능 상태를 위한 신호 및 TTL 캐시가 포함된 BaseStore
- SEO를 위한 Express가 포함된 SSR 및 인지된 성능
- 최적의 번들 크기를 위한 27개의 지연 로드 모듈
- 5개의 특화된 UI 라이브러리가 조화롭게 통합됨
- 자동 인증 및 중앙 집중식 오류 처리를 위한 HTTP 인터셉터
- 세 가지 수준에서 테스트: 단위, E2E 및 접근성
프론트엔드 소스코드는 다음에서 구할 수 있습니다. GitHub. 방문하다 www.playtheevent.com 최종 결과를 보려면.







