简化桌面应用程序开发

苦于处理与Electron桌面应用程序相关的复杂性和大型构建吗?传统的框架,如QT、GTK或Win32,让你想哭吗?今天我们将使用Wails、React和Tailwind构建一个Markdown编辑器。

简化桌面应用程序开发

自Web 2.0时代以来,构建桌面应用程序一直是一个棘手的问题。对于Go语言爱好者来说,情况更为严峻。你被迫选择一些选项,大多是包装现有的UI库,但这些选项都无法真正带来使用Go语言编写后端服务时的高效性和乐趣。最受欢迎的选项Electron是一个庞大的JavaScript堆栈,虽然入门容易,但它臃肿不堪,你被迫编写大量的JavaScript代码,这可能会让你抓狂。 让我们深入探讨一种更好的方式,使用Wails、React和Tailwind来创建一个Markdown编辑器。

我们对这个应用程序的基本要求是:

    预览Markdown文本
    编辑Markdown文本
    创建文件
    保存文件
    导出文件(作为pdf)

第一步:引导! #

Wails遵循类似Rails的哲学,提供了一揽子解决方案和快速形成的观点。它没有的观点是你在视图层使用什么HTML框架。为了让事情变得非常容易入门,它简化了从模板开始的过程。

让我们从这个很棒的预制的vite+react+ts+tailwind模板开始。

wails init -n write -t https://github.com/hotafrika/wails-vite-react-ts-tailwind-template
cd write
wails dev

排队等待npm首次安装和构建。这只需要一次,值得等待,我保证!

现在花一点时间来了解一下,结构如下,每个Wails应用程序都会这样。 - 构建(包含构建的二进制文件、安装程序等)

  • 前端(包含前端代码)
  • wailsjs(包含Go代码)
  • main.go(Go代码入口点)
  • wails.json(wails配置文件)
  • app.go(主要的wails应用程序文件)

