You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.17 02:45:05