Angularでの遅延ロード実装

## 追記

※この記事の書き方よりこちらの方が適切です
→　[[Ionic]lazyLoadのルーティング書き方メモ[Angular]](https://qiita.com/pg_yamaton/items/8462b5475438eebd3cb9)

## この記事の概要

Angularの遅延ロードの実装をしたくて試行錯誤して動作確認までできたので備忘録
ついでにこちらの記事を参考にフォルダ構成を律儀に細分化してみた
https://itnext.io/choosing-a-highly-scalable-folder-structure-in-angular-d987de65ec7

## バージョン

```json:package.json
"@angular/common": "~8.2.14"
"@angular/compiler": "~8.2.14"
"@angular/core": "~8.2.14"
"@angular/router": "~8.2.14"
"typescript": "~3.5.3"
```

## フォルダ構成※ルーティングに関係あるところだけ抜粋

```
src
┣ app
┃ ┣ core
┃ ┃ ┗ auth
┃ ┃ 　┣ login
┃ ┃ 　┃ ┗ login.component.html/scss/spec.ts/ts
┃ ┃ 　┣ auth-routing.module.ts
┃ ┃ 　┣ auth.guard.ts
┃ ┃ 　┗ auth.module.ts
┃ ┣ modules
┃ ┃ ┣ homes
┃ ┃ ┃ ┣ pages
┃ ┃ ┃ ┃ ┗ homes
┃ ┃ ┃ ┃　 ┗ home.component.html/scss/spec.ts/ts
┃ ┃ ┃ ┣ homes-routing.module.ts
┃ ┃ ┃ ┗ homes.module.ts
┃ ┃ ┗ puroducts
┃ ┃ 　 ┣ pages
┃ ┃ 　 ┃ ┣ puroduct-new
┃ ┃ 　 ┃ ┃ ┗ puroduct-new.component.html/scss/spec.ts/ts
┃ ┃ 　 ┃ ┣ puroduct-edit
┃ ┃ 　 ┃ ┃ ┗ puroduct-edit.component.html/scss/spec.ts/ts
┃ ┃ 　 ┃ ┣ puroduct-view
┃ ┃ 　 ┃ ┃ ┗ puroduct-view.component.html/scss/spec.ts/ts
┃ ┃ 　 ┃ ┗ puroduct-list
┃ ┃ 　 ┃　 ┗ puroduct-list.component.html/scss/spec.ts/ts
┃ ┃ 　 ┣ homes-routing.module.ts
┃ ┃ 　 ┗ homes.module.ts
┃ ┣ app-routing.module.ts
┃ ┣ app.component.html/scss/spec.ts/ts
┃ ┗ app.module.ts
┗ index.html
```

小規模プロジェクトならここまで細分化しなくて良いと思われ
実案件がかなり大規模になってきてファイルを探すのが大変になったのでこの分け方を導入しようか検討中

## ルーティング実装

```html:src/index.html

<!-- 〜略〜 -->
  <body>
    <app-root></app-root>
  </body>
<!-- 〜略〜 -->
```

```html:src/app/app.component.html
<!-- 〜略〜 -->
  <router-outlet></router-outlet>
<!-- 〜略〜 -->
```

```typescript:src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        AppRoutingModule,
        AuthModule.forRoot() // Authは遅延にしない
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }
```

```typescript:src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const appRoutes: Routes = [
    {
        path: 'home',
        loadChildren: () => import('./modules/homes/homes.module').then(m => m.HomesModule),
        canActivate: [AuthGuard]
    },
    {
        path: 'products',
        loadChildren: () => import('./modules/products/products.module').then(m => m.ProductsModule),
        canActivate: [AuthGuard]
    },
    // ↓こいつを先頭に記述すると全て「/」になってしまったので注意
    {
        path: '**',
        redirectTo: '/',
    }
];

@NgModule({
    imports: [
        RouterModule.forRoot(appRoutes)
    ],
    exports: [RouterModule]
})
export class AppRoutingModule { }
```
遅延ロードの実装方法は公式ドキュメント通り
https://angular.jp/guide/lazy-loading-ngmodules

### ここから個別のモジュール

#### ログイン

```typescript:src/app/core/auth/auth.module.ts
import { CommonModule } from '@angular/common';
import { ModuleWithProviders, NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { AuthRoutingModule } from './auth-routing.module';
import { AuthGuard } from './auth.guard';
import { LoginComponent } from './login/login.component';

@NgModule({
    declarations: [
        LoginComponent
    ],
    imports: [
        CommonModule,
        ReactiveFormsModule,
        AuthRoutingModule
    ],
    exports: [LoginComponent]
})
export class AuthModule {
    static forRoot(): ModuleWithProviders {
        return {
            ngModule: AuthModule,
            providers: [
                AuthGuard
            ]
        };
    }
}
```

```typescript:src/app/core/auth/auth-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './login/login.component';

const authRoutes: Routes = [
    {
        path: '',
        component: LoginComponent,
    }
];

@NgModule({
    imports: [RouterModule.forChild(authRoutes)],
    exports: [RouterModule],
})
export class AuthRoutingModule {}
```

#### home

```typescript:src/app/modules/homes/homes.module.ts
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { HomesRoutingModule } from './homes-routing.module';
import { HomeComponent } from './pages/home/home.component';

@NgModule({
    declarations: [
        HomeComponent
    ],
    imports: [
        CommonModule,
        HomesRoutingModule
    ],
    providers: [],
    bootstrap: []
})
export class HomesModule { }
```

```typescript:src/app/modules/homes/homes-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './pages/home/home.component';

const homeRoutes: Routes = [
    {
        path: '',
        component: HomeComponent
    }
];

@NgModule({
    imports: [RouterModule.forChild(homeRoutes)],
    exports: [RouterModule]
})
export class HomesRoutingModule { }
```

#### product

```typescript:src/app/modules/products/products.module.ts
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { ProductEditComponent } from './pages/product-edit/product-edit.component';
import { ProductViewComponent } from './pages/product-view/product-view.component';
import { ProductNewComponent } from './pages/product-new/product-new.component';
import { ProductListComponent } from './pages/product-list/product-list.component';
import { ProductsRoutingModule } from './products-routing.module';

@NgModule({
    declarations: [
        ProductEditComponent,
        ProductViewComponent,
        ProductNewComponent,
        ProductListComponent
    ],
    imports: [
        CommonModule,
        ProductsRoutingModule
    ],
    providers: [],
    bootstrap: []
})
export class ProductsModule { }
```

```typescript:src/app/modules/homes/homes-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './pages/home/home.component';

const productRoutes: Routes = [
    {
        path: '',
        children: [
            {
                path: '', // またはpath: 'list'
                component: ProductListComponent
            },
            {
                path: 'new',
                component: ProductNewComponent
            },
            {
                path: 'edit/:id',
                component: ProductEditComponent
            },
            {
                path: 'view/:id',
                component: ProductViewComponent
            }
        ]
    }
];

@NgModule({
    imports: [RouterModule.forChild(productRoutes)],
    exports: [RouterModule]
})
export class ProductsRoutingModule { }
```

childrenの実装方法
https://angular.jp/guide/router#child-route-configuration