blazor webassembly 加載優化方案
對於 blazor webassembly 加載方案的優化是針對於 webassembly 首次加載,由於 blazor webassembly 是在首次加載的時候會將.net core 的所有程式集都會加載到瀏覽器中,並且在使用的時候可能引用了很多第三方的 dll,導致加載緩慢。
優化方案 :
1. 壓縮
發布 blazor webassembly 應用時,將在發布過程中對輸出內容進行靜態壓縮,從而減小應用的大小,並免去運行時壓縮的開銷。使用以下壓縮算法:
从 google/brotli GitHub repository 中获取 JavaScript Brotli 解码器。 缩小的解码器文件被命名为 decode.min.js,并且位于存储库的 js 文件夹中。
修改wwwroot/index.html 文件代码 ,添加autostart="false" ,阻止默认启动加载程序集
<script src="_framework/blazor.webassembly.js" autostart="false"></script>
在 Blazor 的 <script> 标记之后和结束 </body> 标记之前,添加以下 JavaScript 代码 <script> 块:
<script type="module">
import { BrotliDecode } from './decode.min.js';
Blazor.start({
loadBootResource: function (type, name, defaultUri, integrity) {
// 注意:这里使用localhost的时候不会启动压缩
if (type !== 'dotnetjs' && location.hostname !== 'localhost') {
return (async function () {
const response = await fetch(defaultUri + '.br', { cache: 'no-cache' });
if (!response.ok) {
throw new Error(response.statusText);
}
const originalResponseBuffer = await response.arrayBuffer();
const originalResponseArray = new Int8Array(originalResponseBuffer);
const decompressedResponseArray = BrotliDecode(originalResponseArray);
const contentType = type ===
'dotnetwasm' ? 'application/wasm' : 'application/octet-stream';
return new Response(decompressedResponseArray,
{ headers: { 'content-type': contentType } });
})();
}
}
});
</script>
壓縮方案將減少加載時間,大概是壓縮 dll 的三分之一大小,效果如圖

在使用autostart="false"标记以后不会启动就加载,加载程序集将在上面的代码块中执行,默认是加载 br。
2. 延遲加載程式集
通過等待應用程式集直到需要時才加載,提高 blazor webassembly 應用啟動性能,這種方式稱為“延遲加載”。
將 blazor webassembly 項目拆分細緻,通過延遲加載程式集提升 blazor webassembly 首次加載時間,我們將通過一個案例來講解延遲加載程式集。
创建一个空的 Blazor WebAssembly 项目: 项目名称Demand:

取消HTTPS 使用渐进式 Web 应用程序:

在创建 Razor 类库,项目名称:Demand.Components, 然后默认选项创建项目:

创建Components.razor文件,并且删除多余文件,效果如图:

在Components.razor添加以下代码:
@inject NavigationManager NavigationManager @page "/components"
<div>
<h1>Components</h1>
</div>
<button @onclick="Goto">跳转到首页</button>
@code { private void Goto() { NavigationManager.NavigateTo("/"); } }
在Demand项目中引用Demand.Components项目。
修改App.razor文件 ,代码如下:
@using System.Reflection @using
Microsoft.AspNetCore.Components.WebAssembly.Services @*
这里需要注意,WebAssembly是默认注入的,但是Server并没有注入 。
在Server中手动注入 builder.Services.AddScoped<LazyAssemblyLoader
>(); *@ @inject LazyAssemblyLoader AssemblyLoader
<Router
AppAssembly="@typeof(App).Assembly"
AdditionalAssemblies="@lazyLoadedAssemblies"
OnNavigateAsync="@OnNavigateAsync"
>
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
@code { private List<Assembly>
lazyLoadedAssemblies = new(); private async Task
OnNavigateAsync(NavigationContext args) { try { if (args.Path ==
"components") { // 这里自定义Demand.Components依赖的程序集, var assemblies
= await AssemblyLoader.LoadAssembliesAsync(new[] { "Demand.Components.dll"
}); // 添加到路由程序集扫描中 lazyLoadedAssemblies.AddRange(assemblies); } }
catch (Exception ex) { } } }</Assembly
></LazyAssemblyLoader
>
處理指定路由組件需要加載的程式集。
打开Demand项目文件,如果在 Debug 模式下可以使用添加以下忽略列表:
<ItemGroup>
<BlazorWebAssemblyLazyLoad Include="System.Xml.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Xml.XmlSerializer.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Xml.XmlDocument.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Xml.XPath.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Xml.XPath.XDocument.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Xml.XDocument.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Xml.Serialization.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Xml.ReaderWriter.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Xml.Linq.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Windows.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.Quic.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.Compression.ZipFile.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Runtime.Numerics.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Collections.Immutable.dll" />
<BlazorWebAssemblyLazyLoad Include="Microsoft.Win32.Registry.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Web.HttpUtility.dll" />
<BlazorWebAssemblyLazyLoad Include="System.ValueTuple.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Security.AccessControl.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.Mail.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.NameResolution.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.UnmanagedMemoryStream.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.Pipes.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.Pipes.AccessControl.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.Pipelines.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.FileSystem.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.FileSystem.Watcher.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.FileSystem.Primitives.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.FileSystem.DriveInfo.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.FileSystem.AccessControl.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Data.Common.dll" />
<BlazorWebAssemblyLazyLoad Include="Microsoft.CSharp.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Console.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Core.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Data.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Data.DataSetExtensions.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Drawing.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Drawing.Primitives.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Diagnostics.TraceSource.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Diagnostics.Tools.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Diagnostics.TextWriterTraceListener.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Diagnostics.StackTrace.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Diagnostics.Process.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Diagnostics.FileVersionInfo.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Diagnostics.DiagnosticSource.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Diagnostics.Debug.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Diagnostics.Contracts.dll" />
<BlazorWebAssemblyLazyLoad Include="Microsoft.AspNetCore.Authorization.dll" />
<BlazorWebAssemblyLazyLoad Include="Microsoft.AspNetCore.Components.Forms.dll" />
<BlazorWebAssemblyLazyLoad Include="Microsoft.AspNetCore.Metadata.dll" />
<BlazorWebAssemblyLazyLoad Include="Microsoft.Extensions.Configuration.Binder.dll" />
<BlazorWebAssemblyLazyLoad Include="Microsoft.Extensions.FileProviders.Abstractions.dll" />
<BlazorWebAssemblyLazyLoad Include="Microsoft.Extensions.FileProviders.Physical.dll" />
<BlazorWebAssemblyLazyLoad Include="Microsoft.Extensions.Configuration.FileExtensions.dll" />
<BlazorWebAssemblyLazyLoad Include="Microsoft.Extensions.FileSystemGlobbing.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.MemoryMappedFiles.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.IsolatedStorage.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.Compression.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.Compression.FileSystem.dll" />
<BlazorWebAssemblyLazyLoad Include="System.IO.Compression.Brotli.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Formats.Tar.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Formats.Asn1.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.WebSockets.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Private.DataContractSerialization.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Private.Xml.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Security.Cryptography.dll" />
<BlazorWebAssemblyLazyLoad Include="Microsoft.VisualBasic.dll" />
<BlazorWebAssemblyLazyLoad Include="Microsoft.VisualBasic.Core.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Threading.Tasks.Dataflow.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Text.Encoding.CodePages.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.WebSockets.Client.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Private.Xml.Linq.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Text.RegularExpressions.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.Sockets.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.WebClient.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.WebProxy.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.Ping.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Security.Cryptography.X509Certificates.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.WebHeaderCollection.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Security.Cryptography.OpenSsl.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Security.Cryptography.Encoding.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Security.Cryptography.Csp.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Security.Cryptography.Cng.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Security.Claims.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Security.Cryptography.Algorithms.dll" />
<BlazorWebAssemblyLazyLoad Include="Microsoft.Win32.Primitives.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.HttpListener.dll" />
<BlazorWebAssemblyLazyLoad Include="System.AppContext.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.NetworkInformation.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.Requests.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.Primitives.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.Security.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.ServicePoint.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.Http.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Globalization.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Globalization.Calendars.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Globalization.Extensions.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Net.Http.Json.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Web.dll" />
<BlazorWebAssemblyLazyLoad Include="WindowsBase.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Resources.Writer.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Resources.ResourceManager.dll" />
<BlazorWebAssemblyLazyLoad Include="System.Resources.Reader.dll" />
</ItemGroup>
這些是不常用的一些程式集,如果出現以下錯誤,請將找不到的程式集刪除按需加載配置,

但是如果使用了上面的按需加載配置,在發布的時候會出現異常比如下面這個圖這樣;錯誤原因是 blazor webassembly 在發布的時候默認使用裁剪,由於以下程式集剛剛好是沒有使用的,在裁剪以後會配置按需加載,但是它已經被裁剪了,所以導致無法找到按需加載的程式集;只要刪除報錯的程式集即可;這個只有在發布的時候才會出現,debug 還是可以繼續使用上面的按需加載的配置,可以在調試的時候響應更快:

然後下一步.
添加指定项目的按需加载配置, 我们将Demand.Components项目配置上去,
<ItemGroup>
<BlazorWebAssemblyLazyLoad Include="Demand.Components.dll" />
</ItemGroup>
修改Pages/Index.razor文件代码:
@page "/" @inject NavigationManager NavigationManager
<h1>Hello, world!</h1>
<button @onclick="Goto">跳转到components</button>
@code { private void Goto() { NavigationManager.NavigateTo("/components"); } }
然后启动项目,打开 F12 开发者调试工具,点击应用程序,找到存储,点击清除网站数据(第一次加载以后程序集会缓存起来):

点击网络,然后刷新界面,我们看到这里并不会加载Demand.Components.dll,但是这里的程序集:

然後點擊界面的按鈕:

这个时候在来到调试工具的网络, 我们看到Demand.Components.dll已经被加载了,当我们使用的时候这个程序集才会加载,并且第二次加入界面的时候不会重复加载程序集:

然後我們將項目發布(發布的時候記得上面提到的裁剪導致程式集丟失無法使用按需加載的問題,只要在按需加載的配置中清理掉被裁剪的程式集即可):

然後使用 docker compose 部署一個 nginx 代理查看效果:
创建docker-compose.yml文件,并且添加以下代码,在docker-compose.yml的当前目录下创建 conf.d和wwwroot俩个文件夹:
services:
nginx:
image: nginx:stable-alpine
container_name: nginx
volumes:
- ./conf.d:/etc/nginx/conf.d
- ./wwwroot:/wwwroot
ports:
- 811:80
在conf.d中创建webassembly.conf,并且添加以下代码:
server {
listen 80;
server_name http://localhost;
location / {
root /wwwroot;
index index.html;
}
}
然后在docker-compose.yml所属目录中使用docker-compose up -d启动 nginx 服务
打开浏览器访问http://127.0.0.1:811/ (不要使用 localhost 访问,默认不会启动压缩的)然后打开 f12 调试工具,并且在应用程序中清理掉存储,在打开网络选项,刷新浏览器,加载完成,优化到了 2.3MB,启动压缩,并且在发布的时候裁剪了未使用的程序集:

極致優化 到 1mb
在Demand项目文件中添加以下配置, 以下配置禁用了一些功能,比如全球化等
<PublishTrimmed>true</PublishTrimmed>
<InvariantGlobalization>true</InvariantGlobalization>
<BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
<EventSourceSupport>false</EventSourceSupport>
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
<MetadataUpdaterSupport>false</MetadataUpdaterSupport>
<UseNativeHttpHandler>true</UseNativeHttpHandler>
然後我們繼續上面的操作將其發布,並且部署到 nginx 中。
在网络中查看加载大小,我们看到已经来到了 1MB,去掉一些 js 其实应该更小,这样它的加载问题得到了很大的解决(来自小夜鲲大佬的建议)

結尾
如果您有更好的優化方案可以聯繫我.
來自 token 的分享。
- demo 在線訪問:http://webassembly.tokengo.top
- GitHub: https://github.com/239573049/demand
- Gitee: https://gitee.com/hejiale010426/demand
blazor 交流群:452761192
本文來自轉載。
作者:token
原文標題:如何將 webassembly 優化到 1mb?
原文連結:https://www.cnblogs.com/hejiale010426/p/17076817.html