让我们从设计开始:这是我使用的设计(https://v0.dev/r/Z0Ln82RKNlP),感谢v0.dev为我节省了所有时间!这基本上是将html复制/粘贴到app.tsx中的工作。我选择不导入v0库——我只是不相信对于如此简单的设计值得这样做。

第二步:渲染和更新Markdown #

Wails提供了一个服务器/客户端模型,将Golang后端无缝连接到Javascript前端。在我们的markdown编辑器组件中,您将看到一些简单的代码片段,例如:

//在文件开头
import {Save, SendMarkdownToRenderer, Open, Export} from "../wa 将上述的Markdown翻译成中文并删除第一级标题: ilsjs/go/main/App";

// 在组件内部

const updateValue = async (event: React.ChangeEvent<HTMLTextAreaElement>) => {

  const value = event.target.value

  const html = await SendMarkdownToRenderer(value)

  setMd(html);

}

// 跳过多行...

<textarea

           onChange={updateValue}

           ref={ref}

           className="flex min-h-[80px] rounded-md border border-input px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 w-full h-full bg-white dark:bg-gray-700"

           id="markdown-input" placeholder="在此输入您的Markdown..."></textarea></div>


正如您所看到的,我们有一个非常简单的文本区域和一个onChange函数。当文本区域发生变化时,会触发一个事件,调用该函数并执行SendMarkdownToRenderer。该函数是一个生成的客户端代码, 这个非常简单的小函数是我们将状态持久化到“服务器”和Go上下文的方式,然后通过setMD状态设置器将一个字符串值传递回客户端以进行渲染。

**重要提示:**这里有很多很酷的东西。首先,我们有这个非常棒的代码生成,它会在您保存文件时自动发生。一个Go函数会无缝地和神奇地转变成一个可以从React应用程序调用的东西。这种魔法RPC对于一个服务器靠近客户端的UI应用程序非常有效,而且非常令人愉快。

有趣的插曲:如果你眯着眼睛看这个代码,你可以把它看成是 最近的技术Twitter模因是关于“使用服务器”并称之为“使用golang”。

步骤3:新建文件,保存文件,打开文件 #

为了实现这个功能组合,我们将使用相同的模式,使用onClick处理程序来处理按钮。同样,我们利用wails提供的代码生成功能来自动连接。让我们深入了解app.go中的Save函数:

func (a *App) Save() (string, error) {

   hd, err := homedir.Dir()

   if err != nil {

      return "", err

   }

   chosenPath, err := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{

      DefaultDirectory:          path.Join(hd, "Documents"),

      DefaultFilename:           a.filename,

      Title:                     "保存文件",

      ShowHiddenFiles:           false,

      CanCreateDirectories:      true,

      TreatPackagesAsDirectories: true,

   })

   if err != nil {

      return "", err

   }

   err = os.WriteFile(chosenPath, []byte(a.markdown), 0644)

   if err != nil {

      return "", err

   }
``` 框架提供了一个运行时包,允许调用一些函数来提供常见的跨平台工具。在这里,我们调用`SaveFileDialog`来向用户展示一个本地和熟悉的方式来选择文件名和位置来保存Markdown。该函数返回一个路径`chosenPath`,我们在一个简单的`WriteFile`调用中使用它。

我们的状态`a.markdown`通过前面的step 1中的`onChange`处理程序与前端保持同步。

>旅行警告:`SaveFileDialog`需要一个上下文,这非常重要,这个上下文是运行时上下文,运行时上下文存储在app结构体上,你需要始终记得传递它,以便所有的魔法都能正常工作!计划在wails v3中更改这一点,但在撰写本文时,该版本仍在开发中。

**挑战**

看一下,并试着找出新建文件和打开文件是如何工作的。从app.tsx开始,追踪回到app.go! 好的,这真的是一个巨大的时间浪费,但是很有趣。正如你可能已经知道的,有很多导出PDF文件的技术,我决定使用原生的、非基于浏览器的纯pdf库fpdf。幸运的是,我们的markdown -> html编译器还支持通过渲染函数和遍历解析的AST进行扩展。我很开心地适应了一个简陋而简约的pdf渲染器。你可以在[这里](https://github.com/ebuckley/write/blob/main/write/lib/pdf.go)查看。

至于wails部分,它只是一个按钮的`onclick`处理程序,以及在`App.go`上导出的方法。我们只需要将markdown内容放入我们的渲染器中,通过`SavefileDialog`传递保存结果的路径。

> 警告:不要使用这个pdf渲染器的代码,它在代码块上会崩溃!这只是一个我认为可以很好扩展的示例方法。

## 第五步:CI/CD

吃你的蔬菜,让你的代码 卫生且从不在`origin main`上留下糟糕的构建。

我花了很多功夫为这个项目设置了CI/CD,以展示如何为Windows和Linux进行交叉编译。为此,我设置了一个GitHub Action,可以在推送时进行测试/构建,并在您使用与`v *`匹配的标签标记存储库时发布。

是的,你没有看错,我进行了16次构建才发布。不管怎样...为了让你不需要浪费太多时间,可以在这里查看我的部署动作[here](https://github.com/ebuckley/write/blob/main/.github/workflows/main.yml)。

有趣的部分包括:

* 您需要安装一些依赖项`sudo apt install libgtk-3-dev libwebkit2gtk-4.0-dev nsis`
* 别忘了把路径弄对
* 别忘了在您的动作中使用权限块,允许它创建新的发布版本
* 在构建之间从构建目录中复制二进制文件,因为`build/bin`将在构建时被覆盖

因此,我认为我们有一个可以扩展的稳定项目基础,可以修复错误。 用颠覆性和变革性的结论将所有内容包装起来

Wails是用Golang编写的GUI应用程序的改变者——简单、高效和神奇。您可以将其视为前端的“Web风格”MVC,或者是桌面应用程序的“使用Golang”。它有什么不同之处?任何前端视图层都可以使用!从HTML到Svelte,都可以使用。二进制文件只有10Mb,而不是100+Mb的电子文件。就Golang桌面框架而言,我认为Wails是无可争议的最佳选择。

您可以在此项目中查看我编写的代码[这里](https://github.com/ebuckley/write),并在[这里](https://wails.io/)开始使用Wails。