I'm trying to create a service which uses router configuration to create map of routes based on components. It works fine when you don't use lazy loaded module routes.
But I don't know how to get routes from lazy loaded module. In route object there is just loadChildren string and that's it. I digged little bit into angular2 internals and it is using RouterConfigLoader internally to load lazy loaded routes. But it is not exported from RoutingModule, so I suppose it should not be used from the outside.
Is there any public API which would help me with that?
Thanks
But that's the whole idea of lazy loaded modules. No reference exists to the lazy loaded module, so it ain't loaded on load (can I use the word load some more?).
Which also means no routing is available. Based on the string, angular2 loads the (entire) module, and injects the routing on the fly. If you want to know the routing beforehand, you should either not use lazy modules, or do it by hand
Related
In Angular, we can use providedIn: 'root' to make a service tree shakeable. And we can use loadChildren() in our router to specify a lazily loaded module. What's the difference between these two terms 'tree shakeable' and 'lazy loaded'? Do they both only happen when you initially build the project? Why not just call providedIn root services 'lazy loaded services'?
What's the difference between these two terms 'tree shakeable' and 'lazy loaded'?
Tree shaking is a step in a build process that removes unused code from a code base. E.g. components/modules you created, but never used. They get completely eliminated. Same with services, but there are nuances.
Then the code important for the app gets split into bundles by a module bundler. The more lazy loaded elements the app has - the more bundles it will be split into.
Lazy loading means the object will be loaded only when it is needed. E.g. separate lazy-loaded admin module: it has important for the app code, but the code (bundle) won't be sent to ordinary users as they don't have admin permissions, hence they don't need admin-features-related code.
Do they both only happen when you initially build the project?
Yes. During build process unused code gets identified and removed (tree shaking), while the important code gets split into bundles for the purpose of not sending all the app code in one big chunk (including the features the user might not even need). Some of the bundles will be loaded lazily on certain user actions.
Why not just call providedIn root services 'lazy loaded services'?
I presume that providedIn: root services may not be lazy loaded, e.g. the service code will be sent to the user immediately on page init (however the service itself will be initialized on the service usage).
I has LazyModule which I load lazy, and another one ModuleA. I need to use component Module-A-Component inside LazyModule. How can I access this external component? I use Module-A-Component around all application.
If I add Module-A-Component in daclaration array of LazyModule got the error:
Module-A-Component is part of the declarations of 2 modules...
If I move Module-A-Component only in LazyModule I can't use it in other parts of application.
How can I use the external component in lazy loaded module and other modules?
Since there is no code, so I am gonna give a theoretical answer. You need to create a shared-module. Create Module-A-Component inside it and name it accordingly. Then reuse it in MOdule A , MOdule-B and so on.
This will also make sure that there are no circular dependecy.
I' am looking for a way through which I can load multiple modules under same path in Angular. For example, consider I have three modules AModule, BModule and CModule each having its own RouterModule.forChild call. Now I want to mount all these modules under say site route.
One way I have achieved this thing is by wrapping routes in RouterModule.forChild call under site route as follows:
RouterModule.forChild([
{
path: 'site',
children: [{}] // children goes here
}
])
I don't know whether this approach is correct but it is working fine. The only issue which this approach is that I have to specify canActivate in every module I want to mount under site. While this is not a problem, I was looking for a cleaner solution.
I know there is a property loadChildren which could be used to load modules lazily. But I want to load modules eagerly.
I' am using AngularCLI which splits code of module I specify in loadChildren in a separate JavaScript file which is not I want.
I' am using AngularClI v1.2.0 and Angular v4.2.5.
Any help is highly appreciated.
Thanks
I'm not entirely clear on your goal and what you are ultimately trying to achieve, but here are a few thoughts.
You can use the loadChildren and "lazy loading" to load on demand OR eagerly. If you select eagerly loaded routes, as soon as your main route is loaded and your first view is displayed, the other modules marked for eager loading are immediately loaded asynchronously.
I have an example of that here: https://github.com/DeborahK/Angular-Routing in the APM-Final folder.
I'm not clear on why you don't want module splitting. It can significantly improve the startup performance (time to display of the first page) of your application.
In addition to canActivate there is also a canActivateChild so you can put this on the parent and not have to repeat it for each route. The docs for that are here: https://angular.io/api/router/CanActivateChild
At the moment we are in the process of creating a new web application infrastructure.
We initially load a dashboard which is esentially the top bar displaying the logged in user and the set of menus along with it. Clicking on each menu would load a screen (mostly crud screens) in the main section. We areplanning to put each of the crud screens and their components (services, controllers and such) in a seperate module which will encapsulate all the screens from each other, so for example if there is 78 screens there will be 78 seperate modules for each screen. We are also using planing on using Requirejs to load these dependencies dynamically.
The problem however occurs that we need to link the menu with each of the modules for each screen. Typically in a single module based app it would be done like this.
config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/Book/load', {
templateUrl: 'book.html',
controller: 'BookController'
})
.when('/Screen/load', {
templateUrl: 'chapter.html',
controller: 'ChapterController'
});
Where the BookController and ChapterController will be in the SAME module.
However in our case the BookController will be in a BookModule for the book screen and the same applies for the ChapterController. And the routes would be in the initial main module for example AppModule which loads the dashboard initially during startup then.
How would we say for example link the AppModule and the routes with each module for each screen (for example in this case BookController and ChapterController) keeping in mind that we need to load the modules dynamically when NEEDED using requirejs.
(P.S : We are essentially segmenting our application based on feature where feature in our system usually equals screen)
Also any suggestions on any other way we could best structure our app including an answer to the above problem would be very much appreciated.
Regards,
Milinda
Why do you have the route configuration in the initial main module? This creates unnecessary coupling between your modules (ie. your initial module has to know all the possible routes of every module), sort of defeating the purpose of moving your code into modules in the first place.
Each of your modules can have their own route configuration, which will take effect when the modules are loaded. (A consistent naming convention can help avoiding clashes between routes of unrelates modules)
While configuring the routeProvider, you can use lazy loading mechanisms using the resolve attribute of routes: resources referenced here will be resolved before the routeChange event happens, which enables you to wait for any promise resolution or a requireJS loading of a file. This blogpost might help in that regard.
As of this moment, there is no mechanism as far as I am aware for dynamically loading modules at runtime and then incorporating them in an AngularJS app. You can breakdown your app into 78 individual modules loaded via requirejs, but you will still need a single primary module which has all those other 78 as dependencies. It is this primary module which you will then configure all the routes.
There is work going on into a new AngularJS router which borrows from other more flexible routers (i.e. ui-router, etc) which will allow exactly the sort of dynamic loading of modules you are speaking about but as far as I know it won't be available until AngularJS 1.4.
I'm using this method for lazy-loading the controllers/services required for each of my AngularJS routes.
Basically, for each route, I define the dependencies (e.g the controllers, services, etc needed), then a function is added to the resolve of the route definition for that route, that function dynamically loads the javascript files of the dependencies.
This works, however where I run into a problem is this. Suppose that I wanted to lazy-load a service called fooService for the route /foo. However, what if I also wanted to have fooService.getResults() added to the resolve for /foo? This gives an error because perhaps the fooService.js file is not loaded by the time the resolve function for fooService.getResults() is called.
Is there any solution to this?