再探.NET8 NativeAOT

时间:11/21/2023 23:48:19   作者:ChenReal    阅读:107

乘着昨天良好的开局,这一回,我们开始进入实战项目的阶段。 翻了半天,终于找到一个代码量不大也不小的工具类应用:VuePacker。它的主要功能是前端开发工具,主要功能有:

  • 1、遍历某个目录下的所有*.vue代码,解析并将其组装成Vue Component结构的js代码
  • 2、将所指定的*.js代码合并打包成单一的js文件,并进行压缩最小化(minify)
  • 3、将所指定*.css代码打包成单一的css文件,并进行压缩最小化(minify)

看看NativeAOT能否一句将其拿下。

1、动手

先改TargetFramework,然后加上PublishAot,最后dotnet publish发布打包……一通熟手的操作下来,竟然无比顺利,成功编译生得到了exe。果然不出意外地出了意外,双击运行的时候,报 错 了!

Reflection-based serialization has been disabled for this application. Either use the source generator APIs or explicitly configure the 'JsonSerializerOptions.TypeInfoResolver' property.

报错信息的指向很明确,是个Json反序列化的报错。项目代码确实用到了System.Text.Json,沿着这条线索,终于找到解决方法。

首先,解释一下原理(纯粹个人理解)

AOT的编译是会根据代码实际情况对依赖的库进行裁剪,以保证生成文件足够苗条。但有些库可能用到某些动态写法,因此编译器裁剪后打包却不能正常工作。这时候,我们需要引入rd.xml来声明第三方库的编译打包方式,告诉编译器不要对它做裁剪,而是全量编译进去。等于做出一定牺牲,让文件变得臃肿一些,以保证应用能够正常运行,以空间换胜利。

接着,再试试rd.xml这一剂解药
  • 在项目创建rd.xml文件,文件内容如下:
    <Directives>
     <Application>
      <Assembly Name="System.Text.Json"  Dynamic="Required All">
      </Assembly>
     </Application>
    </Directives>
    
  • 打开.csproj文件,增加一下配置
    <ItemGroup>
      <RdXmlFile Include="rd.xml" />
     </ItemGroup>
    

重新发布后,报错消除,我的应用可以正常执行了!但是exe文件的大小,从原来的5.6M涨到了8.4M,竟直胖了50%!

2、优化

rd.xml的方案确实有效果,不过副作用也挺大,是最求极值的在下不能忍受。那么,下面就继续做些优化吧。优化思路:

  • A)换个JSON库?用Newtonsoft.Json?这是重量级选手,我敢保证这个生成的exe会更胖。JSON的库似乎都大不轻量级。
  • B)干脆不要JSON了,反正我的应用也仅仅是用反序列化解析appsetting.json的配置文件而已,几千行代码仅仅调用过一次。其实可以试试yml 或者 ini,这些配置解析的算法都比json轻的多。不过,这样也有坏处,就是对用户不大友好。以往版本都是用json做配置的,换一种配置方式用户教育成本,虽不大但还是有的。让用户无感升级才是最最理想的。
  • C)自己用正则表达式,写个简单的json配置解析方法?嗯,我看行!毕竟我的配置格式是非常简单的Key-Value,没有过多嵌套。正则表达式可以胜任~

按照方案C操作后,得到4.5M的exe文件。

3、继续优化

看来量少用或者不用第三方库,对优化exe文件大小会有立竿见影的效果。好吧,掌握了规律,那就再动动刀子,把仅剩一个的第三方库:NUglify换掉试试。

我发现Javascript打包混淆的代码,自己去造轮子显然不现实,只能找别人的轮子拼接过来。事实上这套代码并不好找,我在GitHub翻了好久,才找到一个停更多年的开源项目:https://github.com/Taritsyn/JSMin.NET将就着用把,反正也只是个试验罢了。

最后,一番折腾下来,我能做到极限大小的exe文件是3.2M。

总结

  • 学会用rd.xml全量编译处理第三方依赖库
  • 想帮exe文件瘦身,必须尽量量少用或者不用第三方库

 

评论
0/200