isc30 / blazor-lazy-loading Goto Github PK
View Code? Open in Web Editor NEWAutomatic Lazy Loading support for Blazor (Server and WebAssembly)
License: MIT License
Automatic Lazy Loading support for Blazor (Server and WebAssembly)
License: MIT License
3.2.0-preview4.20210.8
just released yesterday ๐
Documentation about how to setup DryIoc in the Host so Modules can register new services by themselves :)
The linker in Blazor WASM is including dependencies that aren't in use (in normal scenarios these would be stripped out by the compiler, which is what happens with the linker disabled (ok)).
When adding a reference (RCL project/nuget) to a project with Microsoft.AspNetCore.Components.WebAssembly.Build
and BlazorWebAssemblyEnableLinking
set to true
, the linker will add the dependency project as a boot dependency inside blazor.boot.json
even if it's not used at all.
If this reference is not used, the linker should detect it and not add it as a boot project. I suspect the problem is somewhere where we take the linker output and enumerate the blazor binaries based on it.
This issue doesn't happen with BlazorWebAssemblyEnableLinking
disabled (the unused project is not even inside _framework/_bin
).
Please follow the steps to get this reproduced on your own repository.
In order to check the bug, this minimal example repository with the bug can be used.
<BlazorWebAssemblyEnableLinking>false</BlazorWebAssemblyEnableLinking>
wwwroot/test.css
as StaticWebAssetlib
from host
and use the Component from itlib
appears inside blazor.boot.json
and gets downloaded during startup (ok)_content/lib/test.css
and see that the StaticWebAsset is available (ok)lib
by not using the Component anymore so the compiler strips it outblazor.boot.json
and doesn't get downloaded during startup (ok)_content/lib/test.css
is still available (ok)<BlazorWebAssemblyEnableLinking>true</BlazorWebAssemblyEnableLinking>
lib
from host
and use the Component from itlib
appears inside blazor.boot.json
and gets downloaded during startup (ok)_content/lib/test.css
and see that the StaticWebAsset is available (ok)lib
by not using the Component anymore so the compiler strips it outblazor.boot.json
and still gets downloaded during startup (fail)_content/lib/test.css
is still available (ok)This is a rather big bug. When including a NuGet package and using a small portion of it, the linker will still add every sub-reference, even if not used and the DLL could be skipped.
This should still preserve StaticWebAssets from the projects that don't need a runtime.
Something changed in the latest Blazor release, and now every referenced DLL is downloaded at boot time...
We need to have a way to call lazily Startup
classes after lazy loading.
I don't have a full idea on how this will work but I would maintain 2 actions:
Configure should be called on all the dependencies in the same order as they are loaded into memory.
Initialize should be called after ALL assemblies have been configured, not sure about the order.
Supporting Prise in blszorWASM would be great.
It doesn't serve all file types, I need to change the AspNetCore
repo to accept that
<LazyRouter>
will contain a tree of Routers
<Lazy>
doesn't support loading components with generic arguments
After introducing ModulesHost concept, I should rename all the Nuget packages to:
BlazorLazyLoading.WasmHost
: WebAssembly ServerBlazorLazyLoading.ServerHost
: BlazorServer ServerBlazorLazyLoading.ModulesHost
: Module aggregator/manifest generatorBlazorLazyLoading.Components
: Razor components to enable lazy loading (+ )Hi,
I am working through the wiki docs and thank you for taking the time to write some docs. I realize these are early days, so I would like to ask:
For a wasm client, can one create RCL modules that are not directly referenced by the wasm project (or a modulesHost project), kind of a "disconnected" setup where I could then build a module from a separate solution and deploy the output to some common modules folder?
and double-check that everything works fine
Blazor team did a lot of work to introduce a partial implementation of the lib into blazor itself. This means that the LazyAssemblyLoader
is a native part of blazor now! When .NET 5 RC1 is released, this library should shrink and reuse as much as it can from the official lazy loading support.
The linker needs to be currently disabled in order to use lazy loading.
Stripping assemblies is really dangerous since you don't know which piece a dynamic assembly might need.
The linker can be customized with the following guide. Worth having a look ๐
Error caused while rebuilding server project.
Screen https://prnt.sc/v6jd2y
Hi Ivan, this is an interesting system you've built.
I'm interested in runtime loading of page-based razor component libraries (Blazor server-side), but if I'm reading your readme and wiki correctly, it sounds like this only operates at the component level. Is that accurate?
I suspect page-content RCLs would require somehow registering the newly-loaded page with the router. I saw one of your comments in a closed issue that you were going to ask MS about opening up their router, did you get anywhere with that?
Basically we're planning to build a gigantic (enterprise) system, hundreds of pages, and we're designing around a base "frame" that can host arbitrary content that ideally isn't known at build-time. (We have the beginnings of a page-based system where the "frame" pages are basically two-line stubs -- the @page
directive and a <component>
tag that ties to a referenced RCL, it's that need to build One Giant Solution that I'm trying to break.) I was trying to imagine different ways to discover/load that content at runtime -- and unload, so we don't just accumulate assemblies as the user navigates around in the app all day long.
Have you considered anything along these lines? All I've found so far is that Oqtane content management system, but that's too much tie-in for us.
I have just tried the demo here:
https://github.com/isc30/blazor-lazy-loading/issues?q=is%3Aissue+is%3Aopen
From what I see from the network tab in the chrome dev tools and with fiddler also It seems that all the assemblies are downloaded at the application startup and not at the time of the first usage of the component.
Is there something wrong in my tests?
I test this case with Visual Studio, the break point was not hit in the module.
We need to have the targets
to copy the library DLLs as part of some other package
Pops in white for a few milliseconds while the initial _lazy.json
request is made
Hi,
I discovered your project reading dotnet/aspnetcore#5465
and now I am starting to understand how it works because in my branch https://github.com/enkodellc/blazorboilerplate/tree/development I am trying to modularize the UI, but at the moment I used hacks because in my webassembly version I do not know how to dinamically load modules (see https://github.com/enkodellc/blazorboilerplate/blob/development/src/Client/BlazorBoilerplate.Client/Program.cs)
With the blazor server version I can load modules at runtime and use the pages inside without any problem, but I have to include an unwanted reference to them only if the have a wwwroot folder.
So studying your repository I plan to remove module references in (https://github.com/enkodellc/blazorboilerplate/blob/development/src/Server/BlazorBoilerplate.Server/BlazorBoilerplate.Server.csproj)
Good work!
From the ModulesHost, I need to find a way to enumerate all the modules (project references and nuget packages).
In the end I might just visit every reference that references Razor.Components for this.
Or have an ItemGroup and let the user define the modules manually.
The self-hosting module idea is nice, until you start adding dependencies between them. In that case, the amount of generated DLLs becomes massive.
It's better to have a single "source of truth" from where the lazy DLLs are loaded.
This will make the migration to LazyBlazor simpler and simplify custom manifest generation in the future too.
And you cannot override the ContentTypeProvider
Mentioned in #42
BLLManifestGeneratorAssemblyNames
worksUnable to build Demo solution. The build process failed with error:
Error MSB4018 The "ResolveBlazorRuntimeDependencies" task failed unexpectedly.
System.IO.FileNotFoundException: Could not load file or assembly 'WasmHost.dll' or one of its dependencies. The system cannot find the file specified.
File name: 'WasmHost.dll' ---> System.IO.FileNotFoundException: The system cannot find the file specified. (Exception from HRESULT: 0x80070002)
at System.Reflection.AssemblyName.nGetFileInformation(String s)
at System.Reflection.AssemblyName.GetAssemblyName(String assemblyFile)
at Microsoft.AspNetCore.Components.WebAssembly.Build.ResolveBlazorRuntimeDependencies.ResolveRuntimeDependenciesCore(String entryPoint, IEnumerable1 applicationDependencies, IEnumerable
1 monoBclAssemblies)
at Microsoft.AspNetCore.Components.WebAssembly.Build.ResolveBlazorRuntimeDependencies.Execute()
at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
at Microsoft.Build.BackEnd.TaskBuilder.d__26.MoveNext()
WasmHost C:\Users\BKV\.nuget\packages\microsoft.aspnetcore.components.webassembly.build\3.2.0-preview4.20210.8\targets\Blazor.MonoRuntime.targets 324
Document how to configure a standard AspNetCore host to serve DLLs (UseLazyLoading)
Docker is great, but it doesn't support multiple targets that run on a image.
With earthly, I could abstract the different steps (build, test, pack, etc) nicely and get it integrated to CI.
https://github.com/vladaionescu/earthly
I need to generate 3 NuGet packages (at least)
Implementing a custom Router is a pain ATM, due to all the route matching utilities being internal
and the handlers being constrained to Type
.
RouteContext
, RouteEntry
, RouteTable
, ...) should be public
.RouteContext.Handler
needs to be of type object
to allow implementing custom handlers. Unhandled exception rendering component: Cannot consume scoped service 'System.Net.Http.HttpClient' from singleton 'BlazorLazyLoading.Abstractions.IContentFileReader'.
System.InvalidOperationException: Cannot consume scoped service 'System.Net.Http.HttpClient' from singleton 'BlazorLazyLoading.Abstractions.IContentFileReader'.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.VisitScopeCache(ServiceCallSite scopedCallSite, CallSiteValidatorState state)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.CallSiteValidatorState, Microsoft.Extensions.DependencyInjection, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Type, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(ServiceCallSite callSite, CallSiteValidatorState argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.VisitConstructor(ConstructorCallSite constructorCallSite, CallSiteValidatorState state)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.CallSiteValidatorState, Microsoft.Extensions.DependencyInjection, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Type, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSiteMain(ServiceCallSite callSite, CallSiteValidatorState argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.VisitRootCache(ServiceCallSite singletonCallSite, CallSiteValidatorState state)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.CallSiteValidatorState, Microsoft.Extensions.DependencyInjection, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Type, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(ServiceCallSite callSite, CallSiteValidatorState argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.VisitConstructor(ConstructorCallSite constructorCallSite, CallSiteValidatorState state)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.CallSiteValidatorState, Microsoft.Extensions.DependencyInjection, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Type, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSiteMain(ServiceCallSite callSite, CallSiteValidatorState argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.VisitRootCache(ServiceCallSite singletonCallSite, CallSiteValidatorState state)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.CallSiteValidatorState, Microsoft.Extensions.DependencyInjection, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Type, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(ServiceCallSite callSite, CallSiteValidatorState argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateCallSite(ServiceCallSite callSite)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.Microsoft.Extensions.DependencyInjection.ServiceLookup.IServiceProviderEngineCallback.OnCreate(ServiceCallSite callSite)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.CreateServiceAccessor(Type serviceType)
at System.Collections.Concurrent.ConcurrentDictionary`2[[System.Type, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Func`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope, Microsoft.Extensions.DependencyInjection, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].GetOrAdd(Type key, Func`2 valueFactory)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.AspNetCore.Components.ComponentFactory.<>c__DisplayClass6_0.<CreateInitializer>g__Initialize|2(IServiceProvider serviceProvider, IComponent component)
at Microsoft.AspNetCore.Components.ComponentFactory.PerformPropertyInjection(IServiceProvider serviceProvider, IComponent instance)
at Microsoft.AspNetCore.Components.ComponentFactory.InstantiateComponent(IServiceProvider serviceProvider, Type componentType)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateComponent(Type componentType)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateChildComponentOnFrame(RenderTreeFrame& frame, Int32 parentComponentId)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(DiffContext& diffContext, Int32 frameIndex)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(DiffContext& diffContext, Int32 frameIndex)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(DiffContext& diffContext, Int32 newFrameIndex)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer renderer, RenderBatchBuilder batchBuilder, Int32 componentId, ArrayRange`1 oldTree, ArrayRange`1 newTree)
at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
In razor page
@code {
[Inject]
private PublicViewDataService publicViewDataService { get; set; }
private Tag[] tags;
protected override async Task OnInitializedAsync()
{
tags = await publicViewDataService.tags();
}
}
publicViewDataService
public class PublicViewDataService : INotifyPropertyChanged
{
private readonly IServiceProvider _serviceProvider;
//private HttpClient Http;
public PublicViewDataService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private Tag[] _tags;
public async Task<Tag[]> tags()
{
if (_tags == null)
{
using (var scope = _serviceProvider.CreateScope())
{
var Http = scope.ServiceProvider.GetRequiredService<HttpClient>();
_tags = await Http.GetFromJsonAsync<Tag[]>("api/data/gettags");
}
}
return _tags;
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.