跳到主要内容

Wails v3 路线

· 13 分钟阅读
Lea Anthony

简介

Wails是一个使用 Go 简化编写跨平台桌面应用程序的能力的项目。 它使用原生 webview 组件作为前端(而不是嵌入式浏览器),将世界上最流行的 UI 系统的强大功能引入Go,同时保持轻量级。

第二版于 2022年9月22日 发布,并带来了很多增强功能包括:

  • 实时开发,利用流行的Vite项目
  • 管理窗口和创建菜单的丰富功能
  • 微软的 WebView2 组件
  • 生成对应 Go 结构体的 TypeScript 模型
  • 创建 NSIS 安装程序
  • 混淆构建

现在,Wails v2 提供了强大的工具来创建丰富的跨平台桌面应用程序。

这篇博文的目的是看看这个项目现在处于什么阶段,以及我们可以在后续中改进什么。

我们现在在哪里?

看到 Wails 自 v2 发布以来的受欢迎程度上升是令人难以置信的。 我经常对社区的创造力和用它建造的美好事物感到惊讶。 随着越来越受欢迎,更多的目光投向了这个项目。 随之而来的是更多的功能请求和错误报告。

随着时间的推移,我已经能够确定该项目面临的一些最紧迫的问题。 我也已经能够识别出一些阻碍该项目的因素。

当前问题

我确定了以下我认为阻碍该项目的领域:

  • API
  • 绑定生成
  • 构建系统

接口

构建 Wails 应用程序的 API 目前由两部分组成:

  • 应用程序 API
  • 运行时 API

著名的应用程序 API 只有一个函数:Run(),它需要一堆 控制应用程序如何工作的选项。 虽然这使用起来非常简单,但这也非常有限。 这是一种“声明式”的方法,隐藏了很多潜在的复杂性。 例如,主窗口没有句柄,所以你不能直接与之互动。 为此,您需要使用运行时 API。 这是个问题当您开始想要做更复杂的事情时,例如创建多个窗口。

运行时 API 为开发者提供了许多实用功能。 其中包括:

  • 窗口管理
  • 对话框
  • 菜单
  • 事件
  • 日志

我对运行时 API 有很多不满意的地方。 第一个是它需要传递一个“context”。 对于传入上下文然后出现运行时错误的新开发人员来说,这既令人沮丧又令人困惑。

运行时 API 的最大问题是它是为只使用单个窗口的应用程序设计的。 随着时间的推移,对多窗口的需求不断增长,API 不太适合这种情况。

关于 v3 API 的想法

如果我们能做这样的事情不是很好吗?

func main() {
app := wails.NewApplication(options.App{})
myWindow := app.NewWindow(options.Window{})
myWindow.SetTitle("My Window")
myWindow.On(events.Window.Close, func() {
app.Quit()
})
app.Run()
}

这种编程方法更加直观,允许开发人员直接与应用程序元素交互。 所有当前的窗口运行时方法都只是窗口对象上的方法。 对于其他运行时方法,我们可以像这样移动他们到应用程序对象:

app := wails.NewApplication(options.App{})
app.NewInfoDialog(options.InfoDialog{})
app.Log.Info("Hello World")

这是一个更强大的 API,可以构建更复杂的应用程序。 它还允许创建多个窗口,这是 GitHub 上投票最多的功能

func main() {
app := wails.NewApplication(options.App{})
myWindow := app.NewWindow(options.Window{})
myWindow.SetTitle("My Window")
myWindow.On(events.Window.Close, func() {
app.Quit()
})
myWindow2 := app.NewWindow(options.Window{})
myWindow2.SetTitle("My Window 2")
myWindow2.On(events.Window.Close, func() {
app.Quit()
})
app.Run()
}

绑定生成

Wails 的关键特性之一是为您的 Go 方法生成绑定,因此它们可能从 JavaScript 调用。 当前执行此操作的方法有点 hack。 它涉及使用特殊标志构建应用程序,然后运行生成的二进制文件,该二进制文件使用反射来确定已绑定的内容。 这导致了先有鸡还是先有蛋的情况:没有绑定就无法构建应用程序,没有构建应用程序就无法生成绑定。 有很多方法可以解决这个问题,但最好的一个根本不会使用这种方法。

曾多次尝试为 Wails 项目编写策略分析器,但收效甚微。 最近,随着有关该主题的更多可用资料,这样做变得稍微容易一些。

