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.3k stars 9.96k forks source link

Improve the load time performance of Blazor WebAssembly apps on low-end mobile devices #42284

Open danroth27 opened 2 years ago

danroth27 commented 2 years ago

We've been hearing reports from users that load performance of Blazor WebAssembly apps on low-end mobile devices can be very slow. For example, this user on Twitter reported "bootstrapping is very slow on low-end mobile devices (~10s), caching doesn't help this". We should investigate where the time is being spent on these devices and evaluate options for improvement.

The first step is to collect some performance profiles. Any help is appreciated! 🙏

danroth27 commented 2 years ago

Some more examples of this feedback:

https://www.reddit.com/r/Blazor/comments/iorby5/why_is_blazor_loading_so_long/ https://twitter.com/lupusa1/status/1260309165777526784: "I mostly work on blazor wasm and it is slow on mobile, so for now I try to be prioritized to desktop solutions." https://twitter.com/Savaged_US/status/1115369807019425793 - "Blazor and dotnet are just too slow for now (especially on low-power mobile devices)" https://twitter.com/Tibcsi_/status/1304509087598682116: "Blazor webassembly is still slow on a mid range mobile"

danroth27 commented 2 years ago

Another report of 15s load time on mobile in this issue: https://github.com/dotnet/aspnetcore/issues/41909

rogihee commented 2 years ago

I experience this as well on my oldest iPad (5th gen) - refreshing is still slow (~5-7s of pure loading), so caching is not helping. Nothing fancy in the app. How can we help profile this?

mandeep-sps commented 2 years ago

Hi Team,

I have a .Net 6 Blazor WASM app with Server Hosted Code. Before Publishing the APP I have added a few Config lines in the project file like this:-

  1. net6.0
  2. false
  3. false
  4. true
  5. true
  6. true
  7. link

and Added the Brotli Compression Decoce.js file and some code on the Index.html Page. Now my APP downloads only 1.5 MB of resources and Its loads into 1.5 Secs. SO I have Optimized my app using these settings.

image

If I am anything missing Please suggest me.

Thanks

Alerinos commented 2 years ago

@mandeep-sps The problem occurs on older devices. Use throttling and do more tests

emorell96 commented 2 years ago

Is this normal? I am testing my own application and I've done all the required things: do not use AOT (bigger files), use brotli (dynamic and static), use http3 and http2, etc... and I've got the load times of the app on my dev machine to be around 2.5 s which is acceptable. But where I am seeing the biggest issue is here: image

So Blazor finishes loading its files at the 400 ms mark, but the first application request is ran a whole second later:

image

image

So is it normal for blazor to take more than a second in starting up? It feels awfully long tbh.

ScottKane commented 2 years ago

