abpframework / abp

Open-source web application framework for ASP.NET Core! Offers an opinionated architecture to build enterprise software solutions with best practices on top of the .NET. Provides the fundamental infrastructure, cross-cutting-concern implementations, startup templates, application modules, UI themes, tooling and documentation.
https://abp.io
GNU Lesser General Public License v3.0
12.93k stars 3.44k forks source link

Lazy load Blazor modules/assemblies #5543

Open hikalkan opened 4 years ago

hikalkan commented 4 years ago

We should work on a general system to lazy load module assemblies. Need to upgrade to .NET 5: https://docs.microsoft.com/en-us/aspnet/core/blazor/webassembly-lazy-load-assemblies

ghd258 commented 3 years ago

Why delay

hikalkan commented 3 years ago

ABP modules require to be initialized on application startup. They registers services to dependency injection for example. I didn't see in Microsoft's document how we register services to Dependency Injection (DI) for lazy loaded assemblies. As I know, it is not possible to register services to DI after the application has started. So, I wanted to postpone this to investigate more in the next milestone. If you know and you can help, it is appreciated.

leonkosak commented 3 years ago

This should greatly improve this issue, right? https://github.com/abpframework/abp/issues/6269#issuecomment-756734786

hikalkan commented 3 years ago

This should greatly improve this issue, right?

I don't think so, to be honest. In any way, this milestone we are more focused on server side blazor (which will improve performance when you use), so we will try to work on it in the next milestones.

muratyuceer commented 3 years ago

also we think about api-definition result size, my application growing but already 2mb

image

stsrki commented 3 years ago

As @hikalkan already mentioned. The main issue with lazy load is that we do a lot of things with DI. So no matter what we do, it will always load all of the modules at once.

Since lazy-load is not an option I think the best way to do this would be to implement prerendering. But the current .Net5 prerendering has its own limitations. For example, when the app is loaded on the client it still needs to get the app state from the server and to re-render a second time. And when it does, it will do (ugly) a small flicker.

There is a better way, but it is only available in new .Net6 so I think it is best to wait until it is released.

https://jonhilton.net/blazor-prerendering-net6/

mostafayakout commented 2 years ago

we can do the following steps as a temporal solution :

1- add route component in the Blazor webAssembly client project to be the same as the one provided by default from ABP to use all features included App.razor 2- make small changes on the component to be like that

@using Microsoft.Extensions.Options
@using Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic
@using Volo.Abp.AspNetCore.Components.Web.Theming.Routing
@using System.Reflection
@inject LazyAssemblyLoader lazyLoader
@inject IOptions<AbpRouterOptions> RouterOptions
<CascadingAuthenticationState>
    <Router AppAssembly="RouterOptions.Value.AppAssembly" OnNavigateAsync="OnNavigateAsync"
            AdditionalAssemblies="lazyLoadedAssemblies">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                <NotAuthorized>
                    @if (!context.User.Identity.IsAuthenticated)
                    {
                        <RedirectToLogin />
                    }
                    else
                    {
                        <p>You are not authorized to access this resource.</p>
                    }
                </NotAuthorized>
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>
@code {
    private List<Assembly> lazyLoadedAssemblies = new List<Assembly>();
    protected override Task OnInitializedAsync()
    {
        lazyLoadedAssemblies = RouterOptions.Value.AdditionalAssemblies;
        return base.OnInitializedAsync();
    }
    private async Task OnNavigateAsync(NavigationContext args)
    {
        if (args.Path.EndsWith("counter"))
        {
            var assemblies = await lazyLoader.LoadAssembliesAsync(
                new List<string> { "MathNet.Numerics.dll" });
            lazyLoadedAssemblies.AddRange(assemblies);
        }
    }
}

3- in this case we can make use of register additional assemblies using Abp configure service feature and also control lazy loading easily