-
Notifications
You must be signed in to change notification settings - Fork 9.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Blazor] Add lighthouse score to automated perf tests #29303
Comments
@drma-dev thanks for contacting us. We do some things out of the box to make loading efficient, but there are more things you can do. You could use preload link tags/headers to download critical assets early, like blazor.boot.json and the dlls so that the runtime can start faster. Prerendering should also help in this case to improve the score. |
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process. |
Do you have a concrete example that works @javiercn ? Thanks! |
Did you get any further in your attempts to speed up loading @drma-dev ? |
man, I believe that any blazor project happens this |
https://github.com/drma-dev/VerusDate if you can't reproduce, you can use my project |
Well, I can reproduce it, of course :-) |
This is in part an artifact of how lighthouse measures LCP. After we prerender we replace the prerendered contents with the interactive version of the DOM. Lighthouse uses that as the LCP. In reality the content is rendered much earlier (the prerendered content) but lighthouse decides that as we are replacing all the nodes (for the exact same hierarchy of nodes) the LCP is that event instead of the initial prerender. If you look at the layout shift, you can see that it's 0, because we in fact don't change the visual aspect of the DOM, just the actual nodes after the app boots up. |
Yeah, in my Blazor WASM .NET 5 with prerendering demo here http://tt-cw-blazor-wasm-prerendering.azurewebsites.net/ we do observe exactly what you are describing @javiercn (Source: https://github.com/thinktecture/blazor-wasm-things-to-know/tree/main/Prerendering) |
Hi - just wanted to leave a few notes here about how I recently achieved 100% across the board on Lighthouse. This was an exercise in achieving 100% in the tests, not in having a perfect web site - however, I do think the performance score being achieved in this way is not just whimsy - my test site works perfectly for me this way - ymmv. SEO 100%The SEO test simply requires having a My
Best Practices 100%I didn't need to do anything here - my Blazor WebAssembly application just passed with 100%. Accessibility 100%The requirements seem pretty slim for this, in my project I had to swap the standard Blazor Performance 100%As noted earlier, Lighthouse doesn't like the way Blazor WebAssembly works, in fact the version on web.dev records errors when Blazor.start() is called - see the Compromise section below For my site, it was acceptable for me to pre-render the home page, and then delay the Blazor startup like this
This has the effect of allowing Lighthouse to render/test the site without tripping over the Blazor load - but the end user has no idea because the home page is so entertaining/exciting 😜 they don't notice the delay. Reading the MS docs and following the links - I found all these properties that I could use in my
CompromiseDelaying the startup of the Blazor WASM module only helps to score high in Lighthouse - so I'm not suggesting it is for everyone - but if you have reasons to need to show a good score but not cause too much delay, then maybe a small delay in startup of 200ms or so would be a compromise you could bear. I have found my site scores around 95% for performance with only a 200ms delay in startup. Sample Report For 200ms delaySample Report For 1200ms delayFinal NotesI do not believe Brotli compression was used here - I've had trouble with that, so wasn't specifically enabling it - I think the Azure App Service is serving up gzipped files, just not Brotli. Another point to note is that if your users have fast/stable internet - you might be better disabling compression altogether - as the time spent uncompressing the files can sometimes be longer than the time it would take to download the larger uncompressed files. @javiercn @danroth27 Is there any impact on the streaming initialisation of wasm modules from serving them compressed? |
Is this an estimate or did you have a scenario where it made a measurable difference? Do you have any timings to measure how much difference it makes?
No, streaming compilation still works with compression. |
I experienced this in some testing, but it was not rigorous. In my simple scenario, I disabled compression in the browser dev tools, cleared all caches and reloaded the site - and I was seeing time to blazor being fully loaded and interactive reduce by a factor of around 5 - but I have not re-visited that testing to be sure it wasn't environmental. When I do, I'll report back. |
@SteveSandersonMS This is a .NET 6 Preview 4 AOT site hosted on Azure App Service - free tier in Europe. Hosting this way may be relevant, but this is what I am seeing: With browser default network settings and clean cache - 13 secondsWith compression disabled in the "network conditions" tab - 3 secondsI can send you the site details via DM if you want - or @danroth27 already has access to the source and the URL. |
That is interesting. It's hard to believe that decompression takes ~10 seconds unless you have an extraordinarily slow CPU. I wonder what else might be going on here. |
Yea, I don't have a super-fast CPU, but it's not terrible : The yellow line indicates starting to load and everything to the right is while it was loading (within a second or so) - the 100% peak is when it was loading the WASM module I think - network traffic had just stopped at that point. I've sent you a message on Twitter and sent an invite to the repo - if you want to look at it it's there - if not that's also fine - it's not a real-life project so there is no "problem" to solve - it's just interesting. |
Update on compression - it was Azure and the web.config that got deployed by Visual Studio's Publish. |
@SQL-MisterMagoo Did you figure out which part of the web.config was making the difference? i.e. what was it that was causing the client to perform so badly? |
@andrew-tevent The web.config that had been created by Visual Studio/Azure Publish did not have Brotli compression support I think - this is an example of the default it was producing <?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<remove fileExtension=".blat" />
<remove fileExtension=".dat" />
<remove fileExtension=".dll" />
<remove fileExtension=".json" />
<remove fileExtension=".wasm" />
<remove fileExtension=".woff" />
<remove fileExtension=".woff2" />
<mimeMap fileExtension=".blat" mimeType="application/octet-stream" />
<mimeMap fileExtension=".dll" mimeType="application/octet-stream" />
<mimeMap fileExtension=".dat" mimeType="application/octet-stream" />
<mimeMap fileExtension=".json" mimeType="application/json" />
<mimeMap fileExtension=".wasm" mimeType="application/wasm" />
<mimeMap fileExtension=".woff" mimeType="application/font-woff" />
<mimeMap fileExtension=".woff2" mimeType="application/font-woff" />
</staticContent>
<httpCompression>
<dynamicTypes>
<add mimeType="application/octet-stream" enabled="true" />
<add mimeType="application/wasm" enabled="true" />
</dynamicTypes>
</httpCompression>
<rewrite>
<rules>
<rule name="Serve subdir">
<match url=".*" />
<action type="Rewrite" url="wwwroot\{R:0}" />
</rule>
<rule name="SPA fallback routing" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="wwwroot\" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration> And the example from Microsoft Docs, which improved things: <?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<remove fileExtension=".dll" />
<remove fileExtension=".json" />
<remove fileExtension=".woff" />
<remove fileExtension=".woff2" />
<mimeMap fileExtension=".json" mimeType="application/json" />
<mimeMap fileExtension=".woff" mimeType="font/woff" />
<mimeMap fileExtension=".woff2" mimeType="font/woff2" />
<mimeMap fileExtension=".dat" mimeType="application/octet-stream" />
<mimeMap fileExtension=".dll" mimeType="application/octet-stream" />
<mimeMap fileExtension=".wasm" mimeType="application/wasm" />
<mimeMap fileExtension=".blat" mimeType="application/octet-stream" />
<mimeMap fileExtension=".js.gz" mimeType="application/javascript" />
<mimeMap fileExtension=".dat.gz" mimeType="application/octet-stream" />
<mimeMap fileExtension=".dll.gz" mimeType="application/octet-stream" />
<mimeMap fileExtension=".json.gz" mimeType="application/json" />
<mimeMap fileExtension=".wasm.gz" mimeType="application/wasm" />
<mimeMap fileExtension=".blat.gz" mimeType="application/octet-stream" />
<mimeMap fileExtension=".html.gz" mimeType="text/html" />
<mimeMap fileExtension=".css.gz" mimeType="text/css" />
<mimeMap fileExtension=".ico.gz" mimeType="image/x-icon" />
<mimeMap fileExtension=".svg.gz" mimeType="image/svg+xml" />
<mimeMap fileExtension=".js.br" mimeType="application/javascript" />
<mimeMap fileExtension=".dat.br" mimeType="application/octet-stream" />
<mimeMap fileExtension=".dll.br" mimeType="application/octet-stream" />
<mimeMap fileExtension=".json.br" mimeType="application/json" />
<mimeMap fileExtension=".wasm.br" mimeType="application/wasm" />
<mimeMap fileExtension=".blat.br" mimeType="application/octet-stream" />
<mimeMap fileExtension=".html.br" mimeType="text/html" />
<mimeMap fileExtension=".css.br" mimeType="text/css" />
<mimeMap fileExtension=".ico.br" mimeType="image/x-icon" />
<mimeMap fileExtension=".svg.br" mimeType="image/svg+xml" />
</staticContent>
<httpCompression>
<dynamicTypes>
<remove mimeType="text/*" />
<remove mimeType="application/javascript" />
<remove mimeType="image/svg+xml" />
</dynamicTypes>
<staticTypes>
<remove mimeType="text/*" />
<remove mimeType="application/javascript" />
<remove mimeType="image/svg+xml" />
</staticTypes>
</httpCompression>
<rewrite>
<outboundRules rewriteBeforeCache="true">
<rule name="Add Vary Accept-Encoding" preCondition="PreCompressedFile" enabled="true">
<match serverVariable="RESPONSE_Vary" pattern=".*" />
<action type="Rewrite" value="Accept-Encoding" />
</rule>
<rule name="Add Encoding Brotli" preCondition="PreCompressedBrotli" enabled="true" stopProcessing="true">
<match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
<action type="Rewrite" value="br" />
</rule>
<rule name="Add Encoding Gzip" preCondition="PreCompressedGzip" enabled="true" stopProcessing="true">
<match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
<action type="Rewrite" value="gzip" />
</rule>
<preConditions>
<preCondition name="PreCompressedFile">
<add input="{HTTP_URL}" pattern="\.(gz|br)$" />
</preCondition>
<preCondition name="PreCompressedBrotli">
<add input="{HTTP_URL}" pattern="\.br$" />
</preCondition>
<preCondition name="PreCompressedGzip">
<add input="{HTTP_URL}" pattern="\.gz$" />
</preCondition>
</preConditions>
</outboundRules>
<rules>
<rule name="Serve subdir">
<match url=".*" />
<action type="Rewrite" url="wwwroot\{R:0}" />
</rule>
<rule name="Rewrite brotli file" stopProcessing="true">
<match url="(.*)"/>
<conditions>
<add input="{HTTP_ACCEPT_ENCODING}" pattern="br" />
<add input="{REQUEST_FILENAME}" pattern="\.(js|dat|dll|json|wasm|blat|htm|html|css|ico|svg)$" />
<add input="{REQUEST_FILENAME}.br" matchType="IsFile" />
</conditions>
<action type="Rewrite" url="{R:1}.br" />
</rule>
<rule name="Rewrite gzip file" stopProcessing="true">
<match url="(.*)"/>
<conditions>
<add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" />
<add input="{REQUEST_FILENAME}" pattern="\.(js|dat|dll|json|wasm|blat|htm|html|css|ico|svg)$" />
<add input="{REQUEST_FILENAME}.gz" matchType="IsFile" />
</conditions>
<action type="Rewrite" url="{R:1}.gz" />
</rule>
<rule name="SPA fallback routing" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="wwwroot\" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration> |
@SQL-MisterMagoo Thanks! So you think client was much slower because it was using gzip instead of brotli? I saw the differences in the web.config - I was wondering if you knew specifically which bits fixed it? I thought compression was enabled in IIS using the default web.config that Blazor creates? Certainly I see gzip encoding in the HTTP requests in the browser. I wanted to understand which parts of the bigger web.config I needed - because there's rewrite rules which I don't really understand why they are needed (pretty sure I don't need the "Serve subdir" rule) |
I tried the sample web.config and it broke my app. First because I was renaming the .dll to .bin files to get around firewall issues - which I fixed by removing the incorrect blazor.boot.json.gz/br files - but then I was getting errors with .js and .css; Felt like server was serving up compressed versions but not setting the Content Encoding header in the response? |
@andrew-tevent Sorry, no I haven't analysed any further - I just updated and it worked, so I was happy. |
With the latest template, for the home page: Performance Performance can be increased from 88 to 99, by:
SEO SEO can be increased from 88 to 100, by:
I can send a PR if that helps. |
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process. |
Thanks for contacting us. We're moving this issue to the |
If I remember it correctly in older version compression broke hot reload or debugger. I am not sure if it is case anymore. |
I mentioned this in my comment ...
|
We've discussed this with the team and there are multiple work efforts that we have going that will improve the score here. |
Is there anything I can do to improve the performance of the system or any future plans for Blazor to do that out of the box?
The text was updated successfully, but these errors were encountered: