16.1 Angular 소개 — 완전한 프레임워크, TypeScript 기반, 버전별 진화
Angular란 무엇인가?
Angular는 Google이 개발하고 유지보수하는 오픈소스 프론트엔드 프레임워크입니다. 단순한 라이브러리가 아닌, 대규모 웹 애플리케이션을 처음부터 끝까지 구축할 수 있는 완전한(full-featured) 프레임워크입니다.
2010년 Google이 출시한 AngularJS(Angular 1)는 선언적 UI 바인딩으로 큰 인기를 얻었습니다. 하지만 현대 웹 요구 사항을 따라가지 못해 2016년 Angular 2로 완전히 재작성되었습니다. Angular 2부터는 단순히 "Angular"라고 부릅니다.
Angular가 제공하는 것
| 기능 | 설명 |
|---|---|
| 컴포넌트 기반 UI | 재사용 가능한 UI 블록 |
| TypeScript 기본 | 정적 타입, IDE 지원 |
| 의존성 주입(DI) | 서비스 관리, 테스트 용이성 |
| Angular Router | SPA 라우팅 내장 |
| HttpClient | HTTP 통신 모듈 내장 |
| Forms | Template-driven / Reactive Forms |
| RxJS 통합 | 비동기 스트림 처리 |
| Angular CLI | 프로젝트 생성, 빌드, 테스트 자동화 |
| Signals | 새 반응형 상태 관리 (Angular 16+) |
React / Vue와의 비교
Angular를 처음 접하는 분들이 가장 궁금해하는 부분입니다.
| 항목 | Angular | React | Vue |
|---|---|---|---|
| 타입 | 완전한 프레임워크 | UI 라이브러리 | 프레임워크 |
| 언어 | TypeScript 기본 | JS / TS | JS / TS |
| 학습 곡선 | 높음 | 중간 | 낮음 |
| 번들 크기 | 중간~큼 | 작음 | 작음 |
| 상태 관리 | Signals, RxJS (내장) | 외부 라이브러리 필요 | Pinia (별도) |
| HTTP 통신 | HttpClient (내장) | 외부 라이브러리 | 외부 라이브러리 |
| 테스트 | Jasmine/Karma 내장 | Jest (별도 설정) | Vitest (별도) |
| 유지보수 | Meta | 커뮤니티 | |
| 적합 대상 | 엔터프라이즈, 대규모 팀 | 다양한 규모 | 중소 규모 |
핵심 차이: Angular는 "모든 것이 포함된 배터리 포함 패키지"입니다. React는 UI만 담당하고 나머지는 직접 선택해야 합니다.
TypeScript 기반의 강점
Angular는 TypeScript를 선택이 아닌 기본으로 채택합니다.
// TypeScript가 주는 이점: 컴파일 시점 오류 검출
interface User {
id: number;
name: string;
email: string;
}
// 타입 오류 즉시 감지
const user: User = {
id: 1,
name: 'Alice',
email: 'alice@example.com'
// phone: '010-...' // ❌ 컴파일 오류 — User 타입에 없는 프로퍼티
};
// 자동완성, 리팩토링 지원
function greetUser(u: User): string {
return `Hello, ${u.name}!`; // IDE가 u. 입력 시 id, name, email 자동완성
}
TypeScript를 쓰면:
- 버그를 런타임 전에 발견
- IDE 자동완성이 완벽하게 동작
- 대규모 팀에서 코드 의도가 명확해짐
- 리팩토링이 안전해짐
Angular 버전별 진화
AngularJS (2010) → "Angular 1"
- 양방향 데이터 바인딩으로 혁신
- 하지만 성능/구조 한계
Angular 2 (2016) → 완전 재작성
- TypeScript 기본
- 컴포넌트 기반 아키텍처
- RxJS 통합
Angular 4~13 (2017~2021) → 점진적 개선
- Ivy 렌더러 (Angular 9)
- Strict Mode 기본화
Angular 14 (2022) → Standalone 컴포넌트 (실험적)
- NgModule 없이 컴포넌트 단독 사용
- inject() 함수 도입
Angular 15 (2022) → Standalone 안정화
- Directive Composition API
Angular 16 (2023) → Signals 도입 (실험적)
- 새 반응형 상태 관리 시스템
- takeUntilDestroyed
Angular 17 (2023) → 현대 Angular
- 새 제어 흐름 문법 (@if, @for, @switch)
- Deferrable Views (@defer)
- Signals 안정화
- 새 공식 문서 (angular.dev)
Angular 18 (2024)
- Zoneless Change Detection (실험적)
- Material 3 완성
- Signal-based inputs 안정화
Angular 19 (2024)
- Incremental Hydration
- Route-level render mode
- Linked Signals
- Resource API (실험적)
핵심 아키텍처
Angular 애플리케이션은 여러 핵심 개념으로 구성됩니다.
Angular 앱
├── 컴포넌트 (Component) ← UI 단위
│ ├── 템플릿 (HTML)
│ ├── 클래스 (TypeScript)
│ └── 스타일 (CSS/SCSS)
│
├── 서비스 (Service) ← 비즈니스 로직, 데이터
│ └── @Injectable
│
├── 의존성 주입 (DI) ← 서비스 제공/소비
│
├── 라우터 (Router) ← URL ↔ 컴포넌트 매핑
│
└── 모듈 (NgModule) / Standalone
└── 컴포넌트 묶음 (Angular 17 이전 방식)
컴포넌트 — UI의 기본 단위
// app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root', // HTML에서 <app-root> 태그로 사용
standalone: true, // Angular 17+ 기본값
template: `
<h1>{{ title }}</h1>
<p>Angular {{ version }} 시작하기</p>
`,
styles: [`
h1 { color: #dd0031; } /* Angular 브랜드 컬러 */
`]
})
export class AppComponent {
title = 'My Angular App';
version = 19;
}
서비스 — 비즈니스 로직 분리
// user.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root' // 앱 전체에서 싱글톤으로 사용 가능
})
export class UserService {
private users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
getUsers() {
return this.users;
}
}
기본 코드 예제 — Hello Angular
// main.ts — 앱 부트스트랩
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent)
.catch(err => console.error(err));
// app/app.component.ts — 루트 컴포넌트
import { Component, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule],
template: `
<div class="container">
<h1>{{ title }}</h1>
<!-- Angular 17+ 새 제어 흐름 문법 -->
@if (isLoggedIn()) {
<p>안녕하세요, {{ userName() }}님!</p>
<button (click)="logout()">로그아웃</button>
} @else {
<button (click)="login()">로그인</button>
}
<h2>사용자 목록</h2>
<ul>
@for (user of users(); track user.id) {
<li>{{ user.name }} (ID: {{ user.id }})</li>
} @empty {
<li>사용자가 없습니다.</li>
}
</ul>
</div>
`
})
export class AppComponent {
title = 'Angular 19 데모';
// Signals — 새 반응형 상태 관리
isLoggedIn = signal(false);
userName = signal('');
users = signal([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' }
]);
login() {
this.isLoggedIn.set(true);
this.userName.set('Alice');
}
logout() {
this.isLoggedIn.set(false);
this.userName.set('');
}
}
실전 예제 — 미니 대시보드
실무에서 Angular를 어떻게 구성하는지 보여주는 간단한 대시보드 예제입니다.
// dashboard/dashboard.component.ts
import { Component, OnInit, inject } from '@angular/core';
import { AsyncPipe } from '@angular/common';
import { Observable } from 'rxjs';
import { DashboardService } from './dashboard.service';
interface Stats {
totalUsers: number;
activeUsers: number;
revenue: number;
}
@Component({
selector: 'app-dashboard',
standalone: true,
imports: [AsyncPipe],
template: `
<div class="dashboard">
<h1>대시보드</h1>
@if (stats$ | async; as stats) {
<div class="stats-grid">
<div class="stat-card">
<h3>전체 사용자</h3>
<span class="number">{{ stats.totalUsers | number }}</span>
</div>
<div class="stat-card">
<h3>활성 사용자</h3>
<span class="number">{{ stats.activeUsers | number }}</span>
</div>
<div class="stat-card">
<h3>매출</h3>
<span class="number">{{ stats.revenue | currency:'KRW' }}</span>
</div>
</div>
} @else {
<p>데이터 로딩 중...</p>
}
</div>
`
})
export class DashboardComponent implements OnInit {
// inject() 함수로 DI (Angular 14+ 권장 방식)
private dashboardService = inject(DashboardService);
stats$!: Observable<Stats>;
ngOnInit() {
this.stats$ = this.dashboardService.getStats();
}
}
// dashboard/dashboard.service.ts
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class DashboardService {
private http = inject(HttpClient);
getStats(): Observable<{ totalUsers: number; activeUsers: number; revenue: number }> {
// 실제 환경: return this.http.get('/api/stats');
// 예제용 모의 데이터
return of({
totalUsers: 12847,
activeUsers: 3421,
revenue: 45000000
}).pipe(delay(500)); // 네트워크 지연 시뮬레이션
}
}
Angular가 적합한 프로젝트
Angular는 다음과 같은 상황에서 빛을 발합니다:
적합한 경우
- 엔터프라이즈 애플리케이션: ERP, CRM, 관리자 대시보드
- 대규모 팀: 5명 이상, TypeScript + 강한 컨벤션 필요
- 장기 유지보수: 구글의 LTS 보장, 마이그레이션 도구 제공
- 전체 솔루션 필요: 라우팅, HTTP, 폼, 상태관리 모두 기본 포함
- 은행/금융 시스템: Google, YouTube, Wix 등 사용
주의가 필요한 경우
- 소규모 간단한 앱: 설정 오버헤드가 큼
- 초보자 첫 프레임워크: 학습 곡선이 높음
- 빠른 프로토타입: React/Vue가 더 빠름
고수 팁
팁 1: Angular DevTools 필수 설치
Chrome/Firefox에서 Angular DevTools 확장을 설치하면 컴포넌트 트리, 변경 감지, 프로파일링을 시각적으로 확인할 수 있습니다.
팁 2: 버전 이해하기
Angular는 6개월마다 주요 버전을 릴리스합니다. LTS(Long-Term Support)는 18개월 보장됩니다. ng update로 쉽게 마이그레이션 가능합니다.
# 마이그레이션 확인
ng update
# 특정 버전으로 업데이트
ng update @angular/core@19 @angular/cli@19
팁 3: angular.dev 공식 문서
2023년부터 공식 문서가 angular.dev로 이전되었습니다. 구 angular.io는 더 이상 업데이트되지 않습니다.
팁 4: Standalone 컴포넌트가 미래
Angular 17부터 ng new 기본값이 Standalone 컴포넌트입니다. NgModule 방식은 레거시로 간주됩니다. 새 프로젝트는 반드시 Standalone으로 시작하세요.
정리
| 개념 | 핵심 |
|---|---|
| Angular | Google의 완전한 TypeScript 프레임워크 |
| 버전 | 6개월 주기, 현재 Angular 19 |
| 아키텍처 | 컴포넌트 + 서비스 + DI + 라우터 |
| 최신 트렌드 | Standalone 컴포넌트, Signals, 새 제어 흐름 |
| 적합 | 엔터프라이즈, 대규모 팀, 장기 프로젝트 |
다음 챕터에서는 Angular CLI를 사용해 실제 프로젝트를 생성하고 구조를 탐색합니다.