Angular App 无需重新编译即可动态加载插件

Posted

技术标签:

【中文标题】Angular App 无需重新编译即可动态加载插件【英文标题】:Angular App dynamically load plugin without recompile 【发布时间】:2020-06-18 04:59:48 【问题描述】:

我正在尝试开发我的 Web Api (NET CORE) 可插件应用程序的前端。我想使用 Angular 9,但我不是 Angular 专家。

我的后端被设计为可扩展的,在启动时它会在指定的文件夹中监视,如果存在一个或多个包含扩展基本应用程序(如插件)的逻辑的 dll 文件,它会加载它们。 我想在前端使用类似的方法。我尝试了不同的解决方案并阅读了很多文章,但很难找到想要在编译时导入未知插件的人。

我尝试了惰性模块(从这个开始:https://www.mokkapps.de/blog/manually-lazy-load-modules-and-components-in-angular/),这将是完美的,但使用它我必须在编译我的 Angular 应用程序之前知道实现的插件(模块),因为如果我想使用模块,我必须使用 Import在我的主应用程序中运行。

所以我进行了更多搜索,在文章 Load new modules dynamically in run-time with Angular CLI & Angular 5 之后我尝试了 System.Js 方法,但我找不到 angular 9 的有效解决方案。

我很确定我不是唯一一个会创建一个可插入的 Angular 应用程序的人,该应用程序可以在不重新编译主应用程序的情况下加载插件。

我需要一些关于正确方法的建议或使用插件架构的 Angular 应用程序的工作示例。

【问题讨论】:

Angular 的可热插拔架构尚未广泛实现。只有在运行时导入的 angular 9 才使得构建这样的东西成为可能,而无需使用 hacky 解决方法。一些资源:brianflove.com/2019/12/13/lazy-load-angular-v9-components @mamichels 感谢您提供有趣的链接。当用户显示方法 'loadModule(moduleInfo: ModuleData, ownerWindow?: any)' 时,我在 cmets 中为我的解决方案找到了一些有用的东西(我希望)......这给了我希望。 @mamichels提到的网址好像改成了brianflove.com/2019-12-13/lazy-load-angular-v9-components 【参考方案1】:

我不确定这是不是更好更优雅的解决方案,因为我是 Angular 的新手,但目前它对我有用。

我假设插件是 Element Web 组件 (https://angular.io/guide/elements)。 为了创建我的第一个元素(插件),我遵循了本教程:https://www.techiediaries.com/angular/angular-9-elements-web-components/。

顺便说一句,此时我无法动态加载我的插件,因为在编译项目以使用它之前,我必须知道我在元素中部署的组件的名称。 我使用 Extensions Element (https://angular-extensions.github.io/elements/#/home) 找到了解决方案。 所以我创建了一个动态组件,用于在运行时显示插件的组件。

这是动态组件的代码:

export class DynamicComponentContainerComponent implements OnInit 
  plugin: Plugin
  sub: any;

  constructor(private route: ActivatedRoute, private pluginService: PluginService)  

  ngOnInit() 
    this.sub = this.route
      .data
        .subscribe(data => 
           this.pluginService.getPlugin(data['pluginName'])
            .subscribe(
              (res) => 
                this.plugin = res;
              ,
              (err) => 
                console.error(err)
               
            );
          );
  

  ngOnDestroy() 
    this.sub.unsubscribe();
  

及其html模板:

<div *ngIf="plugin != null">
<ng-template #loading>Loading plugin plugin.tag ...</ng-template>
<ng-template #error>Error Loading plugin plugin.tag</ng-template>
<ax-lazy-element
    *axLazyElementDynamic="plugin.tag; url: plugin.url; module: plugin.isModule; 
errorTemplate: error; loadingTemplate: loading;">
</ax-lazy-element>
</div>

它可以工作,因为我的后端服务于插件的 JS 编译文件(元素 Web 组件),所以我必须在使用它之前注册我的插件(因为我需要一些值来处理它,比如组件的名称或路由的路径)。 实际上,动态组件中的 axLazyElementDynamic 属性需要 JS Element Web 组件文件的 url 和组件名称才能起作用。

现在我必须动态地为每个插件组件添加路由路径。 在我的应用组件中,我创建了这个简单的方法:

loadPlugins() 
  this.pluginService.getPlugins()
    .subscribe(plugins => 
      plugins.forEach(plugin => 
        this.router.config.unshift( path: plugin.path, component: 
DynamicComponentContainerComponent, data:  pluginName: plugin.name  );
        this.links.push( text: plugin.description, path: plugin.path );
      );
    );

插件服务只是从后端(我之前注册插件的地方)获取插件数据。

我希望这可以帮助某人。

【讨论】:

以上是关于Angular App 无需重新编译即可动态加载插件的主要内容,如果未能解决你的问题,请参考以下文章

动态数据更新,无需刷新或重新加载

qt动态库编译,是不是只要声明

node.js + mysql + ejs 数据插入后无需重新加载页面即可更新屏幕信息

AngularJS 指令在使用 $.get 加载动态内容后编译

JBoss 无需重新启动即可重新加载证书信任库

Rabbitmq 无需重启即可重新加载/刷新新证书