在带有路由的模块中导入带有路由的延迟加载模块会中断路由
Importing a lazy-loaded module with routes in a module with a route breaks routing
我们的angular4.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 模块,其中包含在整个应用程序中使用的通用组件(我们有很多)。但是,有些组件(例如模态框)仅由 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]
}
]);
这显然也不是正确的方法
- 到子路由,或
- 到模块嵌入
因为我加载Car路线的时候,得到的是Maintenance Program的默认路线.
我试过:
- 更改
MaintenanceProgramModuleRoutes
和 CarModuleRoutes
在 CarModule
的 @NgModule.imports[]
、 中的导入顺序
- 正在从 CarModule 中删除空路径。
*创建 另一个 共享模块的唯一解决方案是在没有路由器的情况下包含共享组件,还是有其他更优雅的方法来做到这一点?*
这是一个简化的例子,我们实际上有很多路由和数百个组件,它们只被重用了两三次。随着应用程序的增长,这个问题肯定会持续到未来,所以我需要一个可扩展和可维护的解决方案。创建数十个或更多额外的共享模块是不可行的。
实际上,在创建共享模块时,不需要关心使用共享模块的一小部分的模块,因为Angular的tree-shaking只会保留使用过的代码导入模块,并删除其余部分。
我准备了一个最小的项目来演示它: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() {}
}
}
}
]);
请注意,SharedModule
中的 BComponent
在 AModule
块中缺失。 Sames 用于排除 AComponent
.
的 BModule
块
此外,请注意,在构建选项中将 commonChunk
设置为 false
时会出现此行为。此选项允许您在以下选项之间进行选择:
false
:将 SharedModule
的所需部分直接捆绑到导入它的惰性模块中。 Pro: 延迟模块之间的加载时间均匀。 缺点: SharedModule
中的一些代码在惰性模块块之间重复,总体应用程序大小较大
true
(默认):有一个公共块,其中包含 SharedModule
的部分 至少 被两个惰性模块( rest 被捆绑到惰性模块本身)。 专业版: 没有重复代码,整体应用体积更小。 缺点:第一个惰性模块加载速度较慢(即使当前路由不需要它,它也会加载公共块)
作为结论,Angular 构建为 SharedModule
提供了优化,其中 commonChunk
设置为 true
或 false
(取决于您的上下文)您真的不必担心您的 SharedModule
尺码。因此,您不必像以前那样尝试奇怪的模式,混合模块同时履行功能模块角色和共享模块角色。
在顶级应用路由器中试试这个:
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]
}
}
Your needed change: add #module_class_name
in end of router path.
我用来处理大共享模块的方法是为每个组件创建一个模块。在您的示例中,您应该创建一个 ModalModule
,声明并导出您的 ModalComponent
。它应该看起来像这样
@NgModule({
declarations: [
ModalComponent,
],
imports: [
RouterModule,
CommonModule, // any modules that your modal need
],
exports: [
ModalComponent,
]
})
export class ModalModule {}
然后只需在您的 CarModule 导入和 MaintenanceProgramModule
导入中包含 ModalModule
。
@NgModule({
declarations: [CarComponent],
imports: [ CarRoutingModule, ModalModule ],
})
export class CarModule
您应该为所有共享组件创建模块,并且只在需要它的路由中包含每个共享组件的模块。它确实有助于大大减少每页的大小。
我们的angular4.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 模块,其中包含在整个应用程序中使用的通用组件(我们有很多)。但是,有些组件(例如模态框)仅由 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]
}
]);
这显然也不是正确的方法
- 到子路由,或
- 到模块嵌入
因为我加载Car路线的时候,得到的是Maintenance Program的默认路线.
我试过:
- 更改
MaintenanceProgramModuleRoutes
和CarModuleRoutes
在CarModule
的@NgModule.imports[]
、 中的导入顺序
- 正在从 CarModule 中删除空路径。
*创建 另一个 共享模块的唯一解决方案是在没有路由器的情况下包含共享组件,还是有其他更优雅的方法来做到这一点?*
这是一个简化的例子,我们实际上有很多路由和数百个组件,它们只被重用了两三次。随着应用程序的增长,这个问题肯定会持续到未来,所以我需要一个可扩展和可维护的解决方案。创建数十个或更多额外的共享模块是不可行的。
实际上,在创建共享模块时,不需要关心使用共享模块的一小部分的模块,因为Angular的tree-shaking只会保留使用过的代码导入模块,并删除其余部分。
我准备了一个最小的项目来演示它: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() {}
}
}
}
]);
请注意,SharedModule
中的 BComponent
在 AModule
块中缺失。 Sames 用于排除 AComponent
.
BModule
块
此外,请注意,在构建选项中将 commonChunk
设置为 false
时会出现此行为。此选项允许您在以下选项之间进行选择:
false
:将SharedModule
的所需部分直接捆绑到导入它的惰性模块中。 Pro: 延迟模块之间的加载时间均匀。 缺点:SharedModule
中的一些代码在惰性模块块之间重复,总体应用程序大小较大true
(默认):有一个公共块,其中包含SharedModule
的部分 至少 被两个惰性模块( rest 被捆绑到惰性模块本身)。 专业版: 没有重复代码,整体应用体积更小。 缺点:第一个惰性模块加载速度较慢(即使当前路由不需要它,它也会加载公共块)
作为结论,Angular 构建为 SharedModule
提供了优化,其中 commonChunk
设置为 true
或 false
(取决于您的上下文)您真的不必担心您的 SharedModule
尺码。因此,您不必像以前那样尝试奇怪的模式,混合模块同时履行功能模块角色和共享模块角色。
在顶级应用路由器中试试这个:
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]
}
}
Your needed change: add
#module_class_name
in end of router path.
我用来处理大共享模块的方法是为每个组件创建一个模块。在您的示例中,您应该创建一个 ModalModule
,声明并导出您的 ModalComponent
。它应该看起来像这样
@NgModule({
declarations: [
ModalComponent,
],
imports: [
RouterModule,
CommonModule, // any modules that your modal need
],
exports: [
ModalComponent,
]
})
export class ModalModule {}
然后只需在您的 CarModule 导入和 MaintenanceProgramModule
导入中包含 ModalModule
。
@NgModule({
declarations: [CarComponent],
imports: [ CarRoutingModule, ModalModule ],
})
export class CarModule
您应该为所有共享组件创建模块,并且只在需要它的路由中包含每个共享组件的模块。它确实有助于大大减少每页的大小。