在Angular 2,4,5,6中实现插件架构/插件系统/可插拔框架

Ant*_*lin 123 plugins angular-cli angular-universal angular

更新5/24/2018:我们现在从我的原始帖子中获得了+3版本的Angular,但仍然没有最终可行的解决方案.Lars Meijdam(@LarsMeijdam)提出了一个有趣的方法,当然值得一看.(由于专有问题,他不得不暂时删除他最初发布样本的GitHub存储库.但是,如果您需要副本,可以直接给他发消息.请参阅下面的评论以获取更多信息.)

Angular 6中最近的架构变化确实使我们更接近解决方案.此外,Angular Elements(https://angular.io/guide/elements)提供了一些组件功能 - 尽管不是我在本文中最初描述的内容.

如果来自令人惊奇的Angular团队的任何人碰巧碰到了这个,请注意,似乎还有很多其他人也对这个功能非常感兴趣.积压可能值得考虑.


我想实现在一个可插拔(插件)的框架Angular 2,Angular 4,Angular 5,或Angular 6应用程序.

(我开发这个可插拔框架的具体用例是我需要开发一个微型内容管理系统.由于这里不一定详述的一些原因,Angular 2/4/5/6它几乎完全适合该系统的大多数需求.)

通过可插拔框架(或插件架构),我特别指的是一个允许第三方开发人员通过使用可插拔组件创建或扩展主应用程序功能的系统,而无需直接访问或了解主应用程序的源代码或内部运作.

(关于" 没有直接访问或了解应用程序的源代码或内部工作 "的措辞是一个核心目标.)

可插入框架的示例包括常见的内容管理系统,如WordPressDrupal.

理想情况(与Drupal一样)是简单地将这些可插入组件(或插件)放入文件夹,让应用程序自动检测或发现它们,让它们神奇地"工作".以某种热插拔方式发生这种情况,意味着在应用程序运行时,这将是最佳的.

我目前正在尝试确定以下五个问题的答案(在您的帮助下).

  1. 实用性:Angular 2/4/5/6应用程序的插件框架是否实用?(到目前为止,我还没有找到任何实用的方法来创建一个真正的可插拔框架Angular2/4/5/6.)
  2. 预期的挑战:在为Angular 2/4/5/6应用程序实现插件框架时可能会遇到哪些挑战?
  3. 实施策略:可以采用哪些具体技术或策略来实现Angular 2/4/5/6应用程序的插件框架?
  4. 最佳实践:Angular 2/4/5/6应用程序实现插件系统的最佳实践是什么?
  5. 替代技术: 如果插件框架在应用程序中实用Angular 2/4/5/6,那么相对等效的技术(例如React)可能适用于现代高反应性Web应用程序

一般来说,使用Angular 2/4/5/6非常理想,因为:

我非常想Angular 2/4/5/6用于我目前的项目.如果我能够使用Angular 2/4/5/6,我也将使用Angular-CLI并且可能Angular Universal(用于服务器端渲染.)

到目前为止,关于上述问题,我的想法如下.请查看并提供您的反馈和启示.

  • Angular 2/4/5/6应用程序使用包 - 但这不一定与允许应用程序中的插件相同.Drupal通过将插件文件夹放入公共模块目录中,系统可以自动"拾取" 插件,从而实际添加其他系统(例如)中的插件.在Angular 2/4/5/6,一个软件包(作为一个插件可能)通常安装npm,添加到package.json,然后手动导入到应用程序 - 如app.module.这比Drupal丢弃文件夹并让系统自动检测包的方法复杂得多.安装插件越复杂,人们使用它们的可能性就越小.如果有一种方法Angular 2/4/5/6可以自动检测和安装插件,那会好得多.我非常有兴趣找到一种方法,允许非开发人员安装Angular 2/4/5/6应用程序并安装任何选定的插件,而无需了解所有应用程序的体系结构.

  • 通常,提供可插拔体系结构的好处之一是,第三方开发人员可以非常轻松地扩展系统的功能.显然,这些开发人员不熟悉他们所插入的应用程序的所有代码复杂性.一旦开发了插件,其他技术用户就可以简单地安装应用程序和任何选定的插件.然而,Angular 2/4/5/6相对复杂并且具有非常漫长的学习曲线.为了进一步复杂的是,大多数生产Angular 2/4/5/6应用也使用Angular-CLI,Angular UniversalWebPack.实现插件的人可能必须至少掌握一些基本知识,了解所有这些是如何组合在一起的 - 以及对工作的强大了解TypeScript和合理的熟悉程度NodeJS.知识要求是否如此极端以至于没有第三方想要开发插件?

  • 大多数插件可能具有一些服务器端组件(例如,用于存储/检索插件相关数据)以及一些客户端输出.Angular 2/4/5特别(强烈地)阻止开发人员在运行时注入自己的模板 - 因为这会带来严重的安全风险.为了处理插件可以容纳的许多类型的输出(例如,图形的显示),似乎允许用户创建以一种形式注入到响应流中的内容可能是必要的.我想知道如何在没有象征性地粉碎Angular 2/4/5/6安全机制的情况下满足这种需求.

  • 大多数生产Angular 2/4/5/6应用程序都是使用Ahead of Time(AOT)编译预编译的.(可能一切都应该是.)我不确定如何将插件添加到预编译的应用程序(或与之集成).最好的方案是将插件与主应用程序分开编译.但是,我不确定如何使这项工作.回退可能是使用任何包含的插件重新编译整个应用程序,但这对于只想安装应用程序(在他自己的服务器上)以及任何选定插件的管理用户来说有点复杂.

  • Angular 2/4/5/6应用程序中,尤其是预编译的应用程序中,单个错误或冲突的代码可能会破坏整个应用程序.Angular 2/4/5/6应用程序并不总是最容易调试.应用不良插件可能会导致非常不愉快的体验.我目前还没有意识到一种优雅地处理不良插件的机制.

Lar*_*dam 15

我在github上创建了一个存储库,其中包含可能有帮助的解决方案.它使用Angular 6库和1个基本应用程序,它们懒洋洋地加载UMD捆绑库; https://github.com/lmeijdam/angular-umd-dynamic-example

如果您有任何建议,请随时添加!

  • 正如另一条评论中所提到的,由于公司政策的原因,我不得不将存储库设为私有.随着讨论的进行,我将在稍后将其恢复为在线状态 (2认同)

Den*_*ika 10

我刚刚为我的书" 使用Angular开发 "发表了一个新章节,该书解决了Angular 2+中的插件主题,对于那些试图构建外部插件的人来说应该是非常有趣的.

关键点:

  • 插件
  • 基于字符串名称构建组件
  • 从外部源加载配置
  • 动态更改应用程序路由
  • 外部插件
  • 创建插件库
  • 将插件加载到应用程序中
  • 带插件内容的动态路由

这本书是免费的,并且"付出你想要的"模式.随意拿一份副本,希望有所帮助.


yur*_*zui 7

?Github演示angular-plugin-architecture

也许Ivy可以更改某些内容,但是暂时我使用的是使用Angular CLI Custom Builder并满足以下要求的解决方案:

  • AOT
  • 避免重复代码(@ angular / core {common,forms,router},rxjs,tslib之类的软件包)
  • 在所有插件中使用共享库,但请勿从每个插件中的共享库中生成生成的工厂,而应重用库代码和工厂
  • Angular CLI给予我们的优化水平
  • 对于导入外部模块,我们只需要知道一件事:它们的捆绑文件路径
  • 我们的代码应识别模块并将插件放入页面
  • 支持服务器端渲染
  • 仅在需要时加载模块

用法很简单:

ng build --project plugins --prod --modulePath=./plugin1/plugin1.module#Plugin1Module 
         --pluginName=plugin1 --sharedLibs=shared --outputPath=./src/assets/plugins
Run Code Online (Sandbox Code Playgroud)

在我的文章中对此有更多了解:


Nik*_*ich 6

带有工作插件系统的示例应用程序(感谢Gijs创建github repo!)https://github.com/PacktPublishing/Mastering-Angular-2-Components/tree/master/angular-2-components-chapter-10 based在电子书掌握Angular 2组件

  • 插件架构,以扩展核心应用程序组件
  • 文件插件系统(仅用于添加插件目录/文件而无需编辑任何核心配置文件或需要重新编译应用程序!)
  • 加载并动态使用插件
  • 建立一个基本的插件管理器来动态激活/停用插件

干杯,尼克拉斯

  • 我读过这本书,但插件部分已经过时了.它使用普通的JS和SystemJS,而Angular的目标是Typescript和Webpack.使用Webpack和Typescript似乎无法实现,我发布了一个问题,以防您找到任何解决方案.这是[link](http://stackoverflow.com/questions/43087156/dynamically-load-modules-with-webpack-using-typescript) (4认同)
  • 无法从该链接看到示例代码,您可以发布Code Pen或JSFiddle吗? (2认同)

小智 5

您正在寻找的是延迟模块加载。这是一个示例:http : //plnkr.co/edit/FDaiDvklexT68BTaNqvE?p=preview

import {Component} from '@angular/core';
import {Router} from '@angular/router';

@Component({
  selector: 'my-app',
  template: `
    <a [routerLink]="['/']">Home</a> | 
    <a [routerLink]="['/app/home']">App Home</a> |
    <a [routerLink]="['/app/lazy']">App Lazy</a>

    <hr>
    <button (click)="addRoutes()">Add Routes</button>

    <hr>
    <router-outlet></router-outlet>
  `
})
export class App {
  loaded: boolean = false;
  constructor(private router: Router) {}

  addRoutes() {
    let routerConfig = this.router.config;

    if (!this.loaded) {
      routerConfig[1].children.push({
        path: `lazy`,
        loadChildren: 'app/lazy.module#LazyModule'
      });

      this.router.resetConfig(routerConfig);
      this.loaded = true;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

最好...汤姆

  • 感谢您抽出宝贵时间回答我的问题。我熟悉延迟加载的模块,但是这些并不是我想要的。延迟加载的模块在设计时仍必须是已知的。我希望能够添加构建原始应用程序时不了解或未想到的实际模块和功能。(我正在寻找的是更具动态性的东西。)当然,这些组件将使用(某种形式的)延迟加载,但这只是难题的一小部分。再次感谢您分享此答案。 (17认同)