경로 수준 코드 분할을 사용하여 앱 성능을 개선하세요.
이 게시물에서는 JavaScript 번들 크기를 줄이고 Time to Interactive를 크게 개선할 수 있는 Angular 애플리케이션에서 경로 수준 코드 분할을 설정하는 방법을 설명합니다.
이 도움말의 코드 샘플은 GitHub에서 확인할 수 있습니다. 이그조틱 라우팅 예시는 이그조틱 브랜치에서 확인할 수 있습니다. 경로 수준 코드 분할 예는 지연 브랜치에 있습니다.
코드 분할이 중요한 이유
웹 애플리케이션의 복잡성이 점점 증가함에 따라 사용자에게 전송되는 JavaScript의 양이 크게 증가했습니다. 대용량 JavaScript 파일은 상호작용을 눈에 띄게 지연시킬 수 있으므로 특히 모바일에서는 비용이 많이 드는 리소스가 될 수 있습니다.
애플리케이션의 기능을 희생하지 않고 JavaScript 번들을 축소하는 가장 효율적인 방법은 공격적인 코드 분할을 도입하는 것입니다.
코드 분할을 사용하면 애플리케이션의 JavaScript를 여러 경로 또는 기능과 연결된 여러 청크로 나눌 수 있습니다. 이 접근 방식은 초기 애플리케이션 로드 중에 사용자에게 필요한 JavaScript만 전송하여 로드 시간을 짧게 유지합니다.
코드 분할 기법
코드 분할은 구성요소 수준과 경로 수준의 두 가지 수준에서 실행할 수 있습니다.
- 구성요소 수준 코드 분할에서는 구성요소를 자체 JavaScript 청크로 이동하고 필요할 때 지연 로드합니다.
- 경로 수준 코드 분할에서는 각 경로의 기능을 별도의 청크로 캡슐화합니다. 사용자가 애플리케이션을 탐색할 때 개별 경로와 연결된 청크를 가져오고 필요할 때 연결된 기능을 가져옵니다.
이 게시물에서는 Angular에서 경로 수준 분할을 설정하는 방법을 중점적으로 설명합니다.
샘플 애플리케이션
Angular에서 경로 수준 코드 분할을 사용하는 방법을 자세히 살펴보기 전에 샘플 앱을 살펴보겠습니다.
앱 모듈의 구현을 확인합니다. AppModule
내부에는 HomeComponent
와 연결된 기본 경로와 NyanComponent
와 연결된 nyan
경로라는 두 가지 경로가 정의됩니다.
@NgModule({
...
imports: [
BrowserModule,
RouterModule.forRoot([
{
path: '',
component: HomeComponent,
pathMatch: 'full'
},
{
path: 'nyan',
component: NyanComponent
}
])
],
...
})
export class AppModule {}
경로 수준 코드 분할
코드 분할을 설정하려면 nyan
이그조틱 경로를 리팩터링해야 합니다.
Angular CLI 버전 8.1.0에서는 이 명령어를 사용하여 모든 작업을 실행할 수 있습니다.
ng g module nyan --module app --route nyan
이렇게 하면 다음이 생성됩니다.
- NyanModule
라는 새 라우팅 모듈
- NyanModule
를 동적으로 로드하는 AppModule
의 경로인 nyan
- NyanModule
의 기본 경로
- 사용자가 기본 경로를 클릭할 때 렌더링되는 NyanComponent
라는 구성요소
Angular로 코드 분할을 구현하는 방법을 더 잘 이해할 수 있도록 이러한 단계를 수동으로 진행해 보겠습니다.
사용자가 nyan
경로로 이동하면 라우터가 라우터 콘센트에서 NyanComponent
를 렌더링합니다.
Angular에서 경로 수준 코드 분할을 사용하려면 경로 선언의 loadChildren
속성을 설정하고 동적 가져오기와 결합합니다.
{
path: 'nyan',
loadChildren: () => import('./nyan/nyan.module').then(m => m.NyanModule)
}
이 경로는 이그조틱 경로와 두 가지 주요 차이점이 있습니다.
component
대신loadChildren
를 설정합니다. 경로 수준 코드 분할을 사용하는 경우 구성요소 대신 동적으로 로드된 모듈을 가리켜야 합니다.loadChildren
에서 promise가 해결되면NyanComponent
를 가리키는 대신NyanModule
를 반환합니다.
위 스니펫은 사용자가 nyan
로 이동할 때 Angular가 nyan
디렉터리에서 nyan.module
를 동적으로 로드하고 모듈에 선언된 기본 경로와 연결된 구성요소를 렌더링해야 한다고 지정합니다.
다음 선언을 사용하여 기본 경로를 구성요소와 연결할 수 있습니다.
import { NgModule } from '@angular/core';
import { NyanComponent } from './nyan.component';
import { RouterModule } from '@angular/router';
@NgModule({
declarations: [NyanComponent],
imports: [
RouterModule.forChild([{
path: '',
pathMatch: 'full',
component: NyanComponent
}])
]
})
export class NyanModule {}
이 코드는 사용자가 https://example.com/nyan
로 이동할 때 NyanComponent
를 렌더링합니다.
Angular 라우터가 로컬 환경에서 nyan.module
를 지연 로드하는지 확인하려면 다음 단계를 따르세요.
- `Control+Shift+J` (Mac의 경우 `Command+Option+J`)를 눌러 DevTools를 엽니다.
네트워크 탭을 클릭합니다.
샘플 앱에서 NYAN을 클릭합니다.
nyan-nyan-module.js
파일이 네트워크 탭에 표시됩니다.
이 예시는 GitHub에서 확인할 수 있습니다.
스피너 표시
현재 사용자가 NYAN 버튼을 클릭해도 애플리케이션이 백그라운드에서 JavaScript를 로드하고 있음을 나타내지 않습니다. 스크립트를 로드하는 동안 사용자에게 피드백을 제공하려면 스피너를 추가하는 것이 좋습니다.
이렇게 하려면 먼저 app.component.html
의 router-outlet
요소 내에 표시기의 마크업을 추가합니다.
<router-outlet>
<span class="loader" *ngIf="loading"></span>
</router-outlet>
그런 다음 라우팅 이벤트를 처리할 AppComponent
클래스를 추가합니다. 이 클래스는 RouteConfigLoadStart
이벤트를 수신하면 loading
플래그를 true
로 설정하고 RouteConfigLoadEnd
이벤트를 수신하면 플래그를 false
로 설정합니다.
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
loading: boolean;
constructor(router: Router) {
this.loading = false;
router.events.subscribe(
(event: RouterEvent): void => {
if (event instanceof NavigationStart) {
this.loading = true;
} else if (event instanceof NavigationEnd) {
this.loading = false;
}
}
);
}
}
아래 예에서는 스피너가 작동하는 모습을 볼 수 있도록 인위적인 500ms 지연 시간을 도입했습니다.
결론
경로 수준 코드 분할을 적용하여 Angular 애플리케이션의 번들 크기를 줄일 수 있습니다.
- Angular CLI 지연 로드 모듈 생성기를 사용하여 동적으로 로드된 경로를 자동으로 스캐폴드합니다.
- 사용자가 지연 라우트로 이동할 때 진행 중인 작업이 있음을 나타내는 로드 표시기를 추가합니다.