Angular 12 实现可连接插件:后端按需动态加载模块方案咨询
Angular 非路由场景手动懒加载工具模块实现方案
以下两种方案均适配你的场景,无需依赖路由懒加载,也不需要使用已废弃的 entryComponents 配置:
方案1:模块内置在前端构建产物,后端仅返回模块加载标识
适合模块代码在前端项目中维护,后端仅根据用户权限返回可用工具列表的场景:
- 第一步:将每个工具对应的服务、组件封装为独立的 NgModule,无需做额外配置,Angular Ivy 编译模式默认支持所有组件动态创建
- 第二步:封装工具加载服务,根据后端返回的工具标识动态导入对应模块,示例代码如下:
import { Injectable, Compiler, Injector, NgModuleFactory } from '@angular/core'; import { ConnectableTool, TOOL } from './tool.interface'; @Injectable({ providedIn: 'root' }) export class ToolLoaderService { // 工具标识和模块导入方法的映射,可从后端拉取配置动态更新 private toolModuleMap = new Map([ ['selection', () => import('./tools/selection/ct-selection.module').then(m => m.CtSelectionModule)] ]); private loadedTools = new Map<string, ConnectableTool>(); constructor( private compiler: Compiler, private injector: Injector ) {} async loadTool(toolKey: string): Promise<ConnectableTool> { // 已加载过的工具直接返回缓存 if (this.loadedTools.has(toolKey)) { return this.loadedTools.get(toolKey)!; } const loadModule = this.toolModuleMap.get(toolKey); if (!loadModule) throw new Error('无效的工具标识'); // 加载并编译模块 const moduleClass = await loadModule(); const moduleRef = moduleClass instanceof NgModuleFactory ? moduleClass.create(this.injector) : this.compiler.compileModuleSync(moduleClass).create(this.injector); // 从模块注入器中获取工具服务实例,建议所有工具模块统一用TOOL令牌提供服务,无需硬编码类名 const toolInstance = moduleRef.injector.get<ConnectableTool>(TOOL); this.loadedTools.set(toolKey, toolInstance); return toolInstance; } }
- 对应工具模块的示例配置:
import { NgModule } from '@angular/core'; import { TOOL } from '../tool.interface'; import { CtSelectionTool } from './ct-selection.tool'; import { CtSelectionToolComponent } from './ct-selection-tool.component'; @NgModule({ declarations: [CtSelectionToolComponent], providers: [ { provide: TOOL, useClass: CtSelectionTool } ] }) export class CtSelectionModule {}
- 工具加载完成后,你可以直接用已有的组件工厂逻辑动态创建
toolInstance.plotterComponent对应的组件即可。
方案2:模块完全存储在后端服务器
适合工具模块作为独立资源托管在后端,前端完全按需拉取的场景:
- 第一步:将每个工具模块作为独立 Angular 库进行构建,输出为 ESM 或 UMD 格式的独立 chunk,上传到后端静态资源存储
- 第二步:前端需要加载工具时,动态创建
script标签拉取对应 chunk,加载完成后从全局作用域拿到导出的 NgModule 类,后续编译、注入、组件创建逻辑和方案1完全一致 - 注意点:工具库构建使用的 Angular 版本需要和主应用完全一致,避免编译产物不兼容导致运行错误。
简化方案(Angular 14+ 推荐)
如果你的项目使用 Angular 14 及以上版本,可以直接将工具服务、组件声明为 standalone 独立单元,无需封装 NgModule,加载逻辑可以进一步简化:
async loadStandaloneTool(toolKey: string) { const { CtSelectionTool } = await import('./tools/selection/ct-selection.tool.ts'); return new CtSelectionTool(); }
创建组件时直接调用ViewContainerRef.createComponent(CtSelectionToolComponent)即可,不需要模块编译流程。
内容的提问来源于stack exchange,提问作者Alex Teexone
相关产品推荐
相关产品推荐

