dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.47k stars 10.03k forks source link

Lazy loading of application areas #5465

Closed danroth27 closed 4 years ago

ManfredLange commented 6 years ago

@danroth27 Do you already have a few more details available for how this might work on a conceptual level? E.g. is it envisioned that each lazy-loaded area could be in a separate project/assembly?

I'm always interested in scalability beyond the typical demo projects used at conferences and in tutorials... ;-)

ManfredLange commented 6 years ago

And another aspect that I believe is of interest to people with existing systems: Is there a way to support a hybrid solution, e.g. an ASP.NET MVC application with some parts implemented using Blazor?

Is this the wrong question and/or does this warrant creating a separate issue?

Perhaps I'm asking to fly to the next galaxy while you guys are trying to just get launched into space in the first place....

danroth27 commented 6 years ago

@ManfredLange Nothing to share on the design for lazy loading quite yet.

As for ASP.NET MVC, you can use Blazor with any backend that you'd like including non-.NET back ends like Java, JavaScript, PHP, etc, although we make it particularly easy to use Blazor with ASP.NET Core. However, Blazor today takes full ownership of the app and the DOM, so you can't really use MVC to render some HTML on the server and then use Blazor to manipulate the DOM on the client. We are however looking at server-side pre-rendering support for Blazor.

mungojam commented 6 years ago

@danroth27 link above broken. here's the fixed version server-side pre-rendering, I wish GitHub let you do it the way you tried though. You have to put [24] in brackets rather than [#24]

danroth27 commented 6 years ago

@mungojam Thanks! Fixed

ghost commented 6 years ago

@danroth27 I am not sure, but does it means that Lazy loading will solve this kind of problem? Can it be coupled with "Mozilla HACKS" about WebAssembly?

danroth27 commented 6 years ago

@ckams Lazy loading is about being able to break your Blazor app up into multiple areas that can be loaded independently. It's Blazor specific, so not related to ASP.NET Core MVC and server-side rendering. You do get the perf benefits of WebAssembly in the browser.

ghost commented 6 years ago

@danroth27 I'm not sure I understand. Sorry :s Is Lazy loading like Application Parts? Can Lazy loading be used to load multiple areas in WebAssembly from server-side?

danroth27 commented 6 years ago

Is Lazy loading like Application Parts?

Nope

Can Lazy loading be used to load multiple areas in WebAssembly from server-side?

Yes, lazy loading allows you to load different areas of your app client-side from the server as needed. It's similar to lazy loading in frameworks like Angular or React.

abhishekgoenka commented 6 years ago

I don't see target release. Any idea in which release this feature will be available?

danroth27 commented 6 years ago

@abhishekgoenka Sorry, but we don't know when this feature will land quite yet.

etmendz commented 6 years ago

I'm imagining two levels of lazy loading: page level and component level. This will allow the Blazor team to deliver in phases, whichever is easier first (perhaps page level?).

At page level, the entire page is lazy loaded. Thus, in an app, a page's assembly is only loaded to the browser until the user clicks on the page's link. A page would have to be declared as lazy (ex. @lazy "appname.pagename.wasm").

At component level, the component can be declared @lazy "appname.componentname.wasm". In this sense, the component's assembly will be loaded only when the page that needs it is loaded.

Thus, the @lazy directive can be used by the engine to generate different wasm's that can be "plugged in" to the client at runtime upon request (via page and/or component that needs it). I'm thinking WebAssembly's dynamic linking comes to play here (if I'm understanding it correctly)? Or perhaps Blazor will provide the mechanism to allow it?

hokusp commented 6 years ago

@danroth27 would it be possible to get any news regarding ETA of lazy loading?

danroth27 commented 6 years ago

@hokusp Unfortunately there isn't any news to share at this point. This feature is on our backlog, but we don't expect to get to it any time soon. Our current thinking is that Lazy Loading is not critical for shipping Blazor v1.0. We still want to support it though, and we expect it would ship in a follow on release.

To help us ensure that we are prioritizing this feature correctly, it would be great if folks could share with us more details on how you expect to use this feature and why it's important for your scenarios.

bmsantos commented 6 years ago

Just because Dan asked 👍

In my opinion, Lazy Loading is essential for Blazor to be able to provide a good support for PWAs and a faster web experience in general.

