跳至主要内容

一篇标记为“v3”的文章

查看所有标签

·阅读 9 分钟
Lea Anthony

简介

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

版本 2 于 2022 年 9 月 22 日发布,带来许多增强功能,包括

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

目前,Wails v2 为创建丰富、跨平台的桌面应用程序提供了强大的工具。

这篇博文旨在探讨该项目目前的状况以及我们可以改进的方向。

我们现在身处何处?

看到自 v2 发布以来 Wails 的受欢迎程度不断上升,真是令人难以置信。我一直对社区的创造力以及他们使用它构建的精彩事物感到惊叹。随着知名度的提高,更多的人关注着这个项目。随之而来的是更多功能请求和错误报告。

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

当前问题

我已经确定了以下我认为阻碍项目发展的一些领域

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

API

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

  • 应用程序 API
  • 运行时 API

众所周知,应用程序 API 只有一个函数:Run(),它接受大量选项,这些选项控制应用程序的工作方式。虽然这非常易于使用,但它也有很大的局限性。它是一种“声明式”方法,隐藏了许多底层复杂性。例如,没有主窗口的句柄,因此您无法直接与它交互。为此,您需要使用运行时 API。当您想要执行更复杂的操作(如创建多个窗口)时,这就会成为一个问题。

运行时 API 为开发人员提供了许多实用函数。这包括

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

我对运行时 API 中的一些东西并不满意。首先,它需要传递一个“上下文”。这对新开发人员来说既令人沮丧又令人困惑,他们传递了一个上下文,然后出现运行时错误。

运行时 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 中调用。当前执行此操作的方法有点像黑客行为。它涉及使用特殊标志构建应用程序,然后运行生成的二进制文件,该二进制文件使用反射来确定绑定了什么。这会导致一个鸡和蛋的问题:没有绑定就无法构建应用程序,没有构建应用程序就无法生成绑定。有很多方法可以解决这个问题,但最好的方法是不使用这种方法。

曾尝试为 Wails 项目编写静态分析器,但进展不大。近年来,随着该主题相关资料的增多,编写静态分析器变得稍微容易了一些。

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

构建系统

与 API 的声明式方法一样,构建系统是为了隐藏构建桌面应用程序的复杂性而创建的。当您运行wails build时,它会在幕后执行许多操作

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

虽然这个过程非常强大,但也非常不透明。它非常难以自定义,也很难调试。

为了解决这个问题,在 v3 中,我想将构建系统迁移到 Wails 之外的构建系统。在使用了一段时间Task之后,我成为了它的忠实粉丝。它是一个用于配置构建系统的绝佳工具,应该让任何使用过 Makefiles 的人都觉得比较熟悉。

构建系统将使用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 构建的多窗口应用程序的真实截图。它不是模型,是真实的。它很棒。它即将推出。