이제 Angular 2 대신에 Angular 4가 되어버렸다. 그리고 Angular 4는 그냥 Angular라고 부른다고 한다. Angular 1은 Angular.js 이다. Angular.io는 Angular 2를 지칭하는 말이었고, 그냥 Angular는 Angular 2,4,5,… 을 통칭하는 말이란다.

…~~~ 헷갈리시죠? 네, 저도 헷갈립니다. (한숨) 이놈의 네이밍을 제대로 알아가시는 것으로부터 Angular 4의 특징은 시작됩니다.

1. 그냥 Angular 라고 불린다.

이제 더 이상 버전을 이름 뒤에 붙히지 않습니다. 그냥 Angular 입니다.

‘어? 그럼 Angular 1은요?’

Angular 1은 Angular.js 라고 불리며, Angular 팀에서는 사용을 권장하지는 않습니다. (많은 커뮤니티가 이미 옮겨 가버림…)

2. 버전 3은 어디로 갔나요 ?

Angular 2 개발 당시, 모듈들의 역사를 보면 이러한 이유를 알 수 있다.

alpha 당시는 내가 사용을 안해서 정확하게는 모르고, beta 당시에 여러 모듈들을 각각 사람들이 따로 나누어서 개발을 했는데, 버전들이 약간씩 달라서 사용하기가 어려웠고, 그래서 beta 버전때에는 UMD (Unified Module Definition) 번들 하나를 제공했었다. 그러다가 beta 막바지와 RC 로 넘어오면서 모듈 그룹명칭이 'angular2' 에서 '@angular' 로 바뀌게 되었고, 그 즈음 각각의 모듈들(forms, router, platform-browser, platform-browser-dynamic 등등...) 을 개별 모듈로 나누어서 관리하였다.

개별 모듈로 나누게 된 이유는 아마 내 기억과 생각이 맞다면, 당시에 기본 모듈 번들러를 SystemJS 에서 Webpack으로 넘어가게 되면서, 번들링 과정에서 Tree Shaking을 할 때에 더욱 용이하게 하기 위해 개별 모듈로 나누게 된 것 같다 (당시에 그런 이슈들이 있었던 것 같다, 확실하지는 않다).

이 개별 모듈 중 router가 버전이 달랐다. Angular 2가 정확히 작년 추석에 릴리즈 되었는데, 그때 core, common, platform-browser, ... 등의 모듈들은 버전이 2.0.0이었지만, router는 버전이 3.0.0이었다. 그 이후로 얼마 전까지 버전 2.4.10을 달성하는 동안 꾸준히 router의 버전도 3.4.10까지 따라왔었다.

그래서 모듈 간의 버전을 동일하게 하기 위해서 버전을 4로 통일하겠다는 것이다. 이 내용은 전에 내가 작성했던 글에도 나와있다.

3. 템플릿의 If…Else 조건문

Angular 2에서는 *ngIf 라는 템플릿에서 사용할 수 있는 리터럴이 존재했었다.

<!-- Angular 2 ngIf 예시 -->
<p *ngIf="isLoggedIn">{{username}}님 반갑습니다!</p>

이 리터럴은 단지 expression의 참/거짓 만 판단하여 블록의 렌더링 유무를 결정하였기 때문에, expression이 거짓이면 아예 렌더링 자체도 되질 않았다.

Angular 4부터는 이러한 경우에 else 를 사용할 수 있다.

<!-- Angular 4 If Else 문법-->
<element *ngIf="[condition expression]; else [else template]">
  TRUE CONTENTS
</element>
<template #notLoggedInTpl>
  <p>로그인 해 주세요!</p>
</template>
<p *ngIf="isLoggedIn; else notLoggedInTpl">
  {{username}}님 반갑습니다!
</p>

조금 더 나아가서, Then도 사용할 수 있다.

<template #notLoggedInTpl>
  <p>로그인 해 주세요!</p>
</template>
<template #loggedInTpl>
  <p>{{username}}님 반갑습니다!</p>
</template>
<p *ngIf="isLoggedIn; then loggedInTpl else notLoggedInTpl"</p>

심지어는 여기에다가 pipe도 적용시킬 수 있다.

// 'Angular 4 async - IF Else 예시'
@Component({
  selector: 'login',
  templateUrl: './tpl.html'
})
class Login {
  user = Observable.timer(5000).mapTo({ firstName: 'Kesus', lastName: 'Kim' });
}
<!-- Angular 4 async - IF Else 예시 -->
<div *ngIf="user | async as user; else loading;">
  {{user.firstName}} {{user.lastName}} 님 반갑습니다!
</div>
<template #loading>Loading...</template>

4. Animation 모듈

Angular 2에도 Web Animation을 구현한 Animation 기능이 있기는 했다. 하지만 이는 @angular/core에 존재해서, 이를 사용하기 위해서는 다음과 같은 코드를 작성했어야 했다.

// Angular 2 animation 예시
import {
  Component,
  OnInit,
  animate,
  state,
  style,
  transition,
  trigger
} from '@angular/core';

이제는 @angular/animations 모듈로부터 사용해야한다.

// Angular 4 animation 예시
import {
  Component,
  OnInit
} from '@angular/core';

import {
  animate,
  state,
  style,
  transition,
  trigger
} from '@angular/animations';

5. Server Side Rendering

원래 Angular 2에서 SSR (Server Side Rendering) 은 Angular Universal 에서 했었다. Angular 팀에 있는 것처럼 보이기는 하는데, 뭔가 커뮤니티에 의해 돌아가고 있던 느낌?

Angular 4부터는 Angular의 코더 모듈이 되어서, 그냥 사용할 수 있다! ㅎㅎㅎ

import { platformServer, renderModuleFactory } from '@angular/platform-server';

6. TypeScript가 nullundefined를 허용한다.

이전에는 TypeScript에서 nullundefined를 허용하지 않았다. 만약 이상한 낌새가 보이면 바로 빨간색 글씨를 뿜으며 에러!!!, 더이상 진행이 안됨. 디버깅, 시간 많이 잡아먹음. 에너지 소모, 힘듦. 상사로부터의 갈굼, 왜 이런것도 못해!? 의욕 상실. 수순을 밟았는데, 이제는 감사하게도 TypeScript에서 둘을 허용해주시겠댄다.

이제는 이런 것도 된다…

class AppComponent {
  someVarA: String | null;
  someVarB: Object | undefined;
  someVarC: Number | null | undefined;

  ...
}

7. 더욱 경량화 된 ECMA 모듈

FESM (Flattened ECMAScript Module) 이라 불리는 이 특징은, 더욱 ECMAScript 표준에 맞추어(특히 ES 6) 모듈 시스템의 표준에 맞게 모듈을 구현하였다는 의미로, Tree Shaking을 더욱 도와준다는 의미이다.

이는 곧 성능 향상과 번들 사이즈의 감소로 나타날 수 있는데, 정확한 수치는 재봐야 겠지만 내가 경험한 바로는 이전에 번들이 한 30초 걸리던 것이 지금 15초 내외가 걸린다. 와우!