My use case for lazy loading is simply that any page containing its most usable components should be able to be presented to the user within a max of 2 seconds from first visiting the site. This means that both pages and components should be able to be identified as lazy-loaded. Along with lazy loading a page, it would be great if an already loaded page could hint on the next page/components to be loaded and like this triggering a pre-fetching or nav pre-loading mechanism. PWAs can use Service Workers to do pre-fetching but that would not play nicely with Blazor app if no APIs are provided to facilitate it through Blazor.

hokusp commented 6 years ago

For my current project, it would be great if I could load Blazor components as independent modules. I have a website where different modes will be added over time and those modes should not be coupled to the "mainproject", it should be possible that different independent people develop them and that they can be added to the site without redeploying the whole site. I imagine it a bit like an API controller: There is a request to the server /GetAppMode("identifier") and it then loads the module "identifier" and returns it to the client.

isc30 commented 5 years ago

As for lazy loading, lazy dlls (library projects in general) should be the easiest ones to implement. With this approach, splitting the app in multiple assemblies will simply mean that a request for the dll is made the moment it's required, not before. Then, you could use standard .NET functions like GetAssemblies, GetReferencedAssemblies, etc to know which assemblies (modules) are already loaded.

I don't know a lot about the implementation in this area, sorry if what I'm saying doesn't make sense.

ghost commented 5 years ago

This is one of the key must-have feature that is missing and keeping us away from adapting Blazor. The concept of representing Areas (https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/areas?view=aspnetcore-2.2) as lazy-load modules would be a good approach. Until this feature is added, it is hard to consider Blazor for medium to large size enterprise applications.

Please consider this as a priority feature.

ghost commented 5 years ago

@danroth27 are there any updates on this?

danroth27 commented 5 years ago

Thanks for this feedback, @ganu81! This feature isn't going to fit in .NET Core 3.0, but we will consider it as part of our post-3.0 planning.

micahosborne commented 4 years ago

I agree this is the main reason blazor wasm is so appealing. Modularity. This is the only piece lacking ( to achieve complete decouplization ). This feature should be #1 in my opinion ABOVE ALL OTHERS!!! Can't believe after 2 years this is still a forgotten feature and still unbelievably necessary

Jabronironi commented 4 years ago

Looks like this feature is moved to 5.0 milestone. This makes it very difficult to consider this for large/enterprise applications (and in turn makes it hard to invest knowledge in knowing you are limited to using it for hobby/small projects). +1 for making this a higher priority!

MV10 commented 4 years ago

It's equally important for other Blazor scenarios, not just web assembly.

bauersystems commented 4 years ago

Lazy Loading is definitely important for large projects, otherwise it requires either breaking the app out into multiple sites that are loosely coupled together through shared libraries or the whole application needs to be downloaded just to use it.

Is it possible to plan out the functionality in alignment with the current milestones and then handed over to the community to contribute?

JohnGalt1717 commented 4 years ago

To me this is blocking for the April/May release of Blazor WebAssembly edition. Until this is available (and just automatically works with routing at the very least), Blazor Webassembly can't be used for anything but POC or "hello world". You might as well not release this without this functionality. Anyone that comes to try Blazor WebAsssembly that comes from Angular, React, Vue, or any other framework is just going to laugh you out of the room when you tell them that on first load the entire site is going to be loaded in the browser.

As an example, our production site in Angular, best case scenario based on not supporting this would be over 17 megs to load in Blazor WebAssembly BEFORE first paint. Which isn't going to happen and there's absolutely 0 chance I get this by people internally even for new projects until this functionality is there. (And I strongly suspect that that will be the answer everywhere, not just my company for obvious reasons.)

Please reconsider and make this a priority for April/May 3.2 release otherwise this is DOA for 99% of users. They just don't know it yet because they're making an assumption that this is already available.

bauersystems commented 4 years ago

I agree with JohnGalt1717. We have a few upcoming large client projects that we were wanting to use Blazor for (and a few existing projects that we were considering refactoring to use Blazor). There is no way we can develop large web based applications on Blazor without lazy loading, it wouldn't be feasible. As much as we really want to use it, we cannot consider Blazor a SPA contender until lazy loading is added sufficiently.

alikor commented 4 years ago

