
介绍
Wails 是一个简化使用 Go 编写跨平台桌面应用程序的项目。它使用原生 webview 组件作为前端(而不是嵌入式浏览器),将世界上最流行的 UI 系统的强大功能带到 Go 中,同时保持轻量级。
版本 2 于 2022 年 9 月 22 日发布,带来了许多增强功能,包括
- 实时开发,利用流行的 Vite 项目
- 用于管理窗口和创建菜单的丰富功能
- Microsoft 的 WebView2 组件
- 生成反映 Go 结构的 Typescript 模型
- 创建 NSIS 安装程序
- 混淆构建
现在,Wails v2 为创建丰富的跨平台桌面应用程序提供了强大的工具。
这篇博文旨在了解项目当前的发展状况以及未来可以改进的地方。
我们现在在哪里?
自 v2 发布以来,看到 Wails 的受欢迎程度不断上升真是令人难以置信。我总是对社区的创造力和用 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一段时间后,我成为了它的忠实粉丝。它是配置构建系统的绝佳工具,对于任何使用过 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 构建的多窗口应用程序的真实截图。这不是一个模型。它是真的。很棒。很快就会发布。