모든 특전, 번거로움 없음: Angular 9 튜토리얼
게시 됨: 2022-03-11"매년 인터넷이 중단됩니다."라는 속담이 있으며 일반적으로 개발자는 가서 수리해야 합니다. 오랫동안 기다려온 Angular 버전 9에서는 이것이 적용될 것이라고 생각할 수 있으며 이전 버전에서 개발된 앱은 주요 마이그레이션 프로세스를 거쳐야 합니다.
하지만 그렇지 않습니다! Angular 팀은 컴파일러를 완전히 재설계하여 더 빠른 빌드, 더 빠른 테스트 실행, 더 작은 번들 크기, 그리고 가장 중요한 것은 이전 버전과의 이전 버전과의 호환성을 제공합니다. Angular 9를 사용하면 개발자는 기본적으로 번거로움 없이 모든 혜택을 누릴 수 있습니다.
이 Angular 9 자습서에서는 Angular 애플리케이션을 처음부터 빌드합니다. 우리는 최신 Angular 9 기능 중 일부를 사용하고 그 과정에서 다른 개선 사항을 살펴볼 것입니다.
Angular 9 튜토리얼: 새로운 Angular 애플리케이션으로 시작하기
Angular 프로젝트 예제를 시작하겠습니다. 먼저 Angular의 CLI 최신 버전을 설치해 보겠습니다.
npm install -g @angular/cli
ng version
을 실행하여 Angular CLI 버전을 확인할 수 있습니다.
다음으로 Angular 애플리케이션을 만들어 보겠습니다.
ng new ng9-app --create-application=false --strict
ng new
명령에서 두 개의 인수를 사용하고 있습니다.
-
--create-application=false
는 CLI에 작업 공간 파일만 생성하도록 지시합니다. 이것은 하나 이상의 앱과 여러 라이브러리가 필요할 때 코드를 더 잘 구성하는 데 도움이 됩니다. -
--strict
는 TypeScript 타이핑과 코드 정리를 강화하기 위해 더 엄격한 규칙을 추가합니다.
그 결과 기본 작업 공간 폴더와 파일이 생겼습니다.
이제 새 앱을 추가해 보겠습니다. 이를 위해 다음을 실행합니다.
ng generate application tv-show-rating
메시지가 표시됩니다.
? Would you like to share anonymous usage data about this project with the Angular Team at Google under Google's Privacy Policy at https://policies.google.com/privacy? For more details and how to change this setting, see http://angular.io/analytics. No ? Would you like to add Angular routing? Yes ? Which stylesheet format would you like to use? SCSS
이제 ng serve
를 실행하면 앱이 초기 스캐폴딩으로 실행되는 것을 볼 수 있습니다.
ng build --prod
를 실행하면 생성된 파일 목록을 볼 수 있습니다.
각 파일에는 두 가지 버전이 있습니다. 하나는 레거시 브라우저와 호환되고 다른 하나는 최신 API를 사용하고 브라우저에서 실행하는 데 더 적은 폴리필이 필요한 ES2015를 대상으로 컴파일됩니다.
Angular 9의 한 가지 큰 개선 사항은 번들 크기입니다. Angular 팀에 따르면 대형 앱의 경우 최대 40% 감소를 볼 수 있습니다.
새로 생성된 앱의 경우 번들 크기는 Angular 8과 거의 유사하지만 앱이 성장함에 따라 이전 버전에 비해 번들 크기가 작아지는 것을 볼 수 있습니다.
Angular 9에 도입된 또 다른 기능은 구성 요소 스타일 CSS 파일이 정의된 임계값보다 큰 경우 경고하는 기능입니다.
이것은 나쁜 스타일 가져오기 또는 거대한 구성 요소 스타일 파일을 잡는 데 도움이 됩니다.
TV 프로그램 평가 양식 추가
다음으로 TV 프로그램을 평가하는 양식을 추가합니다. 이를 위해 먼저 bootstrap
및 ng-bootstrap
을 설치합니다.
npm install bootstrap @ng-bootstrap/ng-bootstrap
Angular 9의 또 다른 개선 사항은 i18n(국제화)입니다. 이전에는 개발자가 앱의 모든 로캘에 대해 전체 빌드를 실행해야 했습니다. 대신 Angular 9를 사용하면 앱을 한 번 빌드하고 빌드 후 프로세스에서 모든 i18n 파일을 생성하여 빌드 시간을 크게 줄일 수 있습니다. ng-bootstrap
에는 i18n에 대한 종속성이 있으므로 프로젝트에 새 패키지를 추가합니다.
ng add @angular/localize
다음으로 앱의 styles.scss
에 Bootstrap 테마를 추가합니다.
@import "~bootstrap/scss/bootstrap";
그리고 app.module.ts
의 AppModule
에 NgbModule
및 ReactiveFormsModule
을 포함합니다.
// ... import { ReactiveFormsModule } from '@angular/forms'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; @NgModule({ imports: [ // ... ReactiveFormsModule, NgbModule ], })
다음으로, 우리는 우리 양식의 기본 그리드로 app.component.html
을 업데이트할 것입니다:
<div class="container"> <div class="row"> <div class="col-6"> </div> </div> </div>
그리고 양식 구성 요소를 생성합니다.
ng gc TvRatingForm
tv-rating-form.component.html
을 업데이트하고 TV 프로그램을 평가하는 양식을 추가해 보겠습니다.
<form [formGroup]="form" (ngSubmit)="submit()" class="mt-3"> <div class="form-group"> <label>TV SHOW</label> <select class="custom-select" formControlName="tvShow"> <option *ngFor="let tvShow of tvShows" [value]="tvShow.name">{{tvShow.name}}</option> </select> </div> <div class="form-group"> <ngb-rating [max]="5" formControlName="rating"></ngb-rating> </div> <button [disabled]="form.invalid || form.disabled" class="btn btn-primary">OK</button> </form>
그리고 tv-rating-form.component.ts
는 다음과 같이 보일 것입니다:
// ... export class TvRatingFormComponent implements OnInit { tvShows = [ { name: 'Better call Saul!' }, { name: 'Breaking Bad' }, { name: 'Lost' }, { name: 'Mad men' } ]; form = new FormGroup({ tvShow: new FormControl('', Validators.required), rating: new FormControl('', Validators.required), }); submit() { alert(JSON.stringify(this.form.value)); this.form.reset(); } }
마지막으로 app.component.html
에 양식을 추가해 보겠습니다.
<!-- ... --> <div class="col-6"> <app-tv-rating-form></app-tv-rating-form> </div>
이 시점에서 몇 가지 기본 UI 기능이 있습니다. 이제 ng serve
를 다시 실행하면 실제로 작동하는 것을 볼 수 있습니다.
계속 진행하기 전에 디버깅을 돕기 위해 추가된 몇 가지 흥미로운 새로운 Angular 9 기능을 간단히 살펴보겠습니다. 이것은 일상 업무에서 매우 일반적인 작업이므로 우리 삶을 조금 더 쉽게 만들기 위해 무엇이 변경되었는지 아는 것은 가치가 있습니다.
Angular 9 Ivy로 디버깅
Angular 9 및 Angular Ivy에 도입된 또 다른 큰 개선 사항은 디버깅 경험입니다. 컴파일러는 이제 더 많은 오류를 감지하고 더 "가독성 있는" 방식으로 오류를 던질 수 있습니다.
행동으로 봅시다. 먼저 tsconfig.json
에서 템플릿 검사를 활성화합니다.
{ // ... "angularCompilerOptions": { "fullTemplateTypeCheck": true, "strictInjectionParameters": true, "strictTemplates": true } }
이제 tvShows
배열을 업데이트하고 name
을 title
로 바꾸면:
tvShows = [ { title: 'Better call Saul!' }, { title: 'Breaking Bad' }, { title: 'Lost' }, { title: 'Mad men' } ];
... 컴파일러에서 오류가 발생합니다.
이 유형 검사를 통해 오타와 TypeScript 유형의 잘못된 사용을 방지할 수 있습니다.
@Input()
에 대한 Angular Ivy 검증
우리가 얻는 또 다른 좋은 유효성 검사는 @Input()
입니다. 예를 들어 다음을 tv-rating-form.component.ts
에 추가할 수 있습니다.
@Input() title: string;
... 그리고 app.component.html
에 바인딩합니다.
<app-tv-rating-form [title]="title"></app-tv-rating-form>
... 그런 다음 app.component.ts
를 다음과 같이 변경합니다.
// ... export class AppComponent { title = null; }
이 세 가지를 변경하면 컴파일러에서 다른 유형의 오류가 발생합니다.
이를 우회하려는 경우 템플릿에서 $any()
를 사용하여 값을 any
로 캐스팅하고 오류를 수정할 수 있습니다.
<app-tv-rating-form [title]="$any(title)"></app-tv-rating-form>
그러나 이것을 수정하는 올바른 방법은 형식의 title
을 nullable로 만드는 것입니다.
@Input() title: string | null ;
Angular 9 Ivy의 ExpressionChangedAfterItHasBeenCheckedError
Angular 개발에서 가장 두려운 오류 중 하나는 ExpressionChangedAfterItHasBeenCheckedError
입니다. 고맙게도 Ivy는 오류를 더 명확하게 출력하므로 문제가 어디에서 오는지 쉽게 찾을 수 있습니다.
그럼 ExpressionChangedAfterItHasBeenCheckedError
오류를 소개하겠습니다. 이를 위해 먼저 서비스를 생성합니다.
ng gs Title
다음으로 BehaviorSubject
및 Observable
에 액세스하고 새 값을 내보내는 메서드를 추가합니다.
export class TitleService { private bs = new BehaviorSubject < string > (''); constructor() {} get title$() { return this.bs.asObservable(); } update(title: string) { this.bs.next(title); } }
그 후, 우리는 이것을 app.component.html
에 추가할 것입니다:
<!-- ... --> <div class="col-6"> <h2> {{title$ | async}} </h2> <app-tv-rating-form [title]="title"></app-tv-rating-form> </div>
그리고 TitleService
에서 app.component.ts
를 주입합니다.

export class AppComponent implements OnInit { // ... title$: Observable < string > ; constructor( private titleSvc: TitleService ) {} ngOnInit() { this.title$ = this.titleSvc.title$; } // ... }
마지막으로 tv-rating-form.component.ts
에서 AppComponent
를 주입하고 TitleService
의 제목을 업데이트하면 ExpressionChangedAfterItHasBeenCheckedError
오류가 발생합니다.
// ... constructor( private titleSvc: TitleService ) { } ngOnInit() { this.titleSvc.update('new title!'); }
이제 브라우저의 개발 콘솔에서 자세한 오류를 볼 수 있으며 app.component.html
을 클릭하면 오류가 있는 위치를 알려줍니다.
서비스 호출을 setTimeout
으로 래핑하여 이 오류를 수정할 수 있습니다.
setTimeout(() => { this.titleSvc.update('new title!'); });
ExpressionChangedAfterItHasBeenCheckedError
오류가 발생하는 이유를 이해하고 다른 가능성을 알아보려면 해당 주제에 대한 Maxim Koretskyi의 게시물을 읽을 가치가 있습니다.
Angular Ivy를 사용하면 오류를 보다 명확하게 표시할 수 있으며 코드에서 TypeScript 입력을 강제 적용할 수 있습니다. 다음 섹션에서는 Ivy와 디버깅을 활용하는 몇 가지 일반적인 시나리오를 다룰 것입니다.
컴포넌트 하네스로 Angular 9 앱 테스트 작성하기
Angular 9에서는 구성 요소 하네스 라는 새로운 테스트 API가 도입되었습니다. 그 배후의 아이디어는 DOM과 상호 작용하는 데 필요한 모든 잡다한 일을 제거하여 작업하기 훨씬 쉽고 안정적으로 실행하는 것입니다.
구성 요소 하네스 API는 @angular/cdk
라이브러리에 포함되어 있으므로 먼저 프로젝트에 설치해 보겠습니다.
npm install @angular/cdk
이제 테스트를 작성하고 구성 요소 하네스를 활용할 수 있습니다. tv-rating-form.component.spec.ts
에서 테스트를 설정해 보겠습니다.
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { ReactiveFormsModule } from '@angular/forms'; describe('TvRatingFormComponent', () => { let component: TvRatingFormComponent; let fixture: ComponentFixture < TvRatingFormComponent > ; beforeEach(async (() => { TestBed.configureTestingModule({ imports: [ NgbModule, ReactiveFormsModule ], declarations: [TvRatingFormComponent] }).compileComponents(); })); // ... });
다음으로 구성 요소에 대한 ComponentHarness
를 구현해 보겠습니다. 우리는 두 개의 하네스를 만들 것입니다. 하나는 TvRatingForm
용이고 다른 하나는 NgbRating
용입니다. ComponentHarness
에는 구성 요소 선택기의 값을 취해야 하는 static
필드인 hostSelector
가 필요합니다.
// ... import { ComponentHarness, HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; class TvRatingFormHarness extends ComponentHarness { static hostSelector = 'app-tv-rating-form'; } class NgbRatingHarness extends ComponentHarness { static hostSelector = 'ngb-rating'; } // ...
TvRatingFormHarness
의 경우 제출 버튼에 대한 선택기와 click
을 트리거하는 함수를 만듭니다. 이것을 구현하는 것이 얼마나 쉬운지 알 수 있습니다.
class TvRatingFormHarness extends ComponentHarness { // ... protected getButton = this.locatorFor('button'); async submit() { const button = await this.getButton(); await button.click(); } }
다음으로 등급을 설정하는 메서드를 추가합니다. 여기서 locatorForAll
을 사용하여 사용자가 클릭할 수 있는 별을 나타내는 모든 <span>
요소를 찾습니다. rate
함수는 가능한 모든 등급의 별표를 가져오고 전송된 값에 해당하는 별표를 클릭합니다.
class NgbRatingHarness extends ComponentHarness { // ... protected getRatings = this.locatorForAll('span:not(.sr-only)'); async rate(value: number) { const ratings = await this.getRatings(); return ratings[value - 1].click(); } }
누락된 마지막 부분은 TvRatingFormHarness
를 NgbRatingHarness
에 연결하는 것입니다. 그렇게 하려면 TvRatingFormHarness
클래스에 로케이터를 추가하기만 하면 됩니다.
class TvRatingFormHarness extends ComponentHarness { // ... getRating = this.locatorFor(NgbRatingHarness); // ... }
이제 테스트를 작성해 보겠습니다.
describe('TvRatingFormComponent', () => { // ... it('should pop an alert on submit', async () => { spyOn(window, 'alert'); const select = fixture.debugElement.query(By.css('select')).nativeElement; select.value = 'Lost'; select.dispatchEvent(new Event('change')); fixture.detectChanges(); const harness = await TestbedHarnessEnvironment.harnessForFixture(fixture, TvRatingFormHarness); const rating = await harness.getRating(); await rating.rate(1); await harness.submit(); expect(window.alert).toHaveBeenCalledWith('{"tvShow":"Lost","rating":1}'); }); });
양식 내 select
항목의 경우 하네스를 통해 값 설정을 구현하지 않았습니다. API가 여전히 옵션 선택을 지원하지 않기 때문입니다. 그러나 이것은 구성 요소 하네스 이전에 요소와 상호 작용하는 모습을 여기서 비교할 수 있는 기회를 제공합니다.
테스트를 실행하기 전에 마지막으로 한 가지. title
을 null
로 업데이트했기 때문에 app.component.spec.ts
를 수정해야 합니다.
describe('AppComponent', () => { // ... it(`should have as title 'tv-show-rating'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; expect(app.title).toEqual(null); }); });
이제 ng test
를 실행하면 테스트가 통과합니다.
Angular 9 예제 앱으로 돌아가기: 데이터베이스에 데이터 저장
Firestore에 대한 연결을 추가하고 데이터베이스에 등급을 저장하여 Angular 9 자습서를 마무리하겠습니다.
그러려면 Firebase 프로젝트를 만들어야 합니다. 그런 다음 필요한 종속성을 설치합니다.
npm install @angular/fire firebase
Firebase 콘솔의 프로젝트 설정에서 구성을 가져와서 environment.ts
및 environment.prod.ts
에 추가합니다.
export const environment = { // ... firebase: { apiKey: '{your-api-key}', authDomain: '{your-project-id}.firebaseapp.com', databaseURL: 'https://{your-project-id}.firebaseio.com', projectId: '{your-project-id}', storageBucket: '{your-project-id}.appspot.com', messagingSenderId: '{your-messaging-id}', appId: '{your-app-id}' } };
그런 다음 app.module.ts
에서 필요한 모듈을 가져옵니다.
import { AngularFireModule } from '@angular/fire'; import { AngularFirestoreModule } from '@angular/fire/firestore'; import { environment } from '../environments/environment'; @NgModule({ // ... imports: [ // ... AngularFireModule.initializeApp(environment.firebase), AngularFirestoreModule, ], // ... })
다음으로 tv-rating-form.component.ts
에서 AngularFirestore
서비스를 삽입하고 양식 제출 시 새 등급을 저장합니다.
import { AngularFirestore } from '@angular/fire/firestore'; export class TvRatingFormComponent implements OnInit { constructor( // ... private af: AngularFirestore, ) { } async submit(event: any) { this.form.disable(); await this.af.collection('ratings').add(this.form.value); this.form.enable(); this.form.reset(); } }
이제 Firebase 콘솔로 이동하면 새로 생성된 항목이 표시됩니다.
마지막으로 모든 등급을 AppComponent
에 나열해 보겠습니다. 이를 위해 app.component.ts
에서 컬렉션에서 데이터를 가져옵니다.
import { AngularFirestore } from '@angular/fire/firestore'; export class AppComponent implements OnInit { // ... ratings$: Observable<any>; constructor( // ... private af: AngularFirestore ) { } ngOnInit() { // ... this.ratings$ = this.af.collection('ratings').valueChanges(); } }
… 그리고 app.component.html
에서 평가 목록을 추가합니다.
<div class="container"> <div class="row"> // ... <div class="col-6"> <div> <p *ngFor="let rating of ratings$ | async"> {{rating.tvShow}} ({{rating.rating}}) </p> </div> </div> </div> </div>
이것이 Angular 9 튜토리얼 앱이 모두 합쳐졌을 때의 모습입니다.
Angular 9 및 Angular Ivy: 더 나은 개발, 더 나은 앱, 더 나은 호환성
이 Angular 9 자습서에서는 기본 양식을 작성하고 Firebase에 데이터를 저장하고 여기에서 항목을 검색하는 방법을 다뤘습니다.
그 과정에서 Angular 9 및 Angular Ivy에 어떤 개선 사항과 새로운 기능이 포함되었는지 확인했습니다. 전체 목록은 공식 Angular 블로그의 최신 릴리스 게시물에서 확인할 수 있습니다.
Google Cloud 파트너로서 Toptal의 Google 인증 전문가는 회사의 가장 중요한 프로젝트에 대한 수요가 있을 때 사용할 수 있습니다.