【问题标题】:Importing a lazy-loaded module with routes in a module with a route breaks routing在具有路由的模块中导入具有路由的延迟加载模块会中断路由
【发布时间】:2019-08-19 18:08:46
【问题描述】:

我们的 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]
      }
}

我们确实有一个 shared 模块,其中包含在整个应用程序中使用的通用组件(我们有很多)。但是,有些组件(如模态)仅由 MaintenanceProgramCar 模块共享,但在其他任何地方都不使用。

为了保持共享模块的合理性,我只在MaintenanceProgram 模块中包含这些曾经重用的组件,导出它们,然后将MaintenanceProgram 模块导入Car 模块以访问导出的组件。

CarMaintenanceProgram 模块都在各自的@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. 到模块嵌入

因为当我加载 Car 路线时,我得到了维护程序的默认路线

我试过了:

  1. 更改CarModule@NgModule.imports[]MaintenanceProgramModuleRoutesCarModuleRoutes的导入顺序,
  2. 从 CarModule 中删除空路径。

*是创建另一个共享模块的唯一解决方案,该模块包含共享组件而无需路由器,还是有另一种更优雅的方法来做到这一点?*

这是一个简化的例子,我们实际上有很多路由和数百个组件,它们只被重用了两到三次。随着应用程序的增长,这个问题肯定会持续到未来,所以我需要一个可扩展且可维护的解决方案。创建数十个或更多额外的共享模块是不可行的。

【问题讨论】:

  • 我认为您正在进入的是循环依赖,模块 A 使用 B,而 B 使用 C。但是C再次使用A。我今天回答了这样一个问题可能是this帮助
  • 这里都将调用'' const routes: Routes = [ { path: '', redirectTo: 'fleet', pathMatch: 'full' }, { path: '',跨度>
  • 嗨@RahulSingh,我在ng-cli 中启用了--show-circular-dependencies,但没有收到报告。我会仔细检查..
  • @AniruddhaDas 这不是我的问题所在。当我登陆应用程序 root(root path:'')时,我得到了 Fleet 页面。当我导航到/car/:id 时,我得到了维护程序。
  • @AniruddhaDas 或者这可能是我的问题,但如果是的话,我不明白它的影响或如何解决它。

标签: angular lazy-loading angular-router


【解决方案1】:

实际上,在创建共享模块时,不需要关心使用了共享模块一小部分的模块,因为 Angular 的 tree-shaking 将只保留导入模块中使用的代码,并删除其余部分。

我准备了一个最小的项目来演示它:https://github.com/youkouleley/Angular-treeshaking-demo

这个项目有两个惰性模块:AModuleBModule。这两个模块都导入SharedModuleSharedModule 导出三个组件:

  • AComponent 用于AModule
  • BComponent 用于BModule
  • BothComponent 用于AModule BModule

这是您在生产模式下ng building 这个项目并打开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() {}
        }
      }
    }
  ]);

请注意,SharedModule 中的 BComponentAModule 块中缺失。同样适用于不包括 AComponentBModule 块。

另外,请注意,在构建选项中将commonChunk 设置为false 时会获得此行为。此选项允许您选择:

  • false:将SharedModule 的所需部分直接捆绑到导入它的惰性模块中。 专业版: 甚至延迟模块之间的加载时间。 缺点:来自SharedModule 的一些代码在惰性模块块之间重复,整体应用程序大小更大
  • true(默认):有一个公共块,其中包含 SharedModule 的部分,至少被两个惰性模块使用(其余的被捆绑到惰性模块本身中)。 专业版: 没有重复代码,应用程序整体较小。 缺点:第一个惰性模块加载速度较慢(即使当前路由不需要它,它也会加载公共块)

作为结论,Angular 构建为 SharedModule 提供了优化,将 commonChunk 设置为 truefalse(取决于您的上下文)您不必担心您的 SharedModule 大小.因此,您不必像以前那样尝试奇怪的模式,混合模块同时履行功能模块角色和共享模块角色。

【讨论】:

    【解决方案2】:

    在顶级应用路由器中试试这个:

    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

    【讨论】:

      【解决方案3】:

      我用来处理大型共享模块的方式是为每个组件创建一个模块。在您的示例中,您应该创建一个ModalModule,声明并导出您的ModalComponent。它应该看起来像这样

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

      然后在您的 CarModule 导入中简单地包含 ModalModuleMaintenanceProgramModule 导入。

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

      您应该为所有共享组件创建模块,并且只将每个共享组件的模块包含在需要它的路由中。它确实有助于大大减小每个页面的大小。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-12-07
        • 2017-08-21
        • 1970-01-01
        • 1970-01-01
        • 2020-01-12
        • 1970-01-01
        • 2017-12-07
        • 2019-04-03
        相关资源
        最近更新 更多