Angular CLI는 간단한 명령어를 사용하여 Angular 프로젝트 스캐폴딩(scaffolding)을 생성, 실행, 빌드할 수 있으며 Angular의 다양한 구성 요소를 선별적으로 추가할 수 있는 커맨드-라인 인터페이스(Command Line Interface)이다. 개발용 서버를 내장하고 있어서 간단히 프로젝트를 실행시켜서 동작을 확인할 수 있다.
스캐폴딩(Scaffolding)이란?
양식, 포맷, 기본 구조를 뜻한다. Angular로 처음 프로젝트를 셋팅할 때 프로젝트의 기본 구조라고 생각하면 이해가 쉽다.
$ npm install -g @angular/cli
ng new
명령어를 사용한다.$ ng new <project-name>
프로젝트를 로컬 환경에서 실행하기 위해서는 ng serve
명령어를 사용한다.
프로젝트를 실행할 때 --open(축약형 -o) 옵션을 추가하면 자동으로 브라우저를 실행한다.
$ cd <project-name> // 프로젝트 폴더로 이동
$ ng serve --open // 프로젝트 실행
$ ng serve --port 4201
프로젝트에 새로운 구성요소를 생성하기 위해서는 ng generate
명령어를 사용한다.
ng generate
명령어는 축약형 ng g
와 동일하게 동작한다.
ng generate component
명령어를 사용한다. ng generate component home
명령어를 실행하면 Angular CLI는 아래와 같이 동작한다. home.component.html
: 컴포넌트 템플릿을 위한 HTML 파일home.component.css
: 컴포넌트 템플릿의 스타일링을 위한 CSS 파일home.component.ts
: 컴포넌트 클래스 파일home.component.spec.ts
: 컴포넌트 유닛 테스트를 위한 스펙 파일src/app/app.moddule.ts
에 새롭게 생성된 컴포넌트를 등록한다. 컴포넌트 클래스를 import하고 @NgModule
데코레이터의 declarations
프로퍼티에 컴포넌트 클래스를 등록한다.주의해야 할 것은 ng generate component
명령어 다음에 지정한 컴포넌트명이 실제 생성된 파일명과 다를 수 있다는 것이다.
컴포넌트명을 Angular CLI는 지정된 컴포넌트명의 대소문자를 구별하여 정해진 규칙에 따라 파일명을 암묵적으로 변경한다.
$ ng generate component newComponent // new-component로 변경됨
이와 같은 파일명의 암묵적 변경은 컴포넌트뿐만 아니라 ng generate
명령어로 추가되는 모든 구성요소에 모두 적용된다. 혼란을 방지하기 위해 ng generate
명령어에 지정하는 구성요소 명칭은 하이픈으로 단어를 연결하는 케밥 표기법(kebab-case)을 사용하는 것이 좋다.
즉, CamelCase를 사용하여 ng generate
명령어의 이름을 짓는다면 모두 kebab-case로 변경되어 생성이된다는 의미이다.
src/app/home/home.component.ts
을 살펴보자// src/app/home/home.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor() { }
ngOnInit() { }
}
<!-- src/app/app.component.html -->
<app-home></app-home>
ng generate component home
명령어에서 지정한 컴포넌트명 home
앞에 접두사 app이 자동으로 추가된 값이다.templateUrl,styleUrl 프로퍼티는 외부 파일을 로드하기 위해 사용한다.
// src/app/home/home.component.ts
...
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
...
templateUrl
,styleUrls
프로퍼티 대신 template
,style
프로퍼티를 사용한다.메타데이터는 또 뭐야?
메타데이터는 쉽게 말해서 데이터의 데이터이다. '이 데이터는 어떤 목적, 내용, 이름을 갖고있느냐?' 이뜻이다. 우리가 불러온 데이터를 어떤 목적으로 쓸꺼야? 데코레이터가 프로퍼티명으로 물어보면 우리는 프로퍼티값으로 대답하면 됩니다. 'selector는 HTML Element로 쓸꺼야, templateUrl은 사용자에게 컴포넌트를 보여주는 HTML파일이야, styleUrls는 컴포넌트를 꾸며주는 CSS파일이야'
프로젝트에 새로운 디렉티브를 생성하기 위해서는 ng generate directive
명령어를 사용한다.
$ ng generate directive highlight
ng generate directive highlight
명령어를 실행하면 Angular CLI는 아래와 같이 동작한다.
src/app
폴더에 2개의 파일을 생성highlight.directive.ts
: 디렉티브 클래스 파일highlight.directive.spec.ts
: 디렉티브 유닛 테스트를 위한 스펙 파일src/app/app.module.ts
에 새롭게 생성된 디렉티브를 등록한다.declarations
프로퍼티에 디렉티브를 등록한다.컴포넌트를 생성할 때와는 달리 디렉티브를 위한 폴더는 생성되지 않으며 기본적으로 src/app
폴더에 생성된다. 생성된 highlight.directive.ts
를 살펴보면 @Directive
데코레이터 함수에 전달된 메타데이터 객체의 selector
프로퍼티값으로 '[appHighlight]'가 설정되었다.
// src/app/highlight.directive.ts
import { Directive } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class MyDirectiveDirective {
constructor() { }
}
angular.json
에 설정된 기본 접두사 app과 ng generate directive
명령어에 지정한 디렉티브 이름으로 합성된 디렉티브 셀렉터 이름으로 카멜표기법(camelCase)으로 작성된다. selector 프로퍼티에 지정한 디렉티브의 이름 appHighlight은 HTML attribute처럼 사용된다.
<p appHighlight>Highlight Directive!</p>
프로젝트에 새로운 모듈을 생성하기 위해서는 ng generate module
명령어를 사용한다.
$ ng generate module todos
ng generate module todos
명령어를 실행하면 Angular CLI는 아래와 같이 동작한다.
src/app
폴더에 todos
폴더를 생성한다.src/app/todos
폴더에 1개의 파일을 추가한다.todos.module.ts
: 모듈 클래스 파일todos.module.spec.ts
: 모듈 유닛 테스트를 위한 스펙 파일생성된 모듈은 해당 모듈을 사용하려는 다른 모듈의 imports 프로퍼티에 등록되어야 한다.
// src/app/app.module.ts
...
import { TodosModule } from './todos/todos.module';
@NgModule({
...
imports: [
...
TodosModule
],
bootstrap: [AppComponent]
})
export class AppModule { }
프로젝트에 새로운 서비스를 생성하기 위해서는 ng generate serivce
명령어를 사용한다.
$ ng generate service data
꿈에서 ng generate 나올지경
ng generate service data
명령어를 실행하면 Angular CLI는 아래와 같이 동작한다.
컴포넌트를 생성할 때와는 달리 서비스를 위한 폴더는 생성되지 않으며 기본적으로 src/app
폴더에 생성된다. 생성된 data.service.ts
를 살펴보면 @Injectable
데코레이터 함수에 전달된 메타데이터 객체의 providedIn
프로퍼티 값으로 'root'가 설정되었다.
// src/app/data.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class DataService {
constructor() { }
}
provideIn
프로퍼티는 Angular 6에서 도입된 것으로 프로퍼티 값으로 'root'를 설정하면 루트 인젝터에게 서비스를 제공하도록 지시하여 애플리케이션 전역에서 서비스를 주입할 수 있도록 한다.
프로젝트에 새로운 클래스를 생성하기 위해서는 ng generate class
명령어를 사용한다.
$ ng generate class user
테스트를 위한 스펙 파일을 함께 생성하기 위해서는 --spec
옵션을 추가한다.
$ ng generate class user --spec
프로젝트 개발을 완료한 이후 배포를 위해서는 ng build
명령어를 사용한다.
$ ng build
빌드가 완료되면 프로젝트 루트에 빌드 결과물이 포함된 dist 폴더가 생성된다.
TypeScript기반으로 개발이 진행되는 Angular 애플리케이션은 TypeScript를 Javascript로 변환하여야 한다. 또한 프로젝트가 의존하는 모듈들을 로드하는 HTML 파일의 script 태그를 작성해야 한다. 다양한 프로젝트의 의존 모듈을 순서에 맞게 수작업으로 script 태그에 기술하는 것은 매우 곤란한 일이며 실수가 발생할 수 있다.
Angular CLI로 새로운 프로젝트를 생성할 경우, 의존 모듈의 설치는 기본 패키지 매니저인 npm으로 자동화되어 진행된다. 이때 설치되는 의존 모듈은 약 1,000여 개로 의존성 관리를 위해 수작업은 현실적이지 않다. Angular CLI의 빌드 기능은 의존성 관리를 위한 작업을 자동화하여 진행한다.
Angular CLI 빌드 기능은 내부적으로 모듈 번틀러인 webpack을 사용하며 아래와 같은 작업의 자동화를 지원한다.
Angular CLI 빌드 기능은 소스코드와 의존 모듈을 번들링한다. 이때 번들링되는 코드는 JavaScript뿐만이 아니라 HTML,CSS까지 JavaScript 파일 내에 번들링된다. 또한 index.html
에 번들링된 자바스크립트 파일 5개를 로드하기 위한 태그를 추가한다.
<!-- 빌드 전 -->
<!-- src/index.html -->
...
<body>
<app-root></app-root>
</body>
</html>
<!-- 빌드 후 -->
<!-- dist/index.html -->
...
<body>
<app-root></app-root>
<script type="text/javascript" src="runtime.js"></script>
<script type="text/javascript" src="polyfills.js"></script>
<script type="text/javascript" src="styles.js"></script>
<script type="text/javascript" src="vendor.js"></script>
<script type="text/javascript" src="main.js"></script>
</body>
</html>