You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Dynamically loading multiple modules to the same view. #16387
[ ] bug report => search github for a similar issue or PR before submitting
[x] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
What is the motivation / use case for changing the behavior?
Angular is a great framework for building modular apps. Therefore we have the use case to build a framework that can aggregate multiple modules, dynamically at run-time and in the same view.
Imagine an app such as a dashboard ( e.g. https://blackrockdigital.github.io/startbootstrap-sb-admin-2/pages/index.html ) where each item (app/bundle) from the side-menu is dynamically obtained from the backend.
We have a use case where we can have multiple apps such as those loaded in the same view. You can add 1, 2 or n apps to the same view, therefore, the number of router outlets/proxy components isn't known beforehand. Each app can also be a standalone app if bootstrapped by itself, so they might contain advanced routeing or any normal functionality of an Angular app.
We managed to achieve the use case above by extending the router a bit and playing around with named router outlets. However, we feel that this is risky and might be prone to lots of changes depending on how Angular itself evolves.
This is the "best" solution we found so far if anyone else is attempting this and has a better, smarter or whatever solution we would be really glad to hear about it!
It would be outstanding if Angular would offer some support for those type of apps out of the box. Are there any plans to implement this in the future or is this out of the scope of Angular?
Reacted by Yc. Shen, Huáng Jùnliàng, VenkatTadipaneni, Robin Regmi, David Herges, Yashwardhan Pauranik and Tarun Dhillon
We have the same problem. Also I think we use a similar tricky method as @roby2001 does by modifying router config and by playing around with named router-outlet dynamically. But it is really cumbersome. We just want to load multiple components from another module into a component view without depending on router and lazy loading.
@dherges By using ViewContainerRef and ComponentFactoryResolver sort of APIs, you can add components dynamically in a view. But the component must also be declared as a entryComponent in the same module. There are no simple methods to load a component from another module dynamically yet.
@dherges
I knew ViewContainerRef and ComponentFactoryResolver. But I don't see any way to use them loading a component from another module (I mean another ngModule not imported or as a loadChildren in current ngModule).
I read your gist and wonder how this resolveComponentFactory call can successfully create a ComponentFactory if the component is not declared or as an entry in the containing ngModule or as so from any imported ngModules.
I would be grateful if you can show me a complete sample about loading component from any other module in anytime (de facto lazy loading) as @mlc-mlapis said?
SystemJsNgModuleLoader was the way we used for a long period for dynamic module loading.
But as angular-cli is becoming the de facto tool to create angular application, SystemJsNgModuleLoader might not be working under angular-cli since the webpack adoption. Moreover, I don't think SystemJsNgModuleLoader works well with AOT, do I?
BTW, although angular-cli builds chunks for lazy-loading modules, it still lacks a way to build chunks for modules which intended to be used as lazy-loading or dynamic-loading (more precisely, the loadChildren route will not be pre-wired in its parent module route, but will be intended to be added dynamically by Router.resetConfig() (we are using such a method) or some sort of webpack module loader (which is a missing part).
I open-sourced @sharpangles/angular-dynamic from an enterprise app due to some folks asking for it. It solves alot of other compexities that arise in these scenarios, such as projecting state into dynamic loaded components, 3rd parties, dynamic loading scenarios outside of systemjs, etc...
I looked at both @Toxicable and @EricABC solutions, I must be missing something because, with @Toxicable we still need to build the base application everytime we want to load a new version of the "dynamic" myplugin module...
@EricABC I see no example code, just text that looks nice... but how exactly are you dynamically loading modules without requiring the base application to be either reloaded (webpack HMR) or compiled and served again with the updated chunks.
I am currently looking for a solution to have modules deployed in different servers and (somehow) dynamically loaded (in a host application) whenever a new version is available...
Currently the solution I have looked at require either the use of systemJS (so goodbey AOT and bigger size) or force the user to reload the application (new version has to be built and deployed). Perhaps someone has a more mature solution.
@webmutation The key to dynamic loading is to decouple the devops from the code. First, be sure you write code that can be truly dynamic. Sharpangles is the library I use to accomplish that. Here is a simple example:
First, I use an interface to map from data sent over the wire.
Finally, the template that uses both lazy loading and state projection. These could be combined into a single directive to simplify the syntax, but I tend to prefer separating the concern of lazy loading from state projection.
One thing to note about this code and sharpangles is that up to now no decision has been made on how the lazy loading is performed. Webpack, systemjs, or native module loading already appearing in chrome are all still possible with the example above.
OK, now to make a decision on dynamic loading. There are really only 2 choices: static analysis and dynamic. Neither has anything to do with AOT, which is possible in both.
Static analysis = webpack. Its designed to be able to know about every bit of code in your app before compiling. 'Lazy' loading in webpack is not dynamic at all, just delayed. This is one of the most confusing parts about it, but understand that chunks cannot be updated. This is because something in your new code might impact the minification algorithms used in a previous one. If you change any part, the entire package it rebuilt. This does not prevent you from deploying complex 'dynamic' scenarios by persisting builds produced for different targetted users, audiences, or versions. But if you are looking to have a dashboard with a dynamic tile in it where the developer just freshly minted the code and pushed a build out, then webpack does not support this. When you break down most systems, very few need this level of dynamic and are content with just versioning or tracking production minified build outputs and selecting the correct set of js files for the current user. The big advantage of using webpack is that it produces the most optimal build size and all the tooling requires it (ng-cli).
Using sharpangles with webpack a little more than just dropping in StatefulModule.forRoot(). If you are using the router module, it already registers the NgModuleFactoryLoader to be the SystemJS one. Don't worry, webpack doesnt actually use systemJS, it knows how to replace all this. What you must do is make sure webpack will learn about ALL code in advance. Either you must reference the modules so they are not tree-shaken, or you must use the router. You don't have to actually use the router, but you must register routes like this:
Two things to note here: the string-based loadChildren will be 'learned' by ng-cli and webpack will create a lazy chunk for it. Second, the reference cannot use tsconfig paths (must use real relative paths) as ng-cli doesn't work with them yet (or at least as of version 1.4.*).
Clearly, this isn't really dynamic. You have a reference to the module. Webpack required everything in advance to build. What is useful is that you can write future-proof code that will not change (except that router bit) with an alternate devops process.
Lets say you do actually want TRUE dynamic. Then native module loading (for which you can think of systemJS as the polyfill) is what you must use. This does not prevent the use of AOT (just include the ngfactories in your build, typically using rollup so the ng dependencies get included), and buried in the other branches in sharpangles have been working examples of this approach. However, this is a MASSIVE project. It can be made to work with some simple examples, but when you start looking at production it becomes alot more. You have to think about things like dynamic client-side module loading configuration injected by dependent libraries, shared dependency reconciliation, minification with the ability to chain mappings between builds (no library does this yet), etc....
To summarize, this just isn't realistic today, unless you can satisfy yourself with simple minification and module resolution scenarios. It really has nothing to do with angular which is why no simple angular solution has been presented across the numerous versions of this issue. It is really a devops problem. Sharpangles does have branches that had stages of a working prototype, but it is on hold for a bit because the ideas that evolved were basically a full-fledged 'actor-oriented architecture' devops system, where the script finally dies and we model developer behaviors directly. To do that to its fullest potential I will need to apply a new philosophy we devised that I am currently implementing in an enterprise system called behavior-oriented architecture (which solves the new problems introduced by actors). Unfortunately this is a problem for 2018.
Reacted by Miloš Lapiš, Daniel Mendes, Travis Dent, Hulva Luva.H, Md Khaled Hossain Ansary, Dmitri Maltsev, arkhemlol, Huáng Jùnliàng, Saif eddine Jerbi, Daniel Rose and 3 more
Hello everyone, the best way to load modules at run time without the "core" know anything about the module is using angular elements, if someone has any questions you can contact me and I will explain, I will make a demonstration when I have time
Activity
vicb commentedon Apr 28, 2017
Could you please re-formulate your request to be more generic ? I am not sure to understand exactly what you need.
dherges commentedon Apr 28, 2017
@roby2001 There are
ViewContainerRefAPIs for child components and child views.Your writing is pretty confusing to me though. What exactly is your goal? What is your current code?
onixie commentedon Jun 20, 2017
We have the same problem. Also I think we use a similar tricky method as @roby2001 does by modifying router config and by playing around with named router-outlet dynamically. But it is really cumbersome. We just want to load multiple components from another module into a component view without depending on router and lazy loading.
@dherges By using
ViewContainerRefandComponentFactoryResolversort of APIs, you can add components dynamically in a view. But the component must also be declared as aentryComponentin the same module. There are no simple methods to load a component from another module dynamically yet.dherges commentedon Jun 20, 2017
@onixie There are methods to load a component from another module dynamically. Their names are
ViewContainerRefandComponentFactoryResolver.Samples:
mlc-mlapis commentedon Jun 20, 2017
... and also loading of any module in anytime (de facto lazy loading) by the same way as router does but without the router.
dherges commentedon Jun 20, 2017
@mlc-mlapis This will be a great addition! 🇨🇿 🇪🇺
onixie commentedon Jun 27, 2017
@dherges
I knew
ViewContainerRefandComponentFactoryResolver. But I don't see any way to use them loading a component from another module (I mean another ngModule not imported or as a loadChildren in current ngModule).I read your gist and wonder how this resolveComponentFactory call can successfully create a
ComponentFactoryif the component is not declared or as an entry in the containing ngModule or as so from any imported ngModules.I would be grateful if you can show me a complete sample about loading component from any other module in anytime (de facto lazy loading) as @mlc-mlapis said?
mlc-mlapis commentedon Jun 27, 2017
The principle of loading any NgModule is following:
SystemJsNgModuleLoaderthrough DI in the constructor asNgModuleFactory:loadChildrenused by Angular router.Working demo of the same in a bit different form you can see here:
https://github.com/Toxicable/module-loading.
Relevant Angular source code:
https://github.com/angular/angular/blob/master/packages/core/src/linker/system_js_ng_module_factory_loader.ts
dherges commentedon Jun 27, 2017
@onixie the question is about lazy-loading a module or about dynamically creating a component?
In the above posts, I was talking about dynamic component loading. Lazy loading afaik is only possible with the router for time being.
onixie commentedon Jun 29, 2017
@mlc-mlapis Thank you for the demo.
SystemJsNgModuleLoaderwas the way we used for a long period for dynamic module loading.But as angular-cli is becoming the de facto tool to create angular application,
SystemJsNgModuleLoadermight not be working under angular-cli since the webpack adoption. Moreover, I don't thinkSystemJsNgModuleLoaderworks well with AOT, do I?BTW, although angular-cli builds chunks for lazy-loading modules, it still lacks a way to build chunks for modules which intended to be used as lazy-loading or dynamic-loading (more precisely, the
loadChildrenroute will not be pre-wired in its parent module route, but will be intended to be added dynamically byRouter.resetConfig()(we are using such a method) or some sort of webpack module loader (which is a missing part).mlc-mlapis commentedon Jun 29, 2017
Yes, that is true. This part of Angular has some missing points and it would be great if something new would be introduced in Angular 5. For AOT it is possible to go as https://github.com/Toxicable/module-loading/blob/master/static/src/app/dynamic-loader.component.ts. Another thing is how to create separate AOT modules to be able to load them later when you want.
EricABC commentedon Jul 12, 2017
I open-sourced @sharpangles/angular-dynamic from an enterprise app due to some folks asking for it. It solves alot of other compexities that arise in these scenarios, such as projecting state into dynamic loaded components, 3rd parties, dynamic loading scenarios outside of systemjs, etc...
mlc-mlapis commentedon Jul 12, 2017
@EricABC ... interesting ... I have to read it detaily. 👍
webmutation commentedon Nov 9, 2017
I looked at both @Toxicable and @EricABC solutions, I must be missing something because, with @Toxicable we still need to build the base application everytime we want to load a new version of the "dynamic" myplugin module...
@EricABC I see no example code, just text that looks nice... but how exactly are you dynamically loading modules without requiring the base application to be either reloaded (webpack HMR) or compiled and served again with the updated chunks.
I am currently looking for a solution to have modules deployed in different servers and (somehow) dynamically loaded (in a host application) whenever a new version is available...
Currently the solution I have looked at require either the use of systemJS (so goodbey AOT and bigger size) or force the user to reload the application (new version has to be built and deployed). Perhaps someone has a more mature solution.
EricABC commentedon Nov 9, 2017
@webmutation The key to dynamic loading is to decouple the devops from the code. First, be sure you write code that can be truly dynamic. Sharpangles is the library I use to accomplish that. Here is a simple example:
First, I use an interface to map from data sent over the wire.
Next, here is a component that takes in a dynamicFrame.
Finally, the template that uses both lazy loading and state projection. These could be combined into a single directive to simplify the syntax, but I tend to prefer separating the concern of lazy loading from state projection.
One thing to note about this code and sharpangles is that up to now no decision has been made on how the lazy loading is performed. Webpack, systemjs, or native module loading already appearing in chrome are all still possible with the example above.
OK, now to make a decision on dynamic loading. There are really only 2 choices: static analysis and dynamic. Neither has anything to do with AOT, which is possible in both.
Static analysis = webpack. Its designed to be able to know about every bit of code in your app before compiling. 'Lazy' loading in webpack is not dynamic at all, just delayed. This is one of the most confusing parts about it, but understand that chunks cannot be updated. This is because something in your new code might impact the minification algorithms used in a previous one. If you change any part, the entire package it rebuilt. This does not prevent you from deploying complex 'dynamic' scenarios by persisting builds produced for different targetted users, audiences, or versions. But if you are looking to have a dashboard with a dynamic tile in it where the developer just freshly minted the code and pushed a build out, then webpack does not support this. When you break down most systems, very few need this level of dynamic and are content with just versioning or tracking production minified build outputs and selecting the correct set of js files for the current user. The big advantage of using webpack is that it produces the most optimal build size and all the tooling requires it (ng-cli).
Using sharpangles with webpack a little more than just dropping in StatefulModule.forRoot(). If you are using the router module, it already registers the NgModuleFactoryLoader to be the SystemJS one. Don't worry, webpack doesnt actually use systemJS, it knows how to replace all this. What you must do is make sure webpack will learn about ALL code in advance. Either you must reference the modules so they are not tree-shaken, or you must use the router. You don't have to actually use the router, but you must register routes like this:
Two things to note here: the string-based loadChildren will be 'learned' by ng-cli and webpack will create a lazy chunk for it. Second, the reference cannot use tsconfig paths (must use real relative paths) as ng-cli doesn't work with them yet (or at least as of version 1.4.*).
Clearly, this isn't really dynamic. You have a reference to the module. Webpack required everything in advance to build. What is useful is that you can write future-proof code that will not change (except that router bit) with an alternate devops process.
Lets say you do actually want TRUE dynamic. Then native module loading (for which you can think of systemJS as the polyfill) is what you must use. This does not prevent the use of AOT (just include the ngfactories in your build, typically using rollup so the ng dependencies get included), and buried in the other branches in sharpangles have been working examples of this approach. However, this is a MASSIVE project. It can be made to work with some simple examples, but when you start looking at production it becomes alot more. You have to think about things like dynamic client-side module loading configuration injected by dependent libraries, shared dependency reconciliation, minification with the ability to chain mappings between builds (no library does this yet), etc....
To summarize, this just isn't realistic today, unless you can satisfy yourself with simple minification and module resolution scenarios. It really has nothing to do with angular which is why no simple angular solution has been presented across the numerous versions of this issue. It is really a devops problem. Sharpangles does have branches that had stages of a working prototype, but it is on hold for a bit because the ideas that evolved were basically a full-fledged 'actor-oriented architecture' devops system, where the script finally dies and we model developer behaviors directly. To do that to its fullest potential I will need to apply a new philosophy we devised that I am currently implementing in an enterprise system called behavior-oriented architecture (which solves the new problems introduced by actors). Unfortunately this is a problem for 2018.
webmutation commentedon Nov 14, 2017
@EricABC WOW, thanks for the super complete answer. You have given me a lot of material to digest.
rodrigoEclipsa commentedon Apr 22, 2018
Hello everyone, the best way to load modules at run time without the "core" know anything about the module is using angular elements, if someone has any questions you can contact me and I will explain, I will make a demonstration when I have time
jelbourn commentedon Oct 9, 2020
Tracking the main underlying concern here in #18093
angular-automatic-lock-bot commentedon Nov 9, 2020
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.