For my current project, it would be great if I could load Blazor components as independent modules. I have a website where different modes will be added over time and those modes should not be coupled to the "mainproject", it should be possible that different independent people develop them and that they can be added to the site without redeploying the whole site. I imagine it a bit like an API controller: There is a request to the server /GetAppMode("identifier") and it then loads the module "identifier" and returns it to the client.

This is the Micro frontends pattern and this is defiantly something my team would require.

Different teams (services) would be able to updates their own assembly and this would be dynamically loaded into the host application, component would be able to talk to each other via events this is the dream would also be great if assemblies could be loaded from different sub domains

MarekPokornyOva commented 4 years ago

Hi all Blazor eager developers, I've created assembly lazy load feature for my project. Lazy load works on page level. If you like to check it, navigate to https://github.com/MarekPokornyOva/BlazorLazyLoad. That concept might also help to put hands on and clarify the feature usage and expectations (as danroth27 asked for), at least until this is supported out-of-the-box.

isc30 commented 4 years ago

Hi everyone, good news for you all! I've been following this thread closely from the beggining, and decided to create a fully fledged Blazor Lazy Loading library (wasm, server, prerendering) inspired by the work @MarekPokornyOva has done.

Just by adding a NuGet package the lib automatically orchestrates a build-time manifest generator, build-time dll bundling (using StaticWebAssets), client side manifest consumption, assembly locators based on the manifests, assembly loaders, etc.

V1 will ship with 2 razor components: <Lazy Name="ComponentName" /> and <LazyRouter ... /> which automatically take care of loading the required DLLs/PDBs for you and rendering the components/pages.

It also includes full assembly isolation (using AssemblyLoadContext) for the ServerSide (required for horizontally scaling).

I'm in the last stages of the development and currently looking for a small-ish blazor project where I can contribute so I can implement Lazy Blazor on it.

Does anyone want a hand in their pet project to use it as a POC for this lib?

All the work has been done in here: https://github.com/isc30/blazor-lazy-loading Will also inform when I release the first stable version!

bkv143 commented 4 years ago

Hi everyone, good news for you all! I've been following this thread closely from the beggining, and decided to create a fully fledged Blazor Lazy Loading library (wasm, server, prerendering) inspired by the work @MarekPokornyOva has done.

Will also inform when I release the first stable version!

Could you write a bit more technical description how it works? As much detailed as possible. Thank you.

isc30 commented 4 years ago

@bkv143 Could you write a bit more technical description how it works? As much detailed as possible. Thank you.

Absolutely! It's already in the roadmap to get as much documentation as I can (diagrams, etc) after implementing all the core features.

I will try to give a small overview now:

When BlazorLazyLoading.Module is referenced from a RazorLib project, it will generate 2 things at build time: wwwroot/_lazy/ containing all the required DLLs and PDBs and wwwroot/lazy.json which is a simple manifest file describing what the module contains (components, routes, etc). The generated manifest will also be generated for directly referenced RazorLib projects too, so you can either have completely isolated modules OR a single module aggregating multiple projects.

When BlazorLazyLoading.Components is referenced from any place, you can use the <Lazy> and <LazyRouter> to automatically download the DLLs and render the components.

When calling .AddLazyLoading(...) you need to pass some entry-point module names. When a lazy component is used it will fetch the manifests from these modules (_lazy.json) and inspect them to know where the components/routes exist (in which DLLs). Then, it will fetch the required DLLs and load them. After that, it will render your page/component using a bit of reflection :)

In case you want to manually load an assembly you can also do it by injecting IAssemblyLoader and calling LoadAssemblyByNameAsync, which will fetch it for you and load it into the current assembly context

isc30 commented 4 years ago

I just released BlazorLazyLoading v1.0.0!

It includes full lazy loading support for Wasm, Prerendering, BlazorServer... even DualMode! Lazy loading includes named components and routes (with parameters).

Please check it out https://github.com/isc30/blazor-lazy-loading

and the docs https://github.com/isc30/blazor-lazy-loading/wiki

JohnGalt1717 commented 4 years ago

Great work doing something that Microsoft shouldn't be shipping Blazor without. Hope they work with you to have a migration plan when .net 5 comes out with proper support baked in.

radderz commented 4 years ago

@danroth27 - This issue is to lazy load an "Area" as a way to improve performance of a large application. Would it be possible to extend this concept to "modules" to enable some form of extensibility? As an example, I have a website that allows the upload of widgets (javascript) that asp.net core dynamically loads into the dom enabling extensibility of the user interface.

I'd love to be able to do this in a good way using Blazor too, to enable customised features for specific clients and not others, or even allow customers to add their own widgets meaning the website only know about it's existing through something like an API with the module and details about that module and wouldn't know anything at build time other than that there might be something. We loop through a widget list and add it to a widget canvas basically.

MarekPokornyOva commented 4 years ago

@radderz, maybe you'd try https://github.com/MarekPokornyOva/BlazorLazyLoad - see \Samples\01\BlazorApp\Pages\LazyComponent for component level lazy loading.

radderz commented 4 years ago

@MarekPokornyOva I am talking about the built in version done by MS for .NET 5, I did check your github repo, and it may be possible to do that, but I haven't started a production project yet so would prefer a built in way once we do.

I did however check your repo earlier, how would you go about including an unknown module at runtime? I.e. not it isn't a known assembly at build time so the manifest approach wouldn't work. There was no documentation on how to use the "Raw" style where you manually do things yet.

isc30 commented 4 years ago

@radderz The manifest approach is completely extensible, it doesn't need to rely on static files 😄

You can achieve what you suggest by specifying a custom IAssemblyLocator (where to find the DLLs) and IManifestLocator (where to download the manifest JSON). These could be both AspNetCore endpoints.

This approach would also work well with <Lazy> and <LazyRouter> since they rely on these interfaces too. Also, the assemblies can run a Startup when they load to register new implementations on runtime (f.e. ITagHelperComponent).

Please remember that blazor-lazy-loading is a library, it will give you the building blocks to create a runtime module system on top of it easily (which is more framework-ish).

Writing the "Going Raw" documentation is top priority atm, but please open a ticket in the repository so we can discuss your needs and which documentation would help you.

You can also have a look at these examples, for loading modules manually:

Maybe we can work together on crafting a "demo"+documentation that does what you are suggesting? 😄

radderz commented 4 years ago

@radderz The manifest approach is completely extensible, it doesn't need to rely on static files 😄

You can achieve what you suggest by specifying a custom IAssemblyLocator (where to find the DLLs) and IManifestLocator (where to download the manifest JSON). These could be both AspNetCore endpoints.

Sounds like it may work for what we are doing in JS, that's exactly the concept I meant so it's good to see it being possible even if MS doesn't do it for .NET 5.0. Good work, I'll create a issue in your repo with the use case example as although I may not use it right now it might help you provide good documentation for others doing similar things!

AmarjeetBanwait commented 4 years ago

@danroth27 Will issue (11212) Nested Routing In Blazor be fixed as part of this ?

captainsafia commented 4 years ago

@AmarjeetBanwait Not really. I'd recommend adding any scenarios/thumbs-up you have on the original issue for nested routes.

sbwalker commented 4 years ago

Oqtane ( https://github.com/oqtane/oqtane.framework ) is a modular framework built on Blazor and it already supports dynamic loading of "modules" created as razor class libraries ( including dealing with CSS and JS loading concerns ). However the current challenge we encountered with lazy loading is not related to dynamically loading assemblies or instantiating razor components... it is related to moving beyond "hello world" scenarios and creating a real world data-centric client/server plug-in module. A data-centric client/server module will have a Web API Controller which the razor components will call to retrieve data from the server. However it appears that the only way to load a Web API Controller dynamically is during Startup using mvcBuilder.PartManager.ApplicationParts.Add(part); This is an issue for lazy loading as it means that these assemblies must all be identified and loaded during startup and cannot be loaded on demand. Will it be possible in MVC 5.0 to dynamically add ApplicationParts outside of Startup?

captainsafia commented 4 years ago

Thanks for participating in this thread everyone!

We'll be shipping support for lazy-loading as part of the upcoming preview8 release. Some follow-ups will be shipped in rc1, too. Once preview8 ships, you'll find docs on lazy-loading in Blazor at docs.microsoft.com.

Looking forward to hearing your feedback on the feature!

Dennis-Petrov commented 4 years ago

@captainsafia, when preview 8 will be released?

boukenka commented 4 years ago

@Dennis-Petrov According to the Milestones section, it is scheduled for August 20, 2020.