Angular에서 경로 수준 코드 분할

경로 수준 코드 분할을 사용하여 앱 성능을 개선하세요!

이 게시물에서는 Angular 애플리케이션에서 경로 수준 코드 분할을 설정하는 방법을 설명합니다. 이렇게 하면 JavaScript 번들 크기를 줄이고 상호작용까지의 시간을 크게 개선할 수 있습니다.

GitHub의 이 도움말에서 코드 샘플을 찾을 수 있습니다. 즉시 실행 라우팅 예는 eager 브랜치에서 확인할 수 있습니다. 경로 수준 코드 분할 예는 지연 브랜치에 있습니다.

코드 분할이 중요한 이유

웹 애플리케이션이 점점 더 복잡해짐에 따라 사용자에게 제공되는 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를 동적으로 로드하는 nyan라는 AppModule의 경로 - NyanModule의 기본 경로 - 사용자가 기본 경로에 도달할 때 렌더링될 NyanComponent라는 구성요소

Angular를 사용한 코드 분할 구현에 대해 더 잘 이해할 수 있도록 이 단계를 수동으로 실행해 보겠습니다.

사용자가 nyan 경로로 이동하면 라우터는 라우터 아웃렛에서 NyanComponent를 렌더링합니다.

Angular에서 경로 수준 코드 분할을 사용하려면 경로 선언의 loadChildren 속성을 설정하고 이를 동적 가져오기와 결합합니다.

{
  path: 'nyan',
  loadChildren: () => import('./nyan/nyan.module').then(m => m.NyanModule)
}

Eager 경로에는 두 가지 주요 차이점이 있습니다.

  1. component 대신 loadChildren를 설정합니다. 경로 수준 코드 분할을 사용할 때는 구성요소 대신 동적으로 로드된 모듈을 가리켜야 합니다.
  2. loadChildren에서 프로미스가 해결되면 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를 느리게 다운로드하는지 확인하는 방법은 다음과 같습니다.

  1. `Control+Shift+J` (Mac의 경우 `Command+Option+J`)를 눌러 DevTools를 엽니다.
  2. 네트워크 탭을 클릭합니다.

  3. 샘플 앱에서 NYAN을 클릭합니다.

  4. nyan-nyan-module.js 파일이 네트워크 탭에 표시됩니다.

경로 수준 코드 분할을 사용한 자바스크립트 번들의 지연 로드

GitHub에서 이 예시를 찾아보세요.

스피너 표시

현재 사용자가 NYAN 버튼을 클릭하면 애플리케이션은 백그라운드에서 JavaScript를 로드 중임을 나타내지 않습니다. 스크립트를 로드하는 동안 사용자에게 피드백을 제공하려면 스피너를 추가하는 것이 좋습니다.

이렇게 하려면 먼저 app.component.htmlrouter-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 애플리케이션의 번들 크기를 줄일 수 있습니다.

  1. Angular CLI 지연 로드 모듈 생성기를 사용하여 동적으로 로드된 경로를 자동으로 스캐폴딩합니다.
  2. 사용자가 지연 경로로 이동할 때 진행 중인 작업이 있음을 표시하기 위해 로드 표시기를 추가합니다.