Help us understand the problem. What is going on with this article?

[Angular]Routing単位でcode splittingする

背景

  • Angular初心者です
  • Angularでアプリを作っていますが規模が大きくなってくると初回ロード時のファイルサイズが気になってきました
  • code splittingして必要なコードを必要な時に取得するようにすると良いと聞いたことがあったので調べて試してみました

やったこと

  • Routerで設定しているページの単位にJSファイルを出力するようにしました
  • ページ遷移の都度そのページの表示に必要なコードだけ取得するイメージですね

やり方

サンプルアプリの作成

  • AngularCLIで雛形とコンポーネントを作ります
# サンプルコードが見やすいようにhtmlとcssはインラインにしてる
ng new ng-code-splitting-sample --routing=true --inline-style=true --inline-template=true --skip-tests=true --interactive=false
cd ng-code-splitting-sample
ng generate component home
ng generate component about
  • src/app内は以下のようになっています
  • 必要なところを修正していきます
% tree src/app/
src/app/
├── app-routing.module.ts
├── app.component.ts
├── app.module.ts
├── about
│   └── about.component.ts
└── home
    └── home.component.ts
  • ルーティングの設定を追加
src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'about', component: AboutComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
  • 不要なhtmlを削除しておく
src/app/app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: '<router-outlet></router-outlet>',
  styles: [],
})
export class AppComponent {
  title = 'ng-code-splitting-sample';
}
  • ページ遷移できるように各コンポーネントにリンクを追加
src/app/home/home.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-home',
  template: `
    <p>home works!</p>
    <a routerLink="about">About</a>
  `,
  styles: [],
})
export class HomeComponent implements OnInit {
  constructor() {}

  ngOnInit() {}
}
src/app/about/about.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-about',
  template: `
    <p>about works!</p>
    <a routerLink="/">Home</a>
  `,
  styles: [],
})
export class AboutComponent implements OnInit {
  constructor() {}
  ngOnInit() {}
}
  • ビルドしてみる
npm run build
  • アプリ本体のファイルはmain-es2015.jsmain-es5.jsです
  • code splittingするようにしていないため全てmainに入っています
# mapファイルは省略
% tree dist/ng-code-splitting-sample
dist/ng-code-splitting-sample
├── favicon.ico
├── index.html
├── main-es2015.js
├── main-es5.js
├── polyfills-es2015.js
├── polyfills-es5.js
├── runtime-es2015.js
├── runtime-es5.js
├── styles-es2015.js
├── styles-es5.js
├── vendor-es2015.js
└── vendor-es5.js

code splittingするように修正

  • code splittingするためにはmoduleを分ける必要があります
  • ルーティングごとにmoduleを作ります
    • すでにファイルがあるので今回は-fしてます
ng generate module home --module app --route home -f
ng generate module about --module app --route about -f
  • いくつかファイルが追加されました
% tree src/app/
src/app/
├── app-routing.module.ts
├── app.component.ts
├── app.module.ts
├── about
│   ├── about-routing.module.ts
│   ├── about.component.ts
│   └── about.module.ts
└── home
    ├── home-routing.module.ts
    ├── home.component.ts
    └── home.module.ts
  • ルーティングの設定の確認と修正をします
    • 修正前のRoutesの設定が残っているので削除します
    • 自動でmoduleを非同期に読み込む行が追加されています
src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';

// ここを以下のように変更
const routes: Routes = [
  { path: '', loadChildren: () => import('./home/home.module').then(m => m.HomeModule) },
  { path: 'about', loadChildren: () => import('./about/about.module').then(m => m.AboutModule) },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}
  • こうすることでbuild時にcode splittingされるようになります
  • ビルドして確認してみます
npm run build
  • Routing単位にファイルが生成されてることが確認できます
# mapファイルは省略
% tree dist
dist
└── ng-code-splitting-sample
    ├── about-about-module-es2015.js
    ├── about-about-module-es5.js
    ├── favicon.ico
    ├── home-home-module-es2015.js
    ├── home-home-module-es5.js
    ├── index.html
    ├── main-es2015.js
    ├── main-es5.js
    ├── polyfills-es2015.js
    ├── polyfills-es5.js
    ├── runtime-es2015.js
    ├── runtime-es5.js
    ├── styles-es2015.js
    ├── styles-es5.js
    ├── vendor-es2015.js
    └── vendor-es5.js

まとめ

  • コンポーネントの作り方を少し変えるだけでRouting単位にcode splittingすることができました
  • 設定ファイルなどいじらずできるのがいいですね

参考記事

https://web.dev/route-level-code-splitting-in-angular/

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした