Импорт лениво загруженного модуля с маршрутами в модуль с маршрутом прерывает маршрутизацию

В нашем приложении angular 4.3.6 есть модули с ленивой загрузкой, такие как Fleet, Maintenance, Car и т. д.

Мой маршрутизатор приложений верхнего уровня выглядит так:

const routes: Routes = [
  { path: '', redirectTo: 'fleet', pathMatch: 'full' },
  {
    path: '',
    component: AppComponent,
    canActivate: [AuthenticationGuard],
    children: [
      {
        path: 'fleet',
        loadChildren: "./modules/fleet.module",
        canActivate: [AuthenticationGuard]
      },
      {
        path: 'car/:id',
        loadChildren: "./modules/car.module",
        canActivate: [AuthenticationGuard]
      },
      {
        path: 'maintenanceProgram',
        loadChildren: "./modules/maintenanceProgram.module",
        canActivate: [AuthenticationGuard]
      }
}

У нас есть общий модуль с общими компонентами (у нас их много), используемыми во всем приложении. Однако есть некоторые компоненты, такие как модальные окна, которые используются только модулями MaintenanceProgram и Car, но больше нигде не используются.

Чтобы сохранить общий модуль разумным, я включаю эти когда-то повторно используемые компоненты только в модуль MaintenanceProgram, экспортирую их и импортирую модуль MaintenanceProgram в модуль Car, чтобы иметь доступ к экспортированным компонентам.

Оба модуля Car и MaintenanceProgram имеют следующие встроенные дочерние маршруты, вызываемые в соответствующих модулях @NgModule.imports[]:

Автомобиль:

const CarModuleRoutes = RouterModule.forChild([
  {
    path: '',
    component: CarComponent,
    canActivate: [AuthenticationGuard]
  },
  {
    path: ':id',
    component: CarComponent,
    canActivate: [AuthenticationGuard]
  }
]);

и программа обслуживания:

const MaintenanceProgramModuleRoutes = RouterModule.forChild([
  {
    path: '',
    component: MaintenanceProgramComponent,
    canActivate: [AuthenticationGuard]
  }
]);

Это тоже явно не правильный подход

  1. к дочерней маршрутизации или
  2. к включению модуля

потому что, когда я загружаю автомобильный маршрут, я получаю маршрут по умолчанию программы обслуживания.

Я пытался:

  1. Изменение порядка импорта MaintenanceProgramModuleRoutes и CarModuleRoutes в @NgModule.imports[] CarModule,
  2. Удаление пустого пути из CarModule.

*Единственным решением является создание еще одного общего модуля, содержащего общие компоненты, без маршрутизатора, или есть другой, более элегантный способ сделать это?*

Это упрощенный пример, на самом деле у нас есть много маршрутов и сотни компонентов, которые повторно используются только два или три раза. Эта проблема наверняка сохранится в будущем по мере роста приложения, поэтому мне нужно масштабируемое и удобное в сопровождении решение. Создание десятков и более дополнительных общих модулей просто невозможно.


person msanford    schedule 01.09.2017    source источник
comment
я думаю, что вы попадаете в циклическую зависимость, модуль A использует B, а B использует C. но снова C использует A. Сегодня я ответил на такой вопрос, может быть это помогает   -  person Rahul Singh    schedule 01.09.2017
comment
здесь оба будут вызываться для '' const маршрутов: Routes = [ { path: '', redirectTo: 'fleet', pathMatch: 'full' }, { path: '',   -  person Aniruddha Das    schedule 01.09.2017
comment
Привет @RahulSingh, я включил --show-circular-dependencies в ng-cli и не получил об этом отчет. я перепроверю..   -  person msanford    schedule 01.09.2017
comment
@AniruddhaDas Моя проблема не в этом. Когда я попадаю в приложение root (корень path:''), я получаю страницу флота. Когда я перехожу к /car/:id, я получаю программу обслуживания.   -  person msanford    schedule 01.09.2017
comment
@AniruddhaDas Или, возможно, это моя проблема, но если это так, я не понимаю, каков ее эффект и как ее решить.   -  person msanford    schedule 01.09.2017
comment
@msanford Есть ли решение?   -  person Domi    schedule 12.08.2019
comment
разве это не должно быть просто car для вашего маршрутизатора приложений верхнего уровня, а не car/:id? Вы указываете id в дочерних маршрутах   -  person Andrew Allen    schedule 12.08.2019
comment
@AndrewAllen Неплохое предложение в качестве лучшей практики. Между прочим, car:/id работает в нашем случае, потому что это своего рода не дочерний маршрут: под car/ больше ничего нет. Не стесняйтесь дать ответ и получить эту награду! Если нет, возможно, я опубликую наше возможное решение (но сейчас я работаю над другим проектом, поэтому мне нужно его выкопать).   -  person msanford    schedule 13.08.2019


Ответы (3)


На самом деле, при создании общего модуля не нужно заботиться о модулях, которые используют небольшую часть общего модуля, потому что встряхивание дерева Angular сохранит только используемый код из импортированного модуля и удалит остальное.

Я подготовил минимальный проект, чтобы продемонстрировать это: https://github.com/youkouleley/Angular-treeshaking-demo

В этом проекте есть два ленивых модуля: AModule и BModule. Оба этих модуля импортируют SharedModule. SharedModule экспортирует три компонента:

  • AComponent, который используется AModule только
  • BComponent, который используется BModule только
  • BothComponent, который используется в AModule и BModule

Вот что вы получите, когда ng buildзапустите этот проект в рабочем режиме и откроете файл 4-es2015.<hash>.js:

(window.webpackJsonp = window.webpackJsonp || []).push([[4], {
      KImX: function (n, l, u) {
        "use strict";
        u.r(l);
        var t = u("8Y7J");
        class a {
          constructor() {}
          ngOnInit() {}
        }
        var r = u("phyl");
        class o {}
        var c = u("pMnS"),
        s = t.gb({
            encapsulation: 0,
            styles: [[""]],
            data: {}
          });
        function b(n) {
          return t.sb(0, [(n()(), t.ib(0, 0, null, null, 1, "p", [], null, null, null, null, null)), (n()(), t.rb(-1, null, ["a works!"]))], null, null)
        }
        function i(n) {
          return t.sb(0, [(n()(), t.ib(0, 0, null, null, 1, "app-a", [], null, null, null, b, s)), t.hb(1, 114688, null, 0, a, [], null, null)], function (n, l) {
            n(l, 1, 0)
          }, null)
        }
        var p = t.eb("app-a", a, i, {}, {}, []),
        e = u("gJxL"),
        f = u("SVse"),
        h = u("iInd"),
        d = u("PCNd");
        u.d(l, "AModuleNgFactory", function () {
          return v
        });
        var v = t.fb(o, [], function (n) {
            return t.ob([t.pb(512, t.j, t.T, [[8, [c.a, p, e.a]], [3, t.j], t.u]), t.pb(4608, f.i, f.h, [t.r, [2, f.o]]), t.pb(1073742336, f.b, f.b, []), t.pb(1073742336, h.l, h.l, [[2, h.q], [2, h.k]]), t.pb(1073742336, d.a, d.a, []), t.pb(1073742336, o, o, []), t.pb(1024, h.i, function () {
                  return [[{
                        path: "a",
                        component: a
                      }, {
                        path: "both",
                        component: r.a
                      }
                    ]]
                }, [])])
          })
      },
      PCNd: function (n, l, u) {
        "use strict";
        u.d(l, "a", function () {
          return t
        });
        class t {}
      },
      gJxL: function (n, l, u) {
        "use strict";
        var t = u("8Y7J"),
        a = u("phyl");
        u.d(l, "a", function () {
          return s
        });
        var r = t.gb({
            encapsulation: 0,
            styles: [[""]],
            data: {}
          });
        function o(n) {
          return t.sb(0, [(n()(), t.ib(0, 0, null, null, 1, "p", [], null, null, null, null, null)), (n()(), t.rb(-1, null, ["both works!"]))], null, null)
        }
        function c(n) {
          return t.sb(0, [(n()(), t.ib(0, 0, null, null, 1, "app-both", [], null, null, null, o, r)), t.hb(1, 114688, null, 0, a.a, [], null, null)], function (n, l) {
            n(l, 1, 0)
          }, null)
        }
        var s = t.eb("app-both", a.a, c, {}, {}, [])
      },
      phyl: function (n, l, u) {
        "use strict";
        u.d(l, "a", function () {
          return t
        });
        class t {
          constructor() {}
          ngOnInit() {}
        }
      }
    }
  ]);

Обратите внимание, что BComponent из SharedModule отсутствует в чанке AModule. Sames подходит для фрагмента BModule, который исключает AComponent.

Также обратите внимание, что такое поведение достигается при установке commonChunk на false в параметрах сборки. Эта опция позволяет вам выбирать между:

  • false: Объедините необходимые части SharedModule непосредственно в ленивые модули, которые его импортировали. За: равномерное время загрузки между ленивыми модулями. Против: некоторый код из SharedModule дублируется между блоками ленивых модулей, что увеличивает общий размер приложения.
  • true (по умолчанию): иметь общий фрагмент, содержащий части SharedModule, которые используются как минимум двумя ленивыми модулями (остальные входят в состав самих ленивых модулей). За: отсутствие дублированного кода, меньший общий размер приложения. Против: первый ленивый модуль загружается медленнее (он загружает общий фрагмент, даже если он не нужен текущему маршруту).

В заключение, сборка Angular обеспечивает оптимизацию для SharedModule с commonChunk, установленным либо на true, либо на false (в зависимости от вашего контекста), вам не нужно беспокоиться о размере SharedModule. Таким образом, вам не нужно пробовать странные шаблоны, как вы делали, с гибридными модулями, выполняющими роль функционального модуля и роль общего модуля одновременно.

person Guerric P    schedule 14.08.2019

Попробуйте это в маршрутизаторе приложений верхнего уровня:

const routes: Routes = [
  { path: '', redirectTo: 'fleet', pathMatch: 'full' },
  {
    path: '',
    component: AppComponent,
    canActivate: [AuthenticationGuard],
    children: [
      {
        path: 'fleet',
        loadChildren: "./modules/fleet.module#FleetModule",
        canActivate: [AuthenticationGuard]
      },
      {
        path: 'car/:id',
        loadChildren: "./modules/car.module#CarModule",
        canActivate: [AuthenticationGuard]
      },
      {
        path: 'maintenanceProgram',
        loadChildren: "./modules/maintenanceProgram.module#MaintenanceProgrammodule",
        canActivate: [AuthenticationGuard]
      }
}

Необходимое изменение: добавьте #module_class_name в конец пути к маршрутизатору.

person Hasan Fathi    schedule 18.08.2019

Способ, который я использую для работы с большими общими модулями, заключается в создании модуля для каждого компонента. В вашем примере вы должны создать ModalModule, объявить и экспортировать свой ModalComponent. Это должно выглядеть примерно так

@NgModule({
  declarations: [
    ModalComponent,
  ],
  imports: [
    RouterModule,
    CommonModule, // any modules that your modal need
  ],
  exports: [
    ModalComponent,
  ]
})
export class ModalModule {}

Затем просто включите ModalModule в импорт CarModule и MaintenanceProgramModule в импорт.

@NgModule({
  declarations: [CarComponent],
  imports: [ CarRoutingModule, ModalModule ],
})
export class CarModule

Вы должны создать модуль для всех общих компонентов и включать только модуль каждого общего компонента в маршрут, который в нем нуждается. Это помогает значительно уменьшить размер каждой страницы.

person Rinne Hmm    schedule 19.08.2019