与反射相比,AST 方法要快得多,但要复杂得多。 首先,我们可能需要对如何在代码中指定绑定施加某些约束。 目标是支持最常见的用例,然后在以后扩展它。

构建系统

与 API 的声明性方法一样,创建构建系统是为了隐藏构建桌面应用程序的复杂性。 当你运行 wails build 时,它会在幕后做很多事情:

  • 为绑定构建后端二进制文件并生成绑定
  • 安装前端依赖项
  • 构建前端资产
  • 确定应用程序图标是否存在,如果存在,则嵌入它
  • 构建最终二进制文件
  • 如果构建是针对 darwin/universal 的,它会构建 2 个二进制文件,一个用于 darwin/amd64,一个用于 darwin/arm64,然后使用 lipo 创建一个大的二进制文件
  • 如果需要压缩,它会使用 UPX 压缩二进制文件
  • 确定是否要打包此二进制文件,如果是:
    • 确保将图标和应用程序清单(manifest)编译成二进制文件 (Windows)
    • 构建应用程序包,生成图标包并将二进制文件和 info.plist 复制到应用程序包 (Mac)
  • 如果需要 NSIS 安装程序,它会构建它

整个过程虽然非常强大,但也非常不透明。 定制起来非常困难,调试也非常困难。

为了在 v3 中解决这个问题,我想转移到一个存在于 Wails 之外的构建系统。 在使用 Task 一段时间后,我非常喜欢它。 它是配置构建系统的绝佳工具,任何使用过 Makefile 的人都应该相当熟悉。

构建系统将使用 Taskfile.yml 文件进行配置,该文件默认使用任意受支持的模板生成。 这将具有完成所有当前任务所需的所有步骤,例如构建或打包应用程序,从而实现轻松定制。

这个工具将没有外部要求,因为它将构成 Wails CLI 的一部分。 这意味着您仍然可以使用 wails build,它会完成它今天所做的所有事情。 但是,如果您想自定义构建过程,可以通过编辑 Taskfile.yml 文件来实现。 这也意味着您可以轻松理解构建步骤并根据需要使用自己的构建系统。

构建难题中缺少的部分是构建过程中的原子操作,例如图标生成、压缩和打包。 需要一堆外部工具对开发人员来说不是很好的体验。 为了解决这个问题,Wails CLI 将提供所有这些功能作为 CLI 的一部分。 这意味着构建仍然按预期工作,没有额外的外部工具,但是您可以用您喜欢的任何工具替换构建的任何步骤。

这将是一个更加透明的构建系统,可以更轻松地进行定制并解决围绕它提出的许多问题。

好处

这些积极的变化将为项目带来巨大的好处:

  • 新的 API 将更加直观,并允许构建更复杂的应用程序。
  • 使用静态分析生成绑定会更快,并且会降低当前流程的复杂性。
  • 使用已建立的外部构建系统将使构建过程完全透明,从而实现强大的定制。

对项目维护者的好处是:

  • 新的 API 将更容易维护和适应新功能和平台。
  • 新的构建系统将更容易维护和扩展。 我希望这将导致社区驱动构建管道的新生态系统。
  • 更好地分离项目中的关注点。 这将使添加新功能和平台变得更加容易。

计划

很多这方面的实验已经完成,而且看起来不错。 这项工作目前没有时间表,但我希望到 2023 年第一季度末,将有一个 Mac 的 alpha 版本,允许社区进行测试、试验并提供反馈。

总结

  • v2 API 是声明式的,对开发人员隐藏了很多,不适合多窗口等功能。 将创建一个更简单、直观且功能更强大的新 API。
  • 构建系统不透明且难以定制,因此我们将转向外部构建系统,它将全部开放。
  • 绑定生成缓慢且复杂,因此我们将转向静态分析,这将消除当前方法的许多复杂性。

我们在 v2 的内部做了很多工作,它是可靠的。 现在是时候解决它上面的瓶颈并为开发人员提供更好的体验了。

我希望你和我一样对此感到兴奋。 我期待听到您的想法和反馈。

此致,

Lea

PS: 如果您或您的公司发现 Wails 有用, 请考虑 赞助项目。 谢谢!

PPS:是的,这是一个用 Wails 构建的多窗口应用程序的真实截图。 它不是一个模型。 这是真实的。 太棒了。 即将到来。