Angular技术问题:如何在根模块中加载JIT编译的动态模块
嘿,我完全理解你被这个问题卡三天的痛苦——我之前在做动态组件路由的时候也踩过一模一样的坑!其实核心问题在于:JIT编译的动态模块没法像静态模块那样直接用loadChildren,但我们可以通过手动合并路由配置+正确处理模块注入器来解决。
下面是具体的解决方案,分步骤来:
1. 调整动态模块的配置
首先,我们可以把动态模块里的RouterModule.forChild暂时移除(或者保留,但后续手动提取路由),让模块专注于声明动态组件和提供服务:
let dynaModule = NgModule({ declarations: dyna_comps, exports: dyna_comps, imports: [CommonModule], // 去掉RouterModule.forChild,我们手动处理路由 providers: [GlobalService] })(class { });
2. 编译模块并合并路由
编译完成后,我们已经得到了编译好的组件类型(dyna_comps里的类),这时候可以直接把它们的路由条目合并到根路由配置中,同时创建模块引用以确保服务能被组件访问:
this.compiler.compileModuleAndAllComponentsAsync(dynaModule) .then((factories) => { // 1. 创建动态模块的引用,用于获取模块内的注入器和服务 const moduleRef = factories.moduleFactory.create(this.injector); // 2. 定义动态组件的路由(和你之前在forChild里写的一致) const dynamicRoutes = [ { path: 'cc1', component: dyna_comps[0] }, { path: 'cc2', component: dyna_comps[1] } // 如果需要前缀,可以套一层children: // { path: 'dynamic', children: [/* 上面的路由 */] } ]; // 3. 合并到根路由配置,和你处理静态模块的方式类似 this.router.resetConfig([ ...this.router.config, ...dynamicRoutes ]); // 4. 创建动态组件实例时,使用模块的注入器(而不是根注入器),确保能拿到GlobalService for (let i = 0; i < factories.componentFactories.length; i++) { const f = factories.componentFactories[i]; this.cmpRef = f.create(moduleRef.injector, [], null, moduleRef); this.cmpRef.instance.name = 'DCOMP' + i; // 记得把组件实例挂载到DOM(如果需要的话) // document.body.appendChild(this.cmpRef.location.nativeElement); } });
关键注意点
- 不要用
loadChildren处理JIT模块:loadChildren是为预编译的静态模块设计的,JIT编译的模块已经在内存中,直接用组件类型配置路由即可。 - 使用模块注入器:如果动态组件依赖模块内的服务(比如你的
GlobalService),一定要用模块引用的注入器创建组件,否则组件会找不到服务。 - 路由合并的时机:确保在编译完成后再合并路由,否则Angular会因为组件未编译而报错。
这样操作后,你就能通过路由访问到JIT编译的动态组件了,和静态模块的路由体验一致!
内容的提问来源于stack exchange,提问作者user2894836
相关产品推荐
相关产品推荐