For my Blazor WASM app initial loading is taking 5-10 seconds which is bad enough but on click events from buttons are taking around 2 seconds to fire when accessing the site from a mobile device and often not firing at all resulting in a user having to repeatedly press buttons to get something to happen (doesn't happen from a PC web browser) which is obviously making the app extremely sluggish to use. I would understand if these buttons were submitting data to the server, but when they only trigger a modal to pop up with everything happening locally to the client, I would expect this to be a lot faster.

danroth27 commented 2 years ago

@ScottKane For the slow event firing issues your seeing, could you please open a separate issue with the specs of the devices where you see this problem including the browser version and a repro project that demonstrates the performance issue?

emorell96 commented 2 years ago

@danroth27 is the delay of about a second between Blazor assemblies downloading and the app starting its function normal? (see above: https://github.com/dotnet/aspnetcore/issues/42284#issuecomment-1181850985)

ScottKane commented 2 years ago

@danroth27 I opened https://github.com/dotnet/aspnetcore/issues/43090 for this, I'm currently rebuilding the client from scratch to figure at at what point the performance dies. So far the only thing I can point to causing it is CascadingValue Value="_hubConnection" as the new client doesn't have that yet and seems to be performing fine even without AOT

Shalxxx commented 2 years ago

A lot of complaints are about the initial start speed because of several MBs of runtime DLLs that must be first downloaded while on slow mobile networks.

Is there any technical difficulty that prevents rendering the page on the server and sent to the device while DLLs are loading in the background? And seamlessly switch from server-generated-client-side to client-side without specifically implementing server-side? Such a hybrid solution would solve the main issue of the Blazor.

charlesroddie commented 2 years ago

A lot of complaints are about the initial start speed because of several MBs of runtime DLLs that must be first downloaded while on slow mobile networks.

A large contributor is https://github.com/dotnet/aspnetcore/issues/35302 .

danroth27 commented 2 years ago

Is there any technical difficulty that prevents rendering the page on the server and sent to the device while DLLs are loading in the background?

@Shalxxx Blazor already supports prerendering from the server.

And seamlessly switch from server-generated-client-side to client-side without specifically implementing server-side? Such a hybrid solution would solve the main issue of the Blazor.

This is something we hope to explore for .NET 8: https://github.com/dotnet/aspnetcore/issues/38128

awillSoftwares commented 2 years ago

@danroth27 Doens't solve. The page become unresponsive until the client completely load the big bloated binaries. Prerendering works well when the client load fast enough. Prerendering doesn't work well when system render some content that depends on authentication. Server-side render is good only for search index crowlers, or maybe not even that.

danroth27 commented 2 years ago

@awillSoftwares You're correct that prerendering only improves the perceived load time of the page. We are discussing how we might in the future enable a combined model where the app starts off with Blazor Server and then transitions to Blazor WebAssembly after the app has been downloaded. Prerendering with authentication is also something we're working on for .NET 7: https://github.com/dotnet/aspnetcore/issues/27592.

cirrusone commented 2 years ago

@danroth27 Can you also consider what happens if user device/browser does not support WebAssembly. Currently the User-Agent header appears to be the only way to detect device details which is pretty 'wild'. It would be nice to have some property or method such as .IsWebAssemblySupported() which could test if WebAssembly will actually run on device but without freezing or crashing the application. This would be useful for manual switching between Server/Wasm.

yugabe commented 2 years ago

@cirrusone most current browsers support WebAssembly, but you won't be able to detect it reliably on the server side. On the client, it's basically as easy as testing for the existence of the window global variable WebAssembly. Related: How can I check if a browser supports WebAssembly? (StackOverflow)

There are some instances when WebAssembly itself is supported, but not enabled. The Edge browser does disable WebAssembly support in some cases when using "Enhanced security", or a group policy might disable it for a company. It essentially means checking for the same thing as above.

sajjadarashhh commented 2 years ago

I have same issue in .net 6 blazor wasm on low-level(desktop) devices and i tried to publish aot mode to help them But in aot mode my app is slower in loadtime,runtime and bigger than normal mode.

mandeep-sps commented 2 years ago

@sajjadarashhh Hey Please try to Add Brotli Compressresion into your WASM Project. I am sharing the code Below.

and Some Line of code into Proj. file May be That will Decrease the first load time from your WASM project. Make sure are you using Dotnet 6 SDK.
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
<BlazorWebAssemblyPreserveCollationData>false</BlazorWebAssemblyPreserveCollationData>
<PublishTrimmed>true</PublishTrimmed>
<BlazorEnableCompression>true</BlazorEnableCompression>
<InvariantGlobalization>true</InvariantGlobalization>
<TrimMode>link</TrimMode>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<!--<RunAOTCompilation>true</RunAOTCompilation>-->

GeeSuth commented 2 years ago

@mandeep-sps How does this actually work?!! decode.js where come from?

jirisykora83 commented 2 years ago

@mandeep-sps How does this actually work?!! decode.js where come from?

https://docs.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/webassembly?view=aspnetcore-6.0#compression

mandeep-sps commented 2 years ago

@yugabe @jirisykora83 I have added the Brotli Compression into the WASM App. It's working fine at my end. BR applied to all the DLLs files and as well as to Static Files. Please check my Staging Demo Website for Reference purposes. http://182.75.88.147:8126/

jirisykora83 commented 2 years ago

@yugabe @jirisykora83 I have added the Brotli Compression into the WASM App. It's working fine at my end. BR applied to all the DLLs files and as well as to Static Files. Please check my Staging Demo Website for Reference purposes. http://182.75.88.147:8126/

I check your site and you are right i load slowly even at second load (where most of the dll should be cached). That dont have to be low-end mobile it is even on my desktop. Hard to say when currently there isnt easy way to profile WASM app.

note: Server location seems to be india (?) and my location is EU so "some" latency is expected.

arthastheking113 commented 2 years ago

We are discussing how we might in the future enable a combined model where the app starts off with Blazor Server and then transitions to Blazor WebAssembly after the app has been downloaded.

The switching model in runtime will be great since we take all advantages of both models.

sgf commented 2 years ago

Blazor's performance always slow,never fast 😂

awillSoftwares commented 2 years ago

@sgf Slow as hell. And the solution proposed isn't a real solution

sgf commented 2 years ago

i hava an idea

use machine learning/statistics to cherry pick the most usefully API for the runtime libraries. and reduce most useless api. then should be can reduce the Blazor runtime's size.

give develops 2 options: full rutime(10mb)/tiny runtime(1mb)

You can not have your cake and eat it. We have to give up something

yugabe commented 2 years ago

@sgf It's a solved problem, as .NET supports trimming assemblies already, and that is not the issue. I'm not sure if you're joking, but machine learning has nothing to do with the issue here either. The problem is that there are certain low end mobile devices that load Blazor slower than they are supposed to and it needs to be investigated why that discrepancy is.

sgf commented 2 years ago

@sgf It's a solved problem, as .NET supports trimming assemblies already, and that is not the issue. I'm not sure if you're joking, but machine learning has nothing to do with the issue here either. The problem is that there are certain low end mobile devices that load Blazor slower than they are supposed to and it needs to be investigated why that discrepancy is.

im not sure,but in my PC(i7 6700). the default created Blazor WebAssembly Project in release mode, the page load need 1.5-2s (Ctrl+F5 every time always need). the broswer is Edge lastest ver.

yugabe commented 2 years ago

@sgf So what are you exactly proposing here? Just asking because you're pinging the people on the thread. A 2 second loading time is more than par for the course, given that even JavaScript frameworks need that or more time to load.

sgf commented 2 years ago

@sgf So what are you exactly proposing here? Just asking because you're pinging the people on the thread. A 2 second loading time is more than par for the course, given that even JavaScript frameworks need that or more time to load.

i have no much request, 500ms enough. if got 200ms,thats will be great.

you know there is many PC is slow then my,right? so,if my 1.5s ,they maybe need 3-4s.

and you know that's the localhost tests got. if on the internet thats maybe need 5s-50s.

Laftek commented 2 years ago

@awillSoftwares You're correct that prerendering only improves the perceived load time of the page. We are discussing how we might in the future enable a combined model where the app starts off with Blazor Server and then transitions to Blazor WebAssembly after the app has been downloaded. Prerendering with authentication is also something we're working on for .NET 7: #27592.

This would be gamechanger! Hopefully it will make it to .NET8

sajjadarashhh commented 2 years ago

Problem here is not blazor performance versus js! We use wasm and when comparing blazor wasm performance vs native wasm, blazor is very slower than wasm. When we compare Js vs wasm, wasm performance 1.5 time faster and better than js

Tiberriver256 commented 1 year ago

Not sure if it's useful or not but this doesn't seem to be limited to just low-end mobile devices.

My stats from visiting mudblazor.com:

Time to download assets: 10s Bootstrap time: 5s

My specs: Intel(R) Core(TM) i7-10850H CPU @ 2.70GHz 2.71 GHz 32GB Memory 60Mbps download speed

Their solution is to put their icon on the page while the app starts up:

image

ericgrantholland commented 1 year ago

@danroth27 @javiercn Would it be possible to have Microsoft spend some resources on building a working example of the approach @javiercn describes in this issue(https://github.com/dotnet/aspnetcore/issues/41909)?

Here is the approach in case you don't want to redirect to that link: If you want to keep using .NET and C# to author your web UIs but you need fast startup times, you can consider using Blazor Server to handle the initial page load on first visits and use separate logic to download the Blazor Webassembly bits in the background so that on subsequent visits you can start with the webassembly runtime already downloaded.

Lots of open questions here:

  1. How to download webassembly bits in the background
  2. How to shut off serverside stuff after bits are downloaded
  3. How to store webassembly bits so subsequent visits to the site don't require a re-download.

I truly believe this approach would make many in the dotnet community happy. We want to use WASM, but we honestly can't accept the initial load time for most use cases.

Laftek commented 1 year ago

@danroth27 @javiercn Would it be possible to have Microsoft spend some resources on building a working example of the approach @javiercn describes in this issue(#41909)?

Here is the approach in case you don't want to redirect to that link: If you want to keep using .NET and C# to author your web UIs but you need fast startup times, you can consider using Blazor Server to handle the initial page load on first visits and use separate logic to download the Blazor Webassembly bits in the background so that on subsequent visits you can start with the webassembly runtime already downloaded.

Lots of open questions here:

  1. How to download webassembly bits in the background
  2. How to shut off serverside stuff after bits are downloaded
  3. How to store webassembly bits so subsequent visits to the site don't require a re-download.

I truly believe this approach would make many in the dotnet community happy. We want to use WASM, but we honestly can't accept the initial load time for most use cases.

Please microsoft, do this as an example. Thanks.

mandeep-sps commented 1 year ago

Maybe Microsoft will Decrease the load time in Dotnet 7 Blazor WASM. I am also Expecting this from Blazor Dev Team.

nh43de commented 1 year ago

@awillSoftwares You're correct that prerendering only improves the perceived load time of the page. We are discussing how we might in the future enable a combined model where the app starts off with Blazor Server and then transitions to Blazor WebAssembly after the app has been downloaded. Prerendering with authentication is also something we're working on for .NET 7: #27592.

Ok this may sound naive, but currently all the magic starts with Blazor.start at the bottom of the page. Is it possible that each component could get its own trimmed runtime, or otherwise somehow chunk and prioritize the payload so that, for example, users can start searching while the rest of the dashboard loads? And basically each component will get its own Blazor.start method for its packaged runtime, and only load the shared dependencies that component specifically needs to start.

And no offense but the hot switch between Blazor Server and WASM seems a bit shaky. Blazor WASM and Server already have enough transient failure points that degrade the user experience. Adding more failure points and complications may not increase the developer/business desirability to use Blazor for reaching the masses.

yugabe commented 1 year ago

@nh43de

Is it possible that each component could get its own trimmed runtime, or otherwise somehow chunk and prioritize the payload so that, for example, users can start searching while the rest of the dashboard loads? And basically each component will get its own Blazor.start method for its packaged runtime, and only load the shared dependencies that component specifically needs to start.

I don't think this would be too effective. With trimming only the code your app actually needs is being delivered to the client. I guess it would be possible to trim the app multiple times based on multiple roots, but that exponentially increases the number of paths needs to be considered, and in effect, would result in types being split. If no types are split, not much is gained, but in .NET a type is a type, so there's no way to "merge" two different declarations on demand. And the wins will probably be insignificant. For your app to bootstrap at all you'd need like 80% of all assemblies with most of its types anyways. You could do a proof of concept I guess, build one app with your search function implemented and the same but with the dashboard implemented. The difference of the published apps' bits will be what you would win at most.

And no offense but the hot switch between Blazor Server and WASM seems a bit shaky. Blazor WASM and Server already have enough transient failure points that degrade the user experience. Adding more failure points and complications may not increase the developer/business desirability to use Blazor for reaching the masses.

I assume the team expects this to be viable exactly because:

As for its "shakiness": I expect this to be about as shaky as Blazor Server is. It's a nice feature for those who want them, and I guess it won't be forced on you to use. Options are good.

yugabe commented 1 year ago

@nh43de Without delving too much into it, you're not comparing the right things. Your 4MBs include images on one site, and no images are present on the other. The only relevant basis for comparison would be if you pairwise took the assemblies in each project and compared those for size. If you think this is worth pursuing, I guess you could open a separate issue and supply a demo with some test results.

awillSoftwares commented 1 year ago

@yugabe Even brotli compressed, Blazor minimal size is 1.8 MB. This is too much. It's not 4MB but still almoust 2 MB.

rabberbock commented 1 year ago

We have a Blazor WASM app with thousands of active users and the number one complaint we get is the load time/initialization being slow. The slowness is not just the first time visiting the site and is slow for subsequent visits as well. Most of the time the complaints comes from mobile users, but we have definitely seen very slow startup times on desktop as well. Hoping that .NET 8 can tackle these issues. Happy to provide details to help out here. Thanks!

NguyenSen commented 1 year ago

If you can't improve, you should remove the client feature. It's not worth developing. Too slow compared to other freamwork clients

todosrc commented 1 year ago

2023 is still slower than another SPA framework in the market? , by the way, end-user don't care about Web assembly or html+js

rogihee commented 1 year ago

We just hit this exact same issue for a very old i3 machine with 6.0 . Luckily our requirements were higher so we covered ourselves, but it took quite a long time to track down because it just gets stuck somewhere randomly in the startup sequence. Hopefully https://github.com/dotnet/runtime/pull/80849 will solve this.

charlesroddie commented 1 year ago

The true fix for this NativeAOT. Work on WASM compilation is in runtimelab. This will give: fast startup because it's fully AOTed (unlike Blazor AOT mode which uses JIT), and the smallest deployment sizes in dotnet (not sure about WASM but it's 1MB for x64) especially in reflection-free mode which reduces deployment size further and guarantees performance and type safety). They chose mono as the first way to deploy dotnet code because it was closest to finished at the time, but NativeAOT is the long term solution.

anton-kharchenko commented 1 year ago

The truth is Web Assembly at the moment very slow. My team considered to change from WA to Server side, because in benchmark we improved 3x loading time, from 6 to 2 sec. Especially, we feel it on the mobile devices. Hundreds of users every day complain to us for this. Unfortunately, for all .NET community, we didn't have great SPA via C#. But we all hope that in the next version of WA we shall get quickly framework.

LoupaLoupa commented 1 year ago

The truth is Web Assembly at the moment very slow. My team considered to change from WA to Server side, because in benchmark we improved 3x loading time, from 6 to 2 sec. Especially, we feel it on the mobile devices. Hundreds of users every day complain to us for this. Unfortunately, for all .NET community, we didn't have great SPA via C#. But we all hope that in the next version of WA we shall get quickly framework.

I feel you, unfortunately they focused on MAUI for dotnet 7.0 and Blazor Wasm improvement were delayed a full year which can break the deal. As of now, Wasm is only useful if you replace desktop apps with heavy local processing that take as long to load, your users won't mind because they are use to it. Using for typical web site is and may never be the most optimal choice.

But there is hope, if they can have this out for dotnet 8, it would change things a lot.

https://www.youtube.com/watch?v=48G_CEGXZZM

anton-kharchenko commented 1 year ago

@LoupaLoupa Thank you for the link. It looks pretty good and hopeful. Because in case when you have experience working with Wasm at the moment, you must think a lot to create new project by Wasm or not. Performance, very important thing in user life. When clients feel that We couldn't create a great application, they go to the opposite company, which started project by React or something else. We all wish to continue to use Wasm and improve it.

sajjadarashhh commented 1 year ago

We use wasm for our enterprise application in our case performance is not very important but thats slower than my assumes... And users talk to me in every meet for improving project.