
介绍
Wails 是一个简化使用 Go 编写跨平台桌面应用程序的项目。它使用原生 webview 组件作为前端(而不是嵌入式浏览器),将世界上最流行的 UI 系统的强大功能带入 Go,同时保持轻量级。
v2 版本于 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 一段时间后,我非常喜欢它。它是一个用于配置构建系统的绝佳工具,对于任何使用过 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 构建的多窗口应用程序的真实截图。它不是模型。它是真实的。它很棒。它即将推出。