路由问题
情景介绍
在 remote 项目中进行路由跳转,并不能正确的跳转
搭建 Demo
remote 项目 创建一个 test.component
ng g c test --project remoteremote 项目 app-routing.module.ts 中设置路由
const routes: Routes = [
{
path: "test",
component: TestComponent,
},
];remote 项目 app.component.html 中跳转
<p>remote app works!</p>
<button routerLink="/test">navigate to test</button>
<router-outlet></router-outlet>起服务
点击 navigate to remote,可以看出,到现在没有问题

再点击 navigate to test,可以发现,页面没有变化,并且路由虽然变了,但是和预料当中的
/remote/test不一样,而是/test
至此,我们 Demo 搭建成功,接下来就是分析问题了
分析问题
从上面可以看出,主要是路由方面的问题,所以我们来监听一下 host 和 remote 的路由变化
在 remote 项目的 app.component.ts 中监听路由变化
import { NavigationEnd, Router } from '@angular/router';
import { filter } from 'rxjs';
constructor(
private router: Router
) {
this.router.events
.pipe(filter((event: any) => event instanceof NavigationEnd))
.subscribe((res) => {
console.log('remote', res);
});
}在 host 项目中创建一个 service(load-remote-root-module.service.ts),并在其中监听路由变化
tip为什么要创建 service?别问,问就是后面用的上
import { Injectable } from "@angular/core";
import { NavigationEnd, Router } from "@angular/router";
import { filter } from "rxjs";
@Injectable({
providedIn: "root",
})
export class LoadRemoteRootModuleService {
constructor(private router: Router) {
this.router.events
.pipe(filter((event: any) => event instanceof NavigationEnd))
.subscribe((res) => {
console.log("host", res);
});
}
}刷新页面,或者重启服务,为了方便展示,我加了些 log
可以看出,点击 navigate to remote 后,host 项目的路由监听到了,但是点击 navigate to test 后,host 路由并没有监听到

解决方案
host 项目需要知道 remote 项目的路由变化
remote 项目暴露出自己的路由
app.module.tsexport class AppModule {
static _router: any;
constructor(private router: Router) {
AppModule._router = this.router;
}
}host 项目接收 remote 项目的路由
在上一节讲到的 loadRemoteRootModule 方法中,加入获取并进行监听,setTimeout 是用来异步,要不然获取不到
const loadRemoteRootModule = (module: any) => {
setTimeout(() => {
(module.AppModule._router as Router).events
.pipe(filter((event: any) => event instanceof NavigationEnd))
.subscribe((res) => {
console.log(res);
});
});
......
return module.AppModule;
};
更改 loadRemoteRootModule 方法的位置,来获取 host 的 router
现在 host 项目能监听到 remote 的路由变化了,接下来就是重写路由并进行 navigateByUrl
但是,之前我们的loadRemoteRootModule方法是写在 app-routing.module.ts 中的,所以我们获取不到 host 项目的 router
还记得之前我让你创建的 load-remote-root-module.service.ts 吗,我们现在把loadRemoteRootModule方法,挪到这个 service 中
loadRemoteRootModule 挪到 load-remote-root-module.service.ts 中
load-remote-root-module.service.tsloadRemoteRootModule = (module: any) => {
setTimeout(() => {
(module.AppModule._router as Router).events
.pipe(filter((event: any) => event instanceof NavigationEnd))
.subscribe((res) => {
console.log(res);
});
});
......
return module.AppModule;
};app-routing.module.ts 中 使用 loadRemoteRootModule 这个方法会报错,也将他挪到 load-remote-root-module.service.ts 中
infothis.router.resetConfig 可以重置路由列表,所以我们可以通过这个方法进行路由设置
resetConfig() {
this.router.resetConfig([
{
path: "remote",
loadChildren: () =>
loadRemoteModule({
type: "module",
remoteEntry: "http://localhost:9001/remoteEntry.js",
exposedModule: "./AppModule",
}).then((module) => this.loadRemoteRootModule(module)),
},
...this.router.config
])
}
监听路由变化,进行路由重写
loadRemoteRootModule = (module: any, prefix: string) => {
setTimeout(() => {
(module.AppModule._router as Router).events
.pipe(filter((event: any) => event instanceof NavigationEnd))
.subscribe((res) => {
const url = res.url === '/' ? '' : res.url
this.router.navigateByUrl(`/${prefix}${url}`)
});
});
......
return module.AppModule;
};
resetConfig() {
this.router.resetConfig([
{
path: "remote",
loadChildren: () =>
loadRemoteModule({
type: "module",
remoteEntry: "http://localhost:9001/remoteEntry.js",
exposedModule: "./AppModule",
}).then((module) => this.loadRemoteRootModule(module, 'remote')),
},
...this.router.config
])
}
试验解决方案
从图中可以看出,先后点击 navigate to remote 和 navigate to remote 之后,页面成功展示
