Lazy-loading feature when navigating to route
This is something I first suggested in #376 - now as a separate issue :-) Rob also commented about the possibility of making global resources be global only to a plugin/feature - I think that would fit very well into this.
Have you guys thought about how features and lazy-loaded routes might work together?
We're building a large site here, and it would be good for maintainability if each area of the site could be implemented as a feature, so e.g. any area-specific globalResources calls can be defined within the area, instead of in the site root - but the thing is, each of those areas are bundled separately, which means they are only loaded when the user actually navigates into the area. Would it be possible to support this?
I actually just tried putting this in the file containing the root component for an area, but it seems to break things - the configure function is actually invoked when I navigate into the area, but the use argument is undefined and afterwards the Area1 class is never instantiated. If I remove the configure function, then the area loads as expected. No errors in the console though, so not sure what's going on... it may just be me trying to abuse things here, but I think it it could be handy if it worked :-) Thoughts?
import {FrameworkConfiguration} from "aurelia-framework";
export function configure(use: FrameworkConfiguration)
{
console.log("configure area"); // This is actually invoked when navigating into the area
}
export class Area1
{
constructor()
{
console.log("create area"); // This is only invoked if I remove the 'configure' function
}
}
There are two features we are considering. These won't be in the v1 release, but we aren't stopping there ;) We'll have plenty of point releases that add new features. Here's what I'm thinking:
- The ability to have feature-scoped resources.
- The ability to lazily install/configure a feature.
The basic infrastructure for the first point is in place via the ViewResources hierarchy. It only requires a mechanism and apis to detect that a view model or view resides within a feature area and to patch in the feature-specific resources.
The second feature is a bit more involved since there has to be some way to know when to trigger the lazy feature configuration. I imagine this would come in two possible variants;
- Extend router configuration to enable a "feature" to be associated with a route so that it is loaded first and configured before the routes are resolved.
- Extend
<require>to potentially indicate that an import resides in a feature.
This would enable routing to trigger feature loading as well as individual views.
Thoughts?
Sorry for the long silence - this sounds like exactly what we would like to see :-)
Regarding the extension of the router config, maybe it makes sense to do this based on a convention, so when a flag is set on the route, It automatically looks for an index.ts file next to the view model? Just a thought...
See also my comment in https://github.com/aurelia/router/issues/90 - maybe it makes sense to think about those together?
I don't think the feature dependencies should be configured in the router. Let's say you configure a route to load feature A upon navigation, and feature A requires feature B in some way. Does that mean we must also specify B in the route config?
If features are always sub folders, could <require> be extended to call all the registered features above the required file's directory? For example, if feature-a/sub-feature/my-service is required, Aurelia would check if feature-a is registered as a lazy feature (specified in main.js). If it is, its configure export is called. Then Aurelia would check sub-feature -- which may have been registered as a lazy-loaded feature of feature-a -- and configure that as well. Doing this would allow the feature dependencies to be specified in the configure functions only, and not scattered around the rest of the application.
Also, is this limited to <require>, or can Aurelia hook into the module loader to make it work with standard imports?
@fgambino We don't want to try to hack the module loader. However, we can enable the actual lazy load in various ways. What we would do is create a core capability to enable that and then expose it through a few different places: route config, require elements, etc.
Thanks for the clarification!
Any progress on this? Estimates on release/availability? We're building a large app and will need to lazy load sections of the app too.
Lazy loading has worked from day one. This feature is only about adding special hooks to lazily load and invoke feature registration.
It could be done today with a pipeline step in the router. You could search each router to see if it had a feature associated and then import that module and call it's configure method against a new instance of FrameworkConfiguration. Also, if you wanted to lazily configure through the view, a similar technique could be done there as well, through using a custom view resource.
Most of the community has just wanted basic lazy loading, which we have, so we haven't implemented this feature yet.
I'll add this to my list of "samples" so we can at least build a demo of one way to do this even if an official feature gets pushed out.
Great! Demos would be much appreciated.
@EisenbergEffect can you please keep me in the loop if working on lazy loading features, plugins, resources, etc.? I think it's related to the work we are doing on webpack. Basically, the bundler (i.e. webpack) needs to be able to build a precise dependency graph, and decide what is lazy (in another, on-demand, bundle file) vs what is together.
Today I can easily split an application by route, so that set of pages are bundled separately and only loaded when the route is accessed.
But the issue is that those files are usually rather small compared to the resources they use. For example maybe some pages need a charting library or a large datagrid control?
Currently it is possible to properly split this by using local resources (<require> in the view).
But the "popular" way, starting with our own aurelia-templating-resources, is to .plugin('awesome-charts') at startup, which in turn .globalResources('...') everything. The call to .plugin() means that awesome-charts is a dependency of our main bundle rather than the pages, which do use charts.
Ideally we would like a lightweight way to define where (in which module) resources are located and only load/initialize them when they are actually used. And the build tool needs to figure out where such resources are actually used to packages them in the correct bundle file.
Is there any update on any samples for doing this. We're building a micro-service based app where all area are written by different teams and the shell needs to find/load features on-demand.
You could do this by using Aurelia extensibility points today:
- Use a router pipeline step to check for a feature property on a route. If present, use the feature api to load and configure it.
- Create a custom view resource plugin that enables you to use the
requireelement to specify a feature. The plugin would use the feature api to load and configure it.
Ideally, implement both of these and let them share a common lookup between them to ensure that features aren't double loaded.
Is there likely to be any sample for this? The doc site isn’t that accessible (I’m visually impaired) but that is another issue, happy to reach out separately for this.
From: Rob Eisenberg [mailto:[email protected]] Sent: Thursday, April 06, 2017 07:49 To: aurelia/framework [email protected] Cc: Sean Farrow [email protected]; Comment [email protected] Subject: Re: [aurelia/framework] Lazy-loading feature when navigating to route (#427)
You could do this by using Aurelia extensibility points today:
- Use a router pipeline step to check for a feature property on a route. If present, use the feature api to load and configure it.
- Create a custom view resource plugin that enables you to use the require element to specify a feature. The plugin would use the feature api to load and configure it.
Ideally, implement both of these and let them share a common lookup between them to ensure that features aren't double loaded.
— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/aurelia/framework/issues/427#issuecomment-292084460, or mute the threadhttps://github.com/notifications/unsubscribe-auth/ABY1fonN6r_nObmyqtUvFCBaxc8oshb_ks5rtIrDgaJpZM4IlL7Z.
I don't have a sample of doing this. We'd like to build something like this into the framework but haven't gotten around to it yet. The idea is that when you use the feature api you should be able to specify that they are lazy. Then by associating the feature with a route or via a view require, the framework would be able to handle all the loading and configuring on demand.
Ok, how easy would this be to build? Where should I start to read in terms of the docs? Is there a way of reading docs off-line?
From: Rob Eisenberg [mailto:[email protected]] Sent: Thursday, April 06, 2017 07:53 To: aurelia/framework [email protected] Cc: Sean Farrow [email protected]; Comment [email protected] Subject: Re: [aurelia/framework] Lazy-loading feature when navigating to route (#427)
I don't have a sample of doing this. We'd like to build something like this into the framework but haven't gotten around to it yet. The idea is that when you use the feature api you should be able to specify that they are lazy. Then by associating the feature with a route or via a view require, the framework would be able to handle all the loading and configuring on demand.
— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/aurelia/framework/issues/427#issuecomment-292085336, or mute the threadhttps://github.com/notifications/unsubscribe-auth/ABY1fpsPVBiFrG8S5eZM-S9PAFtSnNjQks5rtIvpgaJpZM4IlL7Z.
No way to read the docs right now. We are working on a completely new implementation of our docs that will enable scenarios like that though.
For learning how to do this by our docs, that's tricky mostly because this involves using some more obscure APIs, but combining them in a particular way to get the desired effect.
I could put something together this weekend maybe. Send me an email and remind me. I think it would make an interesting blog post.