149

Update 5/24/2018: We are now +3 versions of Angular from my original post and still don't have a final workable solution. Lars Meijdam (@LarsMeijdam) has come up with an interesting approach which is certainly worth a look-see. (Due to proprietary issues, he had to temporarily remove the GitHub repository where he had originally posted his sample. However, you may message him directly if you would like a copy. Please see the comments below for more info.)

Recent architectural changes in Angular 6 do bring us closer to a solution. Additionally, Angular Elements (https://angular.io/guide/elements) provides some component functionality--though not quite what I originally described in this post.

If anyone from the amazing Angular team happens to come across this, please note that there seem to be many other people who are also very interested in this functionality. It might well be worth considering for the backlog.


I would like to implement a pluggable (plug-in) framework in an Angular 2, Angular 4, Angular 5, or Angular 6 application.

(My specific use case for developing this pluggable framework is that I need to develop a miniature content management system. For a number of reasons not necessarily elaborated here, Angular 2/4/5/6 is a near perfect fit for most of the needs of that system.)

By pluggable framework (or plug-in architecture), I specifically mean a system which allows third party developers to create or extend the functionality of a primary application through the use of pluggable components without having direct access to or knowledge of the primary application's source code or inner workings.

(That phrasing about "without having direct access to or knowledge of the application's source code or inner workings" is a core objective.)

Examples of pluggable frameworks include common content management systems like WordPress or Drupal.

The ideal situation (as with Drupal) would be to simple be able to place these pluggable components (or plug-ins) into a folder, have the application auto-detect or discover them, and have them just magically "work." Having this occur in some sort of hot-pluggable manner, meaning while the app was running, would be optimum.

I am currently trying to determine answers (with your help) to the following five questions.

  1. Practicality: Is a plugin framework for an Angular 2/4/5/6 application even practical? (Until now, I have not found any practical way to create a truly pluggable framework with Angular2/4/5/6.)
  2. Expected Challenges: What challenges might one encounter in implementing a plugin framework for an Angular 2/4/5/6 application?
  3. Implementation Strategies: What specific techniques or strategies could be employed for implementing a plugin framework for an Angular 2/4/5/6 application?
  4. Best Practices: What are the best practices for implementing a plugin system for an Angular 2/4/5/6 application?
  5. Alternative Technologies: If a plugin framework is not practical in an Angular 2/4/5/6 application, what relatively equivalent technologies (e.g. React) might be suitable for a modern highly reactive Web application?

In general, use of Angular 2/4/5/6 is very desirable because:

  • it is naturally extremely fast--blazingly so.
  • it consumes very little bandwidth (after the initial load)
  • it has a relatively small footprint (after AOT and tree shaking)--and that footprint continues to shrink
  • it is highly functional, and the Angular team and community are continuing rapid growth of its ecosystem
  • it plays well with many of the best and latest Web technologies such as TypeScript and Observables
  • Angular 5 now supports service workers (https://medium.com/@webmaxru/a-new-angular-service-worker-creating-automatic-progressive-web-apps-part-1-theory-37d7d7647cc7)
  • being backed by Google, it is likely to be supported and enhanced well into the future

I would very much like to use Angular 2/4/5/6 for my current project. If I am able to use Angular 2/4/5/6, I will also be using Angular-CLI and probably Angular Universal (for server-side rendering.)

Here are my thoughts, so far, regarding the questions above. Please review and provide your feedback and enlightenment.

  • Angular 2/4/5/6 apps consume packages--but this is not necessarily the same as allowing plugins within an application. A plugin in other systems (e.g. Drupal) can be essentially added by dropping the plugin folder into a common modules directory where it is automatically "picked up" by the system. In Angular 2/4/5/6, a package (as a plugin might be) is usually installed via npm, added to the package.json, and then manually imported into the app--as in app.module. This is much more complicated than the Drupal method of dropping a folder and having the system automatically detect the package. The more complicated it is to install a plugin, the less likely people will be to use them. It would be much better if there was a way for Angular 2/4/5/6 to automatically detect and install plugins. I am very interested to find a method which allows non-developers to install the Angular 2/4/5/6 application and install any chosen plugins without having to understand all of the application's architecture.

  • Generally, one of the benefits of providing a pluggable architecture, is that it is very easy for 3rd party developers to extend the functionality of the system. Obviously, these developers will not be familiar with all of the intricacies of the code for the application they are plugging into. Once the plugins are developed, other even less technical users may simply install the application and any selected plugins. However, Angular 2/4/5/6 is relatively complicated and has a very lengthy learning curve. To further complicate things, most production Angular 2/4/5/6 applications also utilize Angular-CLI, Angular Universal, and WebPack. Someone who is implementing a plugin would probably have to have at least some basic knowledge of how all of these fit together--along with a strong working knowledge of TypeScript and a reasonable familiarity with NodeJS. Are the knowledge requirements so extreme that no third party would ever want to develop a plugin?

  • Most plugins will likely have some server side component (e.g. for storing/retrieving plugin related data) as well as some client-side output. Angular 2/4/5 specifically (and strongly) discourages developers from injecting their own templates at runtime--as this poses a serious security risk. In order to handle many types of output that a plugin may accommodate (e.g. display of a graph), it appears that allowing users to create content which is injected into the response stream, in one form another, is probably necessary. I wonder how it might be possible to accommodate this need without figuratively shredding Angular 2/4/5/6's security mechanisms.

  • Most production Angular 2/4/5/6 applications are pre-compiled using Ahead of Time (AOT) compilation. (Probably all should be.) I am uncertain how plugins might be added to (or integrated with) pre-compiled applications. The best scenario would involve compiling the plugins separately from the main application. However, I am uncertain how to make this work. A fallback might be to re-compile the entire application with any included plugins but that complicates things a bit for an administrative user who simply wants to install the application (on his own server) along with any selected plugins.

  • In an Angular 2/4/5/6 application, especially a pre-compiled one, a single piece of errant or conflicting code can break the entire application. Angular 2/4/5/6 applications are not always the easiest to debug. Application of ill-behaved plugins could result in very unpleasant experiences. I am currently unaware of a mechanism to gracefully handle ill-behaved plugins.

Anthony Gatlin
  • 4,407
  • 5
  • 37
  • 53
  • 1
    In my oppinion, an angular 2 module is a plugin. @angular/router, @angular/forms, @angular/http, @angular/material, these are 'plugins' from angular, we can check out how they make 'plugins'. – Timathon Jan 03 '17 at 07:38
  • 9
    @Timathon, unfortunately, they are not the same. Plugin systems allow an application to be extended without modification of the core application code. Use of @angular/router, @angular/forms, etc. require the user to modify the application. Those are really libraries as opposed to plugins. I am really more interested in allowing non-developer administrative users to select and use the plugins which are most interesting to them without having to be aware of the internal details of the application. – Anthony Gatlin Jan 03 '17 at 16:03
  • 1
    Did you get anywhere with this? I'm interested in trying something similar. The way Angular 2 is build (around Modules) I thought a plugin type architecture would fit it really well but it doesn't seem to any examples etc. – Joe Mar 16 '17 at 14:36
  • 2
    @Joe, I still do not have a good solution for this problem. I thought the same as you. – Anthony Gatlin Apr 25 '17 at 21:52
  • 1
    I am looking for exactly the same mechanism, but no valid answeres so far :( http://stackoverflow.com/questions/43063091/angular2-plugin-mechanism –  Apr 26 '17 at 08:43
  • 1
    Seems like it is a job for: https://angular.io/guide/dynamic-component-loader#dynamic-component-loader – Guillaume Sep 19 '17 at 08:40
  • 1
    I am also looking for the same. What i found is we can use Angular Element that element is just a plugin and will be integrated into Angular or Non Angular web apps. Kinda plug and play. It's not yet official. – Hardik Pithva Dec 04 '17 at 09:59
  • @Hearty, if we are thinking of the same angular.element, it is compatible only with the original AngularJS rather than Angular2+. It would not quite provide what I am describing above.. https://docs.angularjs.org/api/ng/function/angular.element – Anthony Gatlin Dec 05 '17 at 05:51
  • No @AnthonyGatlin, i am not taking about angular.element. I am describing Angular Element which is not yet available in Angular v5 officially but probably be soon. – Hardik Pithva Dec 05 '17 at 07:01
  • Did you find anything promising regarding A v5? –  Jan 06 '18 at 14:59
  • For the moment I use a rather primitive approach. I scan the plugins folder for plugins. I generate metadata objects about the plugins. Using this metadata and a build command I generate angular module files in the core from generic module templates (handlebars or interpolated strings). These files are git ignored. Each install generates it`s own set of modules, hardwiring all dependencies with a build command. Thus I have code completion (static analysis) intact. Not ideal, but hey, it's something. Have you found something better?. I'd like to contact you if possible. – Adrian Moisa Jan 19 '18 at 14:04
  • I'm also interested in this for a dashboard app, where new widgets could be added with extra plugins. You can either use JIT and dyanmically register modules/compile components on the client side, or use AOT and rebuild each time a plugin is added. But we might get something nice in v6: https://next.angular.io/guide/custom-elements – Andrei Tătar Apr 01 '18 at 17:21
  • @AnthonyGatlin Did you found anything practical regarding this question? I've already developed such system in PHP using CakePHP and Now I'm looking forward to doing the same thing in Angular 5 and Firebase. I have the same concerns as your question above but, so far I haven't found anything useful. I would like to chat with you if possible to learn more from your experience so far. – Subhan Apr 20 '18 at 04:46
  • 1
    @Subhan, Given the way that Angular dominates and controls the entire front-end environment, I found that migrating towards another framework, specifically React, offered a much easier path towards my objective. Even though I dearly love Angular, I have discovered that my new love is much more accommodating. – Anthony Gatlin Apr 20 '18 at 11:17
  • @AnthonyGatlin I have same requirements as you , Did you go with react or did you find anything with angular 5 ? I am new to both and requirements are hard a you explained – django Apr 20 '18 at 13:17
  • @django For my current project I am working in React, but I plan to keep current in Angular and switch back and forth as needed. Both of them are great and have their advantages and limitations. Even if Angular did not quite meet my needs for the current project, I am in no way abandoning it. – Anthony Gatlin Apr 20 '18 at 14:52
  • 1
    @AnthonyGatlin So you were not able to build a plugin architecture in Angular 5? Is this approach easier in, for example, React? – Niklas Teich Apr 20 '18 at 18:01
  • @NiklasTeich, yes building plugin components can definitely be done in React--and several have already accomplished this. React is primarily a library for front-end rendering whereas Angular pretty much takes over your whole front-end. React allows a lot more flexibility. Sometimes this good. Other times, Angular is better and can be slightly more performant. However, I found React+Apollo give me about as much performance as I will need for most any app. Beyond the pure front-end, you can plug all kinds of libraries behind React--including those that might accept plugins of various kinds. – Anthony Gatlin Apr 21 '18 at 22:24
  • @Andrew you're using Angular Elements already yourself or you have a different approach? And how do you solve lazy routing if it was not only a component, but a complete module? I'm curious what the current state is regarding implementing this sort of architecture, did you make any progress? – Lars Meijdam Apr 23 '18 at 12:13
  • @LarsMeijdam I haven't used Angular Elements yet, only read about them. I actually haven't started the work on the dashboard... probably in the winter. The idea is that you either include the files dinamically in your project and recompile the entire app on the server (when a plugin is added for example), either use JIT to compile on the client, or try the new angular elements. For lazy loading, I guess you need to create some kind of service that each lazy module calls on init to load the appropiate script dependencies. Or some kind of common chunks plugin... – Andrei Tătar Apr 23 '18 at 13:00
  • Angular Elements looks really slick and is very useful for specific use cases. But might not be in ours. Please see my question regarding my issue; https://stackoverflow.com/questions/50149016/load-new-modules-dynamically-in-run-time-with-angular-cli-angular-5 – Lars Meijdam May 03 '18 at 07:18
  • 2
    I created a repository on github with a solution which might help. It uses Angular 6 libraries and 1 base applications which load up the UMD bundled libraries lazily; https://github.com/lmeijdam/angular-umd-dynamic-example If you have any suggestions, please feel free to add! – Lars Meijdam May 09 '18 at 06:38
  • 1
    @LarsMeijdam, You have a very interesting approach. You may have finally found a reasonable use case for Eval(). As soon as I can get a little time, I want to clone your GitHub repository and experiment with it. It looks promising. Thanks for sharing. – Anthony Gatlin May 09 '18 at 15:24
  • @AnthonyGatlin For the moment I had to put it on private as some of my customers company policies wasn't sure for me to put it on public, will be back ASAP as discussion is ongoing. For now you may contact me if you want the repo still as it holds no company related information – Lars Meijdam May 14 '18 at 05:53
  • @LarsMeijdam Yes, I would very much like to review the repository. Very very much. – Anthony Gatlin May 14 '18 at 11:35
  • any other form of contact I can share the repo to? :) – Lars Meijdam May 14 '18 at 13:13
  • @AnthonyGatlin keep updating your post, the community appreciate the effort and work. I'm going to need a solution to this in the upcoming months and have been keeping an eye on this SO question for some months already. – Dunos May 23 '18 at 16:01
  • @LarsMeijdam anthony.gatlin *AT* happycatfish.com – Anthony Gatlin May 24 '18 at 19:17
  • @LarsMeijdam could I also get a copy of the repo? – jamesthollowell May 31 '18 at 13:04
  • I just came to this question after a lot of hunting. Seems like there's lots to expect from Angular 6. @LarsMeijdam is it still possible to share a copy of the repo to [my github](http://github.com/kochhar)? – Shailesh Jun 21 '18 at 03:18
  • @Shailesh you have any contact details or location i would find one? then we can have a talk about what Ive been creating. Happy to share! – Lars Meijdam Jun 21 '18 at 19:43
  • @LarsMeijdam sorry abt that, you can find me on https://twitter.com/60secondrun – Shailesh Jun 23 '18 at 06:55
  • I've solved this one way, to have my backend application compile the front end when it starts up. But I dropped that and created an Angular plugin interface that the plugins extend. I stopped development on it a while back, but I'm starting to pick it up again - Loader: https://github.com/savantly-net/sprout-platform/blob/master/web/sprout-web-ui/src/app/client-plugins/client-plugins.module.ts - Plugin Interface: https://www.npmjs.com/package/@savantly/ngx-sprout-plugin - More information here https://stackoverflow.com/questions/46256465/can-we-add-a-feature-module-to-an-angular-app-after-aot – Jeremy Jun 23 '19 at 16:38
  • 1
    The lack of this feature still is the biggest disadvantage of Angular. – Stefan Jan 24 '23 at 20:57

12 Answers12

26

Update

For Angular 11 I strongly recommend you to take a look at implementation with Webpack 5 Module Federation

https://github.com/alexzuza/angular-plugin-architecture-with-module-federation

Previos version

️ Github demo angular-plugin-architecture

Maybe Ivy can change something but for the time being I use the solution that uses Angular CLI Custom Builder and meets the following requirements:

  • AOT
  • avoid duplicate code(packages like @angular/core{common,forms,router},rxjs,tslib)
  • use shared library in all plugins but DO NOT SHIP generated factories from that shared library in each plugin but rather reuse library code and factories
  • the same level of optimization that Angular CLI gives us
  • for importing the external modules we just need to know only one thing: their bundle file path
  • our code should recognize module and place plugin into the page
  • support server-side rendering
  • load module only when needed

The usage is simple as:

ng build --project plugins --prod --modulePath=./plugin1/plugin1.module#Plugin1Module 
         --pluginName=plugin1 --sharedLibs=shared --outputPath=./src/assets/plugins

More on this in my article:

yurzui
  • 205,937
  • 32
  • 433
  • 399
  • 1
    Great example! One question. How can I pass `OAuthToken` at runtime to Library service from our main app? – Yogen Darji Feb 11 '20 at 07:08
  • @yurzui can we use the same approach if we have multiple angular applications and we use their whole distribution instead of making a modules like you did plugin 1 and plugin 2 ? – Momin Shahzad Mar 24 '20 at 15:27
  • Would you be able to revisit this example and make it Ivy compatible in the near foreseeable future? If you would, please add an example of a shared service and shared `InjectionToken` that will be provided in the AppModule and injected in other plugins. Thanks! – Jyrkka Jun 19 '20 at 23:41
17

I created a repository on github with a solution which might help. It uses Angular 6 libraries and 1 base applications which load up the UMD bundled libraries lazily; https://github.com/lmeijdam/angular-umd-dynamic-example

If you have any suggestions, please feel free to add!

undefined
  • 33,537
  • 22
  • 129
  • 198
Lars Meijdam
  • 1,177
  • 1
  • 10
  • 18
  • 2
    As mentioned in another comment, I had to make the repository private due to company policy.. I will put it back online later as discussions are ongoing – Lars Meijdam May 14 '18 at 06:51
  • Would love to see your solution please. – Subhan Jun 13 '18 at 20:48
  • @Subhan, I'm currently busy rewriting the repository before placing it back on GH again. Give me a little bit more time. Otherwise you can also contact me directly! :D – Lars Meijdam Jun 15 '18 at 05:57
  • @lars-meijdam : we will still wait a lot :D ... Me too very interested. Thank you in advance – aguetat Aug 01 '18 at 15:10
13

I have just published a new chapter for my book "Developing with Angular" that addresses the topic of plugins in Angular 2+ and should be of a great interest to people that are trying to build external plugins.

Key points:

  • Plugins
  • Building components based on string names
  • Loading configuration from external sources
  • Dynamically changing application routes
  • External plugins
  • Creating plugin libraries
  • Loading plugins into the application
  • Dynamic routes with plugin content

The book is free to get, and has "pay what you want" model. Feel free to grab a copy and hope that helps.

Denys Vuika
  • 621
  • 1
  • 12
  • 10
  • How can I replace a sub-component by your plugin architecture illustraded in the book? I will replace template or maybe I will add an input property ecc... At the same time I need to know if exists a way to override/extend a service provided. – Matteo Calò Mar 23 '18 at 14:18
  • 1
    @Denis Vuyka, The book looks great but it lacks the crucial part - support of AoT compilation. – Sergey Sokolov Mar 24 '18 at 04:44
7

Example application with a working plugin system (thanks to Gijs for founding the github repo!) https://github.com/PacktPublishing/Mastering-Angular-2-Components/tree/master/angular-2-components-chapter-10 based on the eBook Mastering Angular 2 Components

  • plugin architecture to extend core app components
  • file plugin system (for simply adding plugin directories/files without editing any core config files or the need to recompile your application!)
  • load and dynamically use plugins
  • building a rudimentary plugin manager to activate/deactive plugins on-the-fly

Cheers, Niklas

Niklas Teich
  • 111
  • 6
  • 2
    Can't see example code from that link, can you post a Code Pen or JSFiddle? – Sean Chase Feb 08 '17 at 23:58
  • https://github.com/PacktPublishing/Mastering-Angular-2-Components/tree/master/angular-2-components-chapter-10 – Gijs Mar 22 '17 at 01:10
  • 4
    I read the book, but the plugin part is out of date. It uses plain JS and SystemJS, while Angular is aiming toward Typescript and Webpack. Using Webpack and Typescript it seems not achievable, I posted a question in case you found any solutions. Here's the [link](http://stackoverflow.com/questions/43087156/dynamically-load-modules-with-webpack-using-typescript) – Luigi Dallavalle Apr 11 '17 at 07:36
  • This should help: https://github.com/mgechev/angular-seed/issues/1358#issuecomment-248890159 – Guillaume Sep 25 '17 at 16:37
  • can someone confirm if above works? What if we dont want to use systemjs – django Dec 17 '17 at 13:28
5

What you're looking for is lazy module loading. Here is an example of it: 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;
    }
  }
}

Best...Tom

Tom I
  • 125
  • 1
  • 2
  • 18
    Thank you for taking the time to answer my question. I am familiar with lazy loaded modules, but these are not quite what I am looking for. Lazy loaded modules must still be known at design time. I am looking to be able to add actual modules and functionality that were not known about or envisioned when the original app is built. (What I am looking for is something a bit more dynamic.) Certainly those components would use (some form of) lazy loading but it is only one small piece of the puzzle. Thank you again for sharing this answer. – Anthony Gatlin Feb 13 '17 at 17:22
  • 1
    I agree this doesn't answer the question. Lazy loading doesn't help with plugin architecture because they are required at design time. It simply doesn't download/transfer the data to the client until required. – Joe Apr 26 '17 at 10:00
  • What if your app will know about all of the available plug-in-modules at the compile time. At the moment you add a new module to the platform it must be recompiled with this module. Just an idea... Not sure I this will increase the size of JS files significantly, not sure if lazy-loading feature will put such module into a separate file and then lazy load it, I just sharing my idea... – Vladimir Prudnikov Sep 16 '17 at 02:37
  • @VladimirPrudnikov, if an application could know about all of the plugins at compile time, that would be fantastic. However, the idea is to be able to add plugins possibly after the application is compiled. This would allow for truly dynamic plugging of modules. However, this would require the modules to also be pre-compiled at the time they are deployed--and I am not sure how this would work. I am also not sure how to keep the the plugin modules version compatible with Angular. – Anthony Gatlin Mar 19 '18 at 17:42
2

I made a hack for load and compile other modules in bootstrap time, but i haven't solve the problem of cyclic dependencies

 const moduleFile: any = require(`./${app}/${app}.module`),
                    module = moduleFile[Object.keys(moduleFile)[0]];

 route.children.push({
     path: app,
     loadChildren: (): Promise<any> => module
 });
 promises.push(this.compiler.compileModuleAndAllComponentsAsync(module));

then in AppModule add this:

{
        provide: APP_INITIALIZER,
        useFactory: AppsLoaderFactory,
        deps: [AppsLoader],
        multi: true
},
2

I was looking for a plugin system in angular 2/4 too for developing a RAD environment for an enterprise application at work. After some research, I decided to implement a collection of database-stored (but could be in the filesystem) pseudo-Angular components.

The components stored in the database database are based on ng-dynamic and the main component implementation is similar to this:

declare var ctx: any;

@Component({
    selector: 'my-template',
    template: `
<div>
    <div *dynamicComponent="template; context: { ctx: ctx };"></div>
</div>
  `,
    providers: [EmitterService],

})

export class MyTemplateComponent implements OnMount, AfterViewInit, OnChanges {


    // name
    private _name: string;
    get name(): string {
        return this._name;
    }
    @Input()
    set name(name: string) {
        this._name = name;        
        this.initTemplate();
    }

    template: string;
    ctx: any = null;

    private initTemplate() {

        this.templateSvc.getTemplate(this.name).subscribe(res => {
            // Load external JS with ctx implementation
            let promise1 = injectScript(res.pathJs);
            // Load external CCS
            let promise2 = injectScript(res.pathCss);

            Promise.all([promise1, promise2]).then(() => {

                // assign external component code
                this.ctx = ctx; //

                // sets the template
                this.template = res.template;

                this.injectServices();

                if (this.ctx && this.ctx.onInit) {
                    this.ctx.onInit();
                }

            });

        });

    }

The external javascript code is similar to angular components:

var ctx = {

// injected    
_httpService: {},
_emitterService: null,

// properies
model: {
    "title": "hello world!",
},


// events
onInit() {
    console.log('onInit');
},

onDestroy() {
    console.log('onDestroy');
},

onChanges(changes) {
    console.log('changes', changes);
},

customFunction1() {
    console.log('customFunction1');
},

childTemplateName: string = 'other-component'; 

};

And the templates of the components are like angular templates:

<a (click)="customFunction1()">{{ ctx.model.title }}</a>
<input [(ngModel)]="ctx.model.title" type="text" />

And could be nested too:

<a (click)="customFunction1()">{{ ctx.model.title }}</a>
<my-template [name]="childTemplateName"></my-template>

Although it's not perfect, the developers of the custom components have a similar framework than in angular2/4.

zarpilla
  • 353
  • 3
  • 6
2

It can be done, "manually". Since webpack do not know anything about external(plug-ins) module, he cannot include them in bundle(s). So what I did, is to look at the code generated by webpack and I found this pies of code in main.bundle.js:

var map = {
"./dashboard/dashboard.module": ["../../../../../src/app/dashboard/dashboard.module.ts","dashboard.module"]}; 

Lets examine what that array contains:

  1. "./dashboard/dashboard.module" - this is routing URL of the module witch we want to lazy load for example :{ path: 'dashboard', loadChildren: './dashboard/dashboard.module#DashboardModule' }
  2. "../../../../../src/app/dashboard/dashboard.module.ts" - this is entry point(contructor) takes from
  3. "dashboard.module" - actual file name without chunk.js(for example: dashboard.module.chunk.js)

So in theory, if you add entry to the map property configure your routing and follow the pattern, you can have a plug-in system. Now the challenge is how to add or remove entries from that map property. Obviously it cannot be done from angular code, it should be done for external tool.

Niki Uzun
  • 21
  • 1
2

I tried to implement a plugin architecture making use of ABP, Angular and ASP.NET Core: https://github.com/chanjunweimy/abp_plugin_with_ui

Basically, I developed angular plugins using different angular application, then I dynamically add them together.

More Information on how I achieve it:

I have 2 angular-cli application, 1 is the main angular cli application, and another is the plugin angular cli application. The problem we are facing in Angular-cli plugin architecture approach is how we integrate them.

Right now, what I did was, I run ng-build on both of the applications, and put them into a "wwwroot" folder, which then hosted in a ASP.NET core 2.0 server. A simpler repository that shows this idea is Angular Multiple App: https://github.com/chanjunweimy/angular-multiple-app

abp_plugin_with_ui is a repository which works on developing a plugin which contains both the backend and Angular cli. For the backend, I made use of the aspnetboilerplate framework, which the frontend is developed using multiple angular-cli application.

To have the main application integrated with the plugin application, we have to run "ng-build" on both of the application (note that we have to change to href of the plugin application as well), then we move the built contents of plugin angular cli application, to the main application "wwwroot" folder. After achieving all this, we can then run "dotnet run" to serve the ASP.NET Core 2.0 Web Application to host the static files generated by "ng build".

Hopefully it helps. Any comments is welcome! ^^

  • I'm trying to follow your plugin docs, but I think the documentation is skipping a few steps. I apologize if I am misreading it. The whole 'adding a plugin' piece is not clear to me. I followed this step by step, but I'm not really seeing results. What should I see on port 4200 after I run the power shell? I don't see a Plugins folder in /aspnet-core/src/Todo.MainProject.Web.Host/. I ran the powershell, and that folder was not created. Any help appreciated. I think your approach is what I need, but I'm a bit fuzzy on how it works yet. – Brian Kitt Feb 07 '18 at 18:00
  • Ok. I should have done this before asking the question. I spent time debugging, and figured out my answers. #1) the powershell doesn't put the .zip where it needs to go, I need to create the plugin folder, and move the zip. #2) when the angular app starts, it dynamically calls the loader, and copies plugins to the webroot. That was kind of spelled out ,but I get it now. #3) I have to use the url to invoke the plugin, it doesn't show up anywhere. I was expecting it to be on the dashboard. Thanks for your work, this is a significant chunk of code. – Brian Kitt Feb 07 '18 at 19:01
2

A little off topic, but UI Component libraries could be of interest for some of the readers, who search for plugins:
https://medium.com/@nikolasleblanc/building-an-angular-4-component-library-with-the-angular-cli-and-ng-packagr-53b2ade0701e

NativeScript has build-in UI Plugins:
https://docs.nativescript.org/plugins/building-plugins
Those plugins needs an Angular Wrapper:
https://docs.nativescript.org/plugins/angular-plugin

RaSor
  • 869
  • 10
  • 11
2

i'm currently in the same quest as you are, trying to make a Pluggable/Themable Version of Angular, and it's not a trivial problem.

I Actually Found Pretty Good Solutions, reading the book Developing with Angular by the Genius Denys Vuyika, he actually on the book explain a pretty good solution, he talks about External plugins on the page 356 of the book and Uses Rollup.js to achieve the solution, he then process to dynamically load external plugins that have been previously built outside of your application.

There is also two other libraries/projects that help you achieve this result ng-packagr and Nx extensions for Agnular (from Nrwl) we are tying to implement the latter, and i'd say it's not as smooth as we anticipated, angular was simple not built for that, so we have to work around some of the the core on how Angular, and the NX ppls are one of the best on it.

We are only at the beginning of our Open Source Project, we are using Django+Mongo+Angular, (We are calling WebDjangular and one of our possible approaches to this answer, is that Django will have to write some JSON configuration files and build the application every time a new plugin or theme is installed and activated.

What we already accomplished is, from the database we can use tags for the components like on the plugin, and the component will be printed on the screen! Again the project is in very early stages, we are basing our architecture a little bit on Wordpress, and we have a lot of more tests to do to achieve our dream :D

I Hope the Book can help you, and using Rollup.js i know you will be able to crack this non trivial problem.

0

I found a good article from Paul Ionescu about how to build a plugin extensible application in angular.

https://itnext.io/how-to-build-a-plugin-extensible-application-architecture-in-angular5-736890278f3f

He also references an example application at github: https://github.com/ionepaul/angular-plugin-architecture

Marvin Caspar
  • 1,319
  • 1
  • 14
  • 25
  • 1
    that is in Angular 5... does Angular 9, 10 with Ivy provide other ways? Will the example on Angular 5 still work on Angular 9 or 10? – mvermand Sep 11 '20 at 12:31