Angular 20 to 21 업그레이드: 실용적인 생존 가이드
Source: Dev.to
Introduction
Angular 20에서 21로 업그레이드하는 명확하고 간결한 가이드입니다. Karma 제거, 새로운 기본 Zoneless 모드, 자동 HttpClient 제공, 빌드 깨짐 현상 해결 방법 등 핵심 사항을 다룹니다.
Angular 20이 큰 변화를 가져왔다면, Angular 21은 그보다 더 큰 변화를 의미합니다. 20버전이 Signals 안정화에 집중했다면, 21버전은 기존 가드를 완전히 없앱니다. “Angular Way”가 근본적으로 바뀌었습니다: zone.js가 선택 사항이 되고, Karma는 사라지며, RxJS는 점차 가장자리로 물러납니다. 이것은 단순한 업데이트가 아니라 새로운 생태계입니다. 아래에서 깨질 부분과 해결 방법을 확인하세요.
Testing Changes: Karma → Vitest
What breaks
- 커스텀
karma.conf.js파일이나 특정 Karma 플러그인/리포터에 의존하는 경우 실패합니다. HttpClient가 없음을 모킹한 테스트도 깨질 수 있습니다 (HttpClient 섹션 참고).
The Fix
-
새 프로젝트: Vitest가 기본 제공됩니다. 더 빠르고 깔끔하며 Vite를 사용합니다.
-
기존 프로젝트: 당분간 Karma를 계속 사용할 수 있지만, CLI가 경고를 표시합니다.
-
마이그레이션: 스키마틱을 실행하세요
ng generate @angular/core:karma-to-vitest표준 설정을 자동으로 변환합니다. 테스트 설정에 있는 커스텀 Webpack 해킹은 Vite에 맞게 수동으로 다시 작성해야 합니다.
HttpClient Changes
The Change
HttpClient가 이제 루트 인젝터에 기본으로 주입됩니다. app.config.ts에 provideHttpClient()를 추가하거나 HttpClientModule을 임포트할 필요가 없으며, 별도의 설정이 필요할 때만 추가하면 됩니다.
What breaks
HttpClient가 존재하지 않기를 기대하는 테스트가 실패할 수 있습니다.- NgModule와 Standalone 앱이 혼합된 경우 복잡한 인터셉터 순서가 미묘한 동작 변화를 보일 수 있습니다.
The Fix
- 설정 옵션(예:
withInterceptors또는withFetch)을 전달하지 않는 한 명시적인provideHttpClient()호출을 제거하세요. - 변경 후 인터셉터 실행 순서를 확인하세요.
Zoneless Mode (zone.js optional)
The Change
ng new로 생성된 새로운 앱은 기본적으로 zone.js를 제외합니다.
What breaks
- 기존 앱은 여전히
polyfills.ts에서zone.js를 임포트하고 있기 때문에 즉시 깨지지는 않습니다. - 새로운 v21 튜토리얼 코드를 v20 앱에 복사·붙여넣기 하면 Zoneless 동작을 가정하게 되어 “changed after checked” 오류나 뷰가 업데이트되지 않는 현상이 발생할 수 있습니다.
Recommendation
Zone 기반과 Zoneless 감지 방식의 차이를 이해한 뒤 패러다임을 혼용하세요.
New Features
Reactive Forms with Signals
import { form, field } from '@angular/forms/signals';
import { Validators } from '@angular/forms';
// Define a reactive form model
const loginForm = form({
email: field('', [Validators.required, Validators.email]),
password: field('', [Validators.required])
});
// Access values directly as signals!
console.log(loginForm.value().email);
- 왜 사용하나요: 기본적으로 타입 안전하고 깊은 RxJS 지식이 필요 없습니다.
- 상태: 실험 단계 – 새로운 기능에 적합하지만, 기존 대규모 흐름을 바로 재작성하는 것은 피하세요.
Headless Accessibility Primitives
<Option 1>
<Option 2>
aria-expanded와 role="button"을 직접 관리하는 대신, 이 디렉티브를 사용해 접근성 로직을 처리하고 컴포넌트를 스타일링하세요.
Regex Literals in Templates
@if (email() | match: /@company\.com$/) {
Employee
}
작지만 강력합니다: 이제 템플릿에서 정규식 리터럴을 직접 사용할 수 있어, 헬퍼 함수 없이도 간단한 @if 로직을 구현할 수 있습니다.
Upgrade Steps
1. Backup
모든 것을 커밋하세요. 진심입니다.
2. Update the Global CLI
# Optional: Uninstall the old global version first to avoid conflicts
npm uninstall -g @angular/cli
# Verify the npm cache
npm cache verify
# Install the latest global CLI version
npm install -g @angular/cli@latest
3. Update the Local Project
ng update @angular/cli@21 @angular/core@21
4. Run Diagnostics
ngClass와 같이 [class.my‑class]로 대체되는 소프트 디프리케이트된 사용법을 찾아보고, Standalone 마이그레이션 가능성을 식별하세요.
5. Check Your Tests
ng test
- 테스트가 폭발한다면, 다음 중 선택하세요:
- Path A – Karma 유지 (제거된 경우
@angular/build:karma를 수동으로 추가). - Path B – Vitest로 마이그레이션 (권장).
- Path A – Karma 유지 (제거된 경우
6. Optional: Go Zoneless
ng generate @angular/core:zoneless-migration
이것은 “Agentic” 영역입니다. 복잡한 리팩터링을 AI에게 맡기는 방법은 MCP 가이드를 참고하세요.
Conclusion
Angular 21은 “깨끗한 슬레이트” 릴리스입니다. 지난 10년간 축적된 무게—Zone, Karma, 무거운 모듈 패턴—를 버리고 Svelte와 Solid 같은 현대 프레임워크와 경쟁합니다. 테스트 변화 때문에 업그레이드가 다소 험난할 수 있지만, 더 빠르고 단순하며 Signal‑기반 프레임워크라는 최종 목표는 충분히 가치가 있습니다.