Angular에서 경로 수준 코드 분할

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

이 게시물에서는 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)
}

이 경로는 이그조틱 경로와 두 가지 주요 차이점이 있습니다.

  1. component 대신 loadChildren를 설정합니다. 경로 수준 코드 분할을 사용하는 경우 구성요소 대신 동적으로 로드된 모듈을 가리켜야 합니다.
  2. 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를 지연 로드하는지 확인하려면 다음 단계를 따르세요.

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

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

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

경로 수준 코드 분할을 사용한 JavaScript 번들의 지연 로드

이 예시는 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. 사용자가 지연 라우트로 이동할 때 진행 중인 작업이 있음을 나타내는 로드 표시기를 추가합니다.