How to optimize WebAssembly to 1MB?

How to optimize WebAssembly to 1MB?

Optimize WebAssembly to 1MB

最后更新 1/30/2023 10:35 PM
Token
预计阅读 12 分钟
分类
Blazor
标签
.NET Blazor Wasm WebAssembly

Blazor WebAssembly Loading Optimization Scheme

The optimization of the Blazor WebAssembly loading scheme is for the first time when WebAssembly is loaded. Because Blazor WebAssembly loads all assemblies of. NET Core into the browser when it is loaded for the first time, and may reference many third-party DLLs when using it, resulting in slow loading.

** Optimization plan: **

1. compression

When publishing a Blazor WebAssembly application, the output content is statically compressed during the release process, reducing the size of the application and eliminating the overhead of runtime compression. Use the following compression algorithm:

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>

The compression scheme will reduce the loading time, which is about one-third of the size of the compressed dll. The effect is as shown in the figure below.

在使用autostart="false"标记以后不会启动就加载,加载程序集将在上面的代码块中执行,默认是加载 br。

2. Delay loading assemblies

Improve Blazor WebAssembly application startup performance by waiting for the application set to load until needed, an approach called "deferred loading."

Split the Blazor WebAssembly project into detail, and delay loading the assembly to improve the first load time of Blazor WebAssembly. We will explain the delay loading assembly through a case.

创建一个空的 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
>

Handle the assemblies that need to be loaded for the specified routing component.

打开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>

These are some assemblies that are not commonly used. If the following error occurs, Please delete the assemblies that cannot be found and load the configuration on demand,

However, if the above on-demand loading configuration is used, an exception will occur when publishing, such as the figure below; the reason for the error is that Blazor WebAssembly uses clipping by default when publishing. Since the following assemblies are just right and are not used, On-demand loading will be configured after clipping, but it has been clipped, so the assembly loaded on demand cannot be found; just delete the assembly with the error; This will only appear during release. Debug can still continue to use the above on-demand loading configuration, which can respond faster during debugging:

Then the next step.

添加指定项目的按需加载配置, 我们将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,但是这里的程序集:

Then click the button on the interface:

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

Then we publish the project (when publishing, remember the above-mentioned clipping problem that resulted in loss of assemblies and inability to use on-demand loading, just clean up the clipped assemblies in the on-demand loading configuration):

Then use docker compose to deploy a nginx agent to see the effect:

创建docker-compose.yml文件,并且添加以下代码,在docker-compose.yml的当前目录下创建 conf.dwwwroot俩个文件夹:

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,启动压缩,并且在发布的时候裁剪了未使用的程序集:

Optimize to 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>

Then we continue to publish it and deploy it to nginx.

在网络中查看加载大小,我们看到已经来到了 1MB,去掉一些 js 其实应该更小,这样它的加载问题得到了很大的解决(来自小夜鲲大佬的建议)

end

If you have a better optimization plan, you can contact me.

Sharing from token.

Blazor Communication Group: 452761192

This article comes from reprint.

Author: Token

Original title: How to optimize WebAssembly to 1MB?

Original link: www.cnblogs.com/hejiale010426/p/17076817.html

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 11/6/2024

Why is my blog site back in Blazor?

The blog website has gone through hardships in development. It has tried nearly 10 versions such as MVC, Vue, and Go. Now it has returned to Blazor and adopts static SSR. The speed has skyrocketed and it has been successfully launched.

继续阅读
同分类 / 同标签 2/29/2024

Data display can also be done in Winform

In the process of developing winform, data display functions are often needed. I have been using the gridcontrol before. Today, I want to use an example to introduce to you how to use the table component in ant design blazor hybrid to display data.

继续阅读
同分类 / 同标签 2/29/2024

Can Winform's interface become better?

A few days ago, I introduced to you the use of blazor hybrid in winform, and I also said that with blazor's ui, our winform program design can be more beautiful. Next, I want to use an example of drawing in winform blazor hybrid to illustrate it, hoping to be helpful to you.

继续阅读
同分类 / 同标签 1/7/2024

Code Workshop "Article Title URL Alias Generator" is launched

Code Workshop is a newly opened open source project by the webmaster that provides online tools, cross-platform desktop and mobile applications. Webmasters will ultimately strive to bring you a more efficient and convenient experience. Today, webmasters are honored to launch the "Article Title URL Alias Generator" to help you easily create URL aliases for article titles and improve SEO effects and user experience. Come to the code workshop and explore more practical tools!

继